Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: telemetry v2 #2485

Draft
wants to merge 31 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
65b3566
Added types for new version of usage data
vigy02 Dec 5, 2024
f8fcec6
renamed the file
vigy02 Dec 5, 2024
d085c26
Added changeset and updated the cause to be an array
vigy02 Dec 5, 2024
099b13e
update: Added event and changes the errordetails
vigy02 Dec 6, 2024
c65d304
Updated aws_region and latency
vigy02 Dec 6, 2024
b515676
Merge branch 'main' into feature/cli-telemetry-v2
rtpascual Jan 30, 2025
0ca1c3f
update types
rtpascual Jan 30, 2025
8dcce09
Merge branch 'feature/cli-telemetry-v2' into feat/telemetry-v2
rtpascual Jan 31, 2025
51c7839
telemetry v2
rtpascual Feb 6, 2025
347bc83
refactor getLocalProjectId and add AccountIdFetcher
rtpascual Feb 6, 2025
0d00cd1
try this
rtpascual Feb 6, 2025
d0f748a
try this
rtpascual Feb 6, 2025
f403651
fix windows tests
rtpascual Feb 6, 2025
ce9c91a
try that
rtpascual Feb 6, 2025
46b83c6
try this
rtpascual Feb 7, 2025
67f4184
expand to sandbox
rtpascual Feb 7, 2025
2294d58
update anonymizePaths
rtpascual Feb 7, 2025
5963b6d
add workaround for abort events
rtpascual Feb 7, 2025
064e113
add workaround for abort events
rtpascual Feb 8, 2025
8ef823d
fix test
rtpascual Feb 8, 2025
68c3a79
try this
rtpascual Feb 8, 2025
c0e29e9
add changeset
rtpascual Feb 11, 2025
b1826fe
add changeset for snapshot
rtpascual Feb 14, 2025
5239b78
fix console logs and file path regex
rtpascual Feb 17, 2025
5f9e93d
remove stacks in errors
rtpascual Feb 17, 2025
d7c758c
try this
rtpascual Feb 17, 2025
79dee7e
try this
rtpascual Feb 17, 2025
2a08ebf
try this
rtpascual Feb 17, 2025
38e3dd3
remove stacks in error stack
rtpascual Feb 18, 2025
e726051
improve anonymization for accountId
rtpascual Feb 19, 2025
6186822
update getLocalProjectId
rtpascual Feb 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .changeset/hot-spies-fly.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
'@aws-amplify/backend-deployer': minor
'@aws-amplify/platform-core': minor
'@aws-amplify/backend-cli': minor
'@aws-amplify/ai-constructs': minor
'ampx': minor
'@aws-amplify/auth-construct': minor
'@aws-amplify/backend': minor
'@aws-amplify/backend-ai': minor
'@aws-amplify/backend-auth': minor
'@aws-amplify/backend-data': minor
'@aws-amplify/backend-function': minor
'@aws-amplify/backend-output-schemas': minor
'@aws-amplify/backend-output-storage': minor
'@aws-amplify/backend-platform-test-stubs': minor
'@aws-amplify/backend-secret': minor
'@aws-amplify/backend-storage': minor
'@aws-amplify/cli-core': minor
'@aws-amplify/client-config': minor
'create-amplify': minor
'@aws-amplify/deployed-backend-client': minor
'eslint-plugin-amplify-backend-rules': minor
'@aws-amplify/form-generator': minor
'@aws-amplify/integration-tests': minor
'@aws-amplify/model-generator': minor
'@aws-amplify/plugin-types': minor
'@aws-amplify/sandbox': minor
'@aws-amplify/schema-generator': minor
---

for snapshot release
7 changes: 7 additions & 0 deletions .changeset/smooth-peaches-trade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@aws-amplify/backend-deployer': minor
'@aws-amplify/platform-core': minor
'@aws-amplify/backend-cli': patch
---

add new version of telemetry
5 changes: 5 additions & 0 deletions .changeset/violet-dolphins-itch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@aws-amplify/platform-core': patch
---

Add TypeScript definitions for CLI telemetry usage data v2
1 change: 1 addition & 0 deletions .eslint_dictionary.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"amazoncognito",
"amplifyconfiguration",
"ampx",
"anonymize",
"anthropic",
"apns",
"apollo",
Expand Down
2 changes: 2 additions & 0 deletions packages/backend-deployer/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ export type BackendDeployerOutputFormatter = {
export type DeploymentTimes = {
synthesisTime?: number;
totalTime?: number;
deploymentTime?: number;
hotSwapTime?: number;
};

// @public (undocumented)
Expand Down
14 changes: 14 additions & 0 deletions packages/backend-deployer/src/cdk_deployer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ export class CDKDeployer implements BackendDeployer {
synthesisTime: synthTimeSeconds,
totalTime:
synthTimeSeconds + (deployResult?.deploymentTimes?.totalTime || 0),
deploymentTime: deployResult?.deploymentTimes?.deploymentTime,
hotSwapTime: deployResult?.deploymentTimes?.hotSwapTime,
},
};
};
Expand Down Expand Up @@ -341,6 +343,9 @@ export class CDKDeployer implements BackendDeployer {
) => {
const regexTotalTime = /✨ {2}Total time: (\d*\.*\d*)s.*/;
const regexSynthTime = /✨ {2}Synthesis time: (\d*\.*\d*)s/;
const regexDeploymentTime = /✨ {2}Deployment time: (\d*\.*\d*)s/;
const regexHotSwappingResources = /✨ {1}hotswapping resources:/;
let isHotSwapping = false;
const reader = readline.createInterface(stdout);
for await (const line of reader) {
if (line.includes('✨')) {
Expand All @@ -353,6 +358,15 @@ export class CDKDeployer implements BackendDeployer {
if (synthTime && synthTime.length > 1 && !isNaN(+synthTime[1])) {
output.deploymentTimes.synthesisTime = +synthTime[1];
}
const deploymentTime = line.match(regexDeploymentTime);
isHotSwapping = isHotSwapping ? isHotSwapping : line.match(regexHotSwappingResources) !== null;
if (deploymentTime && deploymentTime.length > 1 && !isNaN(+deploymentTime[1])) {
if (isHotSwapping) {
output.deploymentTimes.hotSwapTime = +deploymentTime[1];
} else {
output.deploymentTimes.deploymentTime = +deploymentTime[1];
}
}
}
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ export type DestroyResult = {
export type DeploymentTimes = {
synthesisTime?: number;
totalTime?: number;
deploymentTime?: number;
hotSwapTime?: number;
};

/**
Expand Down
43 changes: 41 additions & 2 deletions packages/cli/src/ampx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@ import { extractSubCommands } from './extract_sub_commands.js';
import {
AmplifyFault,
PackageJsonReader,
TelemetryDataEmitterFactory,
UsageDataEmitterFactory,
} from '@aws-amplify/platform-core';
import { fileURLToPath } from 'node:url';
import { verifyCommandName } from './verify_command_name.js';
import { hideBin } from 'yargs/helpers';
import { PackageManagerControllerFactory, format } from '@aws-amplify/cli-core';
import { extractCommandInfo } from './extract_command_info.js';

const startTime = Date.now();

const packageJson = new PackageJsonReader().read(
fileURLToPath(new URL('../package.json', import.meta.url))
Expand All @@ -36,15 +40,38 @@ const usageDataEmitter = await new UsageDataEmitterFactory().getInstance(
dependencies
);

attachUnhandledExceptionListeners(usageDataEmitter);
const telemetryDataEmitter =
await new TelemetryDataEmitterFactory().getInstance(dependencies);

attachUnhandledExceptionListeners(usageDataEmitter, telemetryDataEmitter);

verifyCommandName();

const parser = createMainParser(libraryVersion);
const errorHandler = generateCommandFailureHandler(parser, usageDataEmitter);

const initTime = Date.now() - startTime;

// Below is a workaround in order to send data to telemetry when user force closes a prompt (ie with Ctrl+C)
// without the counter we would send both success and abort data.
// Trying to do await telemetryDataEmitter.emitAbortion in errorHandler ends up with:
// Warning: Detected unsettled top-level await
let telemetryEmitCount = 0;
// eslint-disable-next-line @typescript-eslint/no-misused-promises
process.on('beforeExit', async (code) => {
if (telemetryEmitCount !== 0) {
process.exit(code);
}
const totalTime = Date.now() - startTime;
await telemetryDataEmitter.emitAbortion(
{ totalTime, initTime },
extractCommandInfo(parser)
);
process.exit(code);
});

try {
await parser.parseAsync(hideBin(process.argv));
const totalTime = Date.now() - startTime;
const metricDimension: Record<string, string> = {};
const subCommands = extractSubCommands(parser);

Expand All @@ -53,8 +80,20 @@ try {
}

await usageDataEmitter.emitSuccess({}, metricDimension);
await telemetryDataEmitter.emitSuccess(
{ totalTime, initTime },
extractCommandInfo(parser)
);
telemetryEmitCount++;
} catch (e) {
if (e instanceof Error) {
const totalTime = Date.now() - startTime;
const errorHandler = generateCommandFailureHandler(
parser,
usageDataEmitter,
telemetryDataEmitter,
{ totalTime, initTime }
);
await errorHandler(format.error(e), e);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { LocalNamespaceResolver } from '../../backend-identifier/local_namespace
import { createSandboxSecretCommand } from './sandbox-secret/sandbox_secret_command_factory.js';
import {
PackageJsonReader,
TelemetryDataEmitterFactory,
UsageDataEmitterFactory,
} from '@aws-amplify/platform-core';
import { SandboxEventHandlerFactory } from './sandbox_event_handler_factory.js';
Expand Down Expand Up @@ -69,6 +70,14 @@ export const createSandboxCommand = (): CommandModule<
libraryVersion,
dependencies
);
},
async () => {
const dependencies = await new PackageManagerControllerFactory()
.getPackageManagerController()
.tryGetDependencies();
return await new TelemetryDataEmitterFactory().getInstance(
dependencies
);
}
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ClientConfigFormat } from '@aws-amplify/client-config';
import {
AmplifyFault,
AmplifyUserError,
TelemetryDataEmitter,
UsageDataEmitter,
} from '@aws-amplify/platform-core';
import assert from 'node:assert';
Expand Down Expand Up @@ -36,6 +37,14 @@ void describe('sandbox_event_handler_factory', () => {
emitFailure: emitFailureMock,
} as unknown as UsageDataEmitter;

// Telemetry data emitter mocks
const emitTelemetrySuccessMock = mock.fn();
const emitTelemetryFailureMock = mock.fn();
const telemetryDataEmitterMock = {
emitSuccess: emitTelemetrySuccessMock,
emitFailure: emitTelemetryFailureMock,
} as unknown as TelemetryDataEmitter;

const printMock = mock.method(printer, 'print');

// Class under test
Expand All @@ -45,7 +54,8 @@ void describe('sandbox_event_handler_factory', () => {
name: 'name',
type: 'sandbox',
}),
async () => usageDataEmitterMock
async () => usageDataEmitterMock,
async () => telemetryDataEmitterMock,
);

afterEach(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { SandboxEventHandlerCreator } from './sandbox_command.js';
import { BackendIdentifier } from '@aws-amplify/plugin-types';
import { AmplifyError, UsageDataEmitter } from '@aws-amplify/platform-core';
import { AmplifyError, TelemetryDataEmitter, UsageDataEmitter } from '@aws-amplify/platform-core';
import { DeployResult } from '@aws-amplify/backend-deployer';
import { format, printer } from '@aws-amplify/cli-core';

Expand All @@ -15,7 +15,8 @@ export class SandboxEventHandlerFactory {
private readonly getBackendIdentifier: (
sandboxIdentifier?: string
) => Promise<BackendIdentifier>,
private readonly getUsageDataEmitter: () => Promise<UsageDataEmitter>
private readonly getUsageDataEmitter: () => Promise<UsageDataEmitter>,
private readonly getTelemetryDataEmitter: () => Promise<TelemetryDataEmitter>,
) {}

getSandboxEventHandlers: SandboxEventHandlerCreator = ({
Expand All @@ -29,6 +30,7 @@ export class SandboxEventHandlerFactory {
sandboxIdentifier
);
const usageDataEmitter = await this.getUsageDataEmitter();
const telemetryDataEmitter = await this.getTelemetryDataEmitter();
try {
await clientConfigLifecycleHandler.generateClientConfigFile(
backendIdentifier
Expand All @@ -40,6 +42,10 @@ export class SandboxEventHandlerFactory {
deployResult.deploymentTimes,
{ command: 'Sandbox' }
);
await telemetryDataEmitter.emitSuccess(
deployResult.deploymentTimes,
{ subCommands: 'SandboxEvent'}
);
}
}
} catch (error) {
Expand All @@ -60,6 +66,7 @@ export class SandboxEventHandlerFactory {
failedDeployment: [
async (...args: unknown[]) => {
const usageDataEmitter = await this.getUsageDataEmitter();
const telemetryDataEmitter = await this.getTelemetryDataEmitter();
if (args.length == 0 || !args[0]) {
return;
}
Expand All @@ -68,13 +75,23 @@ export class SandboxEventHandlerFactory {
await usageDataEmitter.emitFailure(deployError, {
command: 'Sandbox',
});
await telemetryDataEmitter.emitFailure(
deployError,
undefined,
{ subCommands: 'SandboxEvent'}
);
} else {
await usageDataEmitter.emitFailure(
AmplifyError.fromError(deployError),
{
command: 'Sandbox',
}
);
await telemetryDataEmitter.emitFailure(
AmplifyError.fromError(deployError),
undefined,
{ subCommands: 'SandboxEvent'}
);
}
},
],
Expand Down
Loading
Loading