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

[Telemetry] Migration from AppInsights to 1DS #13493

Merged
merged 30 commits into from
Oct 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
78b3831
Draft of telemetry refactoring
danielayala94 Jul 23, 2024
3edc9db
Better draft, including most (if not all?) properties
danielayala94 Jul 24, 2024
7e96912
Various fixes, it now compiles
danielayala94 Aug 7, 2024
c851e1d
Refactor, and temporary commenting tests
danielayala94 Aug 9, 2024
c2b24c0
All tests passing! But will need to clean up a few things
danielayala94 Aug 21, 2024
068d6e9
Polished some code, re-enabled some errorUtils tests
danielayala94 Aug 23, 2024
ceaf74e
Merge branch 'main' into telemetry-migration1
danielayala94 Aug 23, 2024
80cf583
Change files
danielayala94 Aug 23, 2024
bbc7f99
Merge branch 'main' into telemetry-migration1
danielayala94 Aug 26, 2024
8c20caa
Update yarn.lock
danielayala94 Aug 26, 2024
0abd8b6
Let yarn lint:fix cook
danielayala94 Aug 26, 2024
69c36bb
Simplifying
danielayala94 Aug 28, 2024
e29623a
Nit: ordering
danielayala94 Aug 28, 2024
ae530ee
Avoid unnecessary JSON work
danielayala94 Aug 28, 2024
ac8e1b2
nit
danielayala94 Aug 29, 2024
30fb21a
Merge branch 'main' into telemetry-migration1
danielayala94 Aug 29, 2024
6054f21
Merge branch 'main' into telemetry-migration1
danielayala94 Sep 3, 2024
9cd4959
Mostly placing some common props into Part A ext, plus adding/removin…
danielayala94 Sep 10, 2024
1f9587e
Merge branch 'main' into telemetry-migration1
danielayala94 Sep 10, 2024
feca7f3
Merge branch 'main' into telemetry-migration1
danielayala94 Oct 8, 2024
ceffbd7
Merge branch 'main' into telemetry-migration1
danielayala94 Oct 8, 2024
e528795
Distinguish between deviceClass and nodePlatform
danielayala94 Oct 9, 2024
5e8dbac
Merge branch 'main' into telemetry-migration1
danielayala94 Oct 9, 2024
9a9f8e2
Merge branch 'main' into telemetry-migration1
danielayala94 Oct 10, 2024
0642098
Nit
danielayala94 Oct 10, 2024
56496f8
Merge branch 'main' into telemetry-migration1
danielayala94 Oct 10, 2024
781b626
Merge branch 'main' into telemetry-migration1
danielayala94 Oct 10, 2024
5a95c29
Merge branch 'main' into telemetry-migration1
danielayala94 Oct 11, 2024
4b97ed7
Merge branch 'main' into telemetry-migration1
danielayala94 Oct 11, 2024
4d9388c
Merge branch 'main' into telemetry-migration1
danielayala94 Oct 11, 2024
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "none",
"comment": "Enables telemetry by migrating from AppInsights to 1DS",
"packageName": "@react-native-windows/telemetry",
"email": "14967941+danielayala94@users.noreply.github.com",
"dependentChangeType": "none"
}
3 changes: 2 additions & 1 deletion packages/@react-native-windows/telemetry/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@
},
"dependencies": {
"@azure/core-auth": "1.5.0",
"@microsoft/1ds-core-js": "^4.3.0",
"@microsoft/1ds-post-js": "^4.3.0",
"@react-native-windows/fs": "0.0.0-canary.58",
"@xmldom/xmldom": "^0.7.7",
"applicationinsights": "2.9.1",
"ci-info": "^3.2.0",
"envinfo": "^7.8.1",
"lodash": "^4.17.21",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* @format
*/

import * as appInsights from 'applicationinsights';
import * as coreOneDS from '@microsoft/1ds-core-js';
import * as path from 'path';

import {
Expand All @@ -16,6 +16,7 @@ import {
CommandEventName,
CodedErrorEventName,
} from '../telemetry';

import * as basePropUtils from '../utils/basePropUtils';
import * as errorUtils from '../utils/errorUtils';
import * as projectUtils from '../utils/projectUtils';
Expand All @@ -35,22 +36,21 @@ export class TelemetryTest extends Telemetry {
}

// Ensure that we don't actually fire events when testing
Telemetry.isTest = true;
Telemetry.isTestEnvironment = true;

await Telemetry.setup(options);
}

/** Run at the end of each test where telemetry was fired. */
static endTest(finalCallback?: () => void): void {
Telemetry.client?.flush({
callback: _ => {
if (TelemetryTest.hasTestTelemetryProviders) {
expect(TelemetryTest.testTelemetryProvidersRan).toBe(true);
}
if (finalCallback) {
finalCallback();
}
},
Telemetry.appInsightsCore?.flush(undefined /* isAsync */, () => {
// Your callback logic here
if (TelemetryTest.hasTestTelemetryProviders) {
expect(TelemetryTest.testTelemetryProvidersRan).toBe(true);
}
if (finalCallback) {
finalCallback();
}
});
}

Expand All @@ -61,7 +61,7 @@ export class TelemetryTest extends Telemetry {

/** Retrieves the value of a common property.*/
static getCommonProperty(key: string): string | undefined {
return TelemetryTest.client?.commonProperties[key];
return TelemetryTest.commonProperties[key];
}

/** Retrieves the version of the specified tool/package. */
Expand All @@ -77,15 +77,12 @@ export class TelemetryTest extends Telemetry {
}

/** Adds a telemetry processor, usually for verifying the envelope. */
static addTelemetryProcessor(
telemetryProcessor: (
envelope: appInsights.Contracts.EnvelopeTelemetry,
contextObjects?: {
[name: string]: any;
},
static addTelemetryInitializer(
telemetryInitializer: (
envelope: coreOneDS.ITelemetryItem
) => boolean,
): void {
TelemetryTest.client?.addTelemetryProcessor(telemetryProcessor);
TelemetryTest.appInsightsCore?.addTelemetryInitializer(telemetryInitializer);
TelemetryTest.hasTestTelemetryProviders = true;
}
}
Expand Down Expand Up @@ -126,13 +123,12 @@ test('setup() verify static common property values with sync sources', async ()

const props: Record<string, () => string | undefined> = {
deviceArchitecture: () => basePropUtils.deviceArchitecture(),
devicePlatform: () => basePropUtils.devicePlatform(),
nodePlatform: () => basePropUtils.nodePlatform(),
deviceNumCPUs: () => basePropUtils.deviceNumCPUs().toString(),
deviceTotalMemory: () => basePropUtils.deviceTotalMemory().toString(),
ciCaptured: () => basePropUtils.captureCI().toString(),
ciType: () => basePropUtils.ciType(),
isMsftInternal: () => basePropUtils.isMsftInternal().toString(),
sampleRate: () => basePropUtils.sampleRate().toString(),
isTest: () => 'true',
};

Expand Down Expand Up @@ -346,57 +342,49 @@ function verifyTestCommandTelemetryProcessor(
expectedResultCode?: errorUtils.CodedErrorType,
expectedError?: Error,
): (
envelope: appInsights.Contracts.EnvelopeTelemetry,
contextObjects?: {
[name: string]: any;
},
envelope: coreOneDS.ITelemetryItem
) => boolean {
return (envelope, _) => {
return (envelope) => {
TelemetryTest.setTestTelemetryProvidersRan();

try {
// Processor has run, so the test can (potentially) pass
TelemetryTest.setTestTelemetryProvidersRan();

// Verify roleInstance has been removed
expect(envelope.tags['ai.cloud.roleInstance']).toBeUndefined();

const properties = envelope.data.baseData?.properties;
const properties = envelope.baseData;
expect(properties).toBeDefined();

// Verify basics
expect(properties.commandName).toBe('test-command');
const commonProperties = properties!.common;
expect(commonProperties.commandName).toBe('test-command');

// Verify versions info
const versions = JSON.parse(properties.versions);
const versions = properties!.versions;
expect(versions).toBeDefined();

// Verify project info
const project = JSON.parse(properties.project);
expect(project).toStrictEqual(getTestCommandProjectInfo());

expect(Object.keys(versions).length).toBeGreaterThan(0);
for (const key of Object.keys(versions)) {
expect(versions[key]).toBe(TelemetryTest.getVersion(key));
}

if (envelope.data.baseType === 'ExceptionData') {
// Verify event name
expect(properties.eventName).toBe(CodedErrorEventName);
// Verify project info
const project = properties!.project;
expect(project).toStrictEqual(getTestCommandProjectInfo());

// Verify properties exclusive to error scenarios
if (envelope.name === CodedErrorEventName) {
// Verify exception info
const exceptions = envelope.data.baseData?.exceptions;
expect(exceptions).toBeDefined();
expect(exceptions.length).toBe(1);
expect(exceptions[0].message).toBeDefined();
expect(exceptions[0].message).not.toBe('');
const exceptionData = envelope.data!.exceptionData;
expect(exceptionData).toBeDefined();
expect(exceptionData.message).toBeDefined();
expect(exceptionData.message).not.toBe('');

expect(exceptions[0].message).toBe(
expect(exceptionData.message).toBe(
TelemetryTest.getPreserveErrorMessages()
? errorUtils.sanitizeErrorMessage(expectedError?.message || 'None')
: '[Removed]',
);

// Verify coded error info
const codedError = JSON.parse(properties.codedError);
const codedError = envelope.data!.codedError;
expect(codedError).toBeDefined();

expect(codedError.type).toBe(
Expand All @@ -409,14 +397,13 @@ function verifyTestCommandTelemetryProcessor(
(expectedError as errorUtils.CodedError).data ?? {},
);
} else {
// Verify event name
expect(envelope.data.baseData?.name).toBe(CommandEventName);
expect(properties.eventName).toBe(CommandEventName);
// If this is not error scenario, it must be a command successful event.
expect(envelope.name).toBe(CommandEventName);

// Verify command info
const expectedInfo = getTestCommandStartInfo();

const command = JSON.parse(properties.command);
const command = envelope.data!.command;
expect(command).toBeDefined();
expect(command.args).toStrictEqual(expectedInfo.args);
expect(command.options).toStrictEqual(expectedInfo.options);
Expand All @@ -428,7 +415,7 @@ function verifyTestCommandTelemetryProcessor(

// Verify extra props
const extraProps = getExtraProps();
expect(JSON.parse(properties.extraProps)).toStrictEqual(extraProps);
expect(envelope.data?.additionalData).toStrictEqual(extraProps);
}
} catch (ex) {
caughtErrors.push(
Expand All @@ -445,7 +432,7 @@ test('Telemetry run test command end to end, verify event fires', async () => {

// AI eats errors thrown in telemetry processors
const caughtErrors: Error[] = [];
TelemetryTest.addTelemetryProcessor(
TelemetryTest.addTelemetryInitializer(
verifyTestCommandTelemetryProcessor(caughtErrors),
);

Expand Down Expand Up @@ -474,7 +461,7 @@ test.each(testTelemetryOptions)(

// AI eats errors thrown in telemetry processors
const caughtErrors: Error[] = [];
TelemetryTest.addTelemetryProcessor(
TelemetryTest.addTelemetryInitializer(
verifyTestCommandTelemetryProcessor(
caughtErrors,
expectedError.type,
Expand Down Expand Up @@ -503,7 +490,7 @@ test.each(testTelemetryOptions)(

// AI eats errors thrown in telemetry processors
const caughtErrors: Error[] = [];
TelemetryTest.addTelemetryProcessor(
TelemetryTest.addTelemetryInitializer(
verifyTestCommandTelemetryProcessor(
caughtErrors,
expectedError.type,
Expand Down Expand Up @@ -533,7 +520,7 @@ test.each(testTelemetryOptions)(

// AI eats errors thrown in telemetry processors
const caughtErrors: Error[] = [];
TelemetryTest.addTelemetryProcessor(
TelemetryTest.addTelemetryInitializer(
verifyTestCommandTelemetryProcessor(
caughtErrors,
expectedError.type,
Expand All @@ -559,7 +546,7 @@ test.each(testTelemetryOptions)(

// AI eats errors thrown in telemetry processors
const caughtErrors: Error[] = [];
TelemetryTest.addTelemetryProcessor(
TelemetryTest.addTelemetryInitializer(
verifyTestCommandTelemetryProcessor(
caughtErrors,
'Unknown',
Expand All @@ -585,7 +572,7 @@ test.each(testTelemetryOptions)(

// AI eats errors thrown in telemetry processors
const caughtErrors: Error[] = [];
TelemetryTest.addTelemetryProcessor(
TelemetryTest.addTelemetryInitializer(
verifyTestCommandTelemetryProcessor(
caughtErrors,
'Unknown',
Expand Down Expand Up @@ -615,44 +602,40 @@ function getVerifyStackTelemetryProcessor(
caughtErrors: Error[],
expectedError: Error,
): (
envelope: appInsights.Contracts.EnvelopeTelemetry,
contextObjects?: {
[name: string]: any;
},
envelope: coreOneDS.ITelemetryItem,
) => boolean {
return (envelope, _) => {
return (envelope) => {
try {
// Processor has run, so the test can (potentially) pass
TelemetryTest.setTestTelemetryProvidersRan();

if (envelope.data.baseType === 'ExceptionData') {
const data = (envelope.data as any).baseData;
expect(data.exceptions).toBeDefined();
expect(data.exceptions.length).toBe(1);
expect(data.exceptions[0].message).toBeDefined();
expect(data.exceptions[0].message).not.toBe('');
if (envelope.name === CodedErrorEventName) {
const data = (envelope.data as any);
expect(data.exceptionData).toBeDefined();
expect(data.exceptionData.message).toBeDefined();
expect(data.exceptionData.message).not.toBe('');

expect(data.exceptions[0].message).toBe(
expect(data.exceptionData.message).toBe(
TelemetryTest.getPreserveErrorMessages()
? errorUtils.sanitizeErrorMessage(expectedError.message || 'None')
: '[Removed]',
);

const stack = data.exceptions[0].parsedStack;
const stack = data.exceptionData.parsedStack;
expect(stack).toBeDefined();
expect(stack.length).toBeGreaterThan(2);

const filename = path.relative(process.cwd(), __filename);
expect(stack[0].method).toEqual('b');
expect(stack[1].method).toEqual('b');
expect(stack[2].method).toEqual('a');
expect(stack[0].fileName).toEqual(
expect(stack[0].functionName).toEqual('b');
expect(stack[1].functionName).toEqual('b');
expect(stack[2].functionName).toEqual('a');
expect(stack[0].filePath).toEqual(
`[project_dir]\\???.ts(${filename.length})`,
);
expect(stack[1].fileName).toEqual(
expect(stack[1].filePath).toEqual(
`[project_dir]\\???.ts(${filename.length})`,
);
expect(stack[2].fileName).toEqual(
expect(stack[2].filePath).toEqual(
`[project_dir]\\???.ts(${filename.length})`,
);
}
Expand All @@ -675,7 +658,7 @@ test.each(testTelemetryOptions)(

// AI eats errors thrown in telemetry processors
const caughtErrors: Error[] = [];
TelemetryTest.addTelemetryProcessor(
TelemetryTest.addTelemetryInitializer(
getVerifyStackTelemetryProcessor(caughtErrors, expectedError),
);

Expand All @@ -700,7 +683,7 @@ test.each(testTelemetryOptions)(

// AI eats errors thrown in telemetry processors
const caughtErrors: Error[] = [];
TelemetryTest.addTelemetryProcessor(
TelemetryTest.addTelemetryInitializer(
getVerifyStackTelemetryProcessor(caughtErrors, expectedError),
);

Expand All @@ -714,4 +697,4 @@ test.each(testTelemetryOptions)(
expect(caughtErrors).toHaveLength(0);
});
},
);
);
Loading
Loading