Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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": "prerelease",
"comment": "Enabled telemetry collection",
"packageName": "@react-native-windows/telemetry",
"email": "14967941+danielayala94@users.noreply.github.com",
"dependentChangeType": "patch"
}
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 @@ -20,8 +20,9 @@
"dependencies": {
"@azure/core-auth": "1.5.0",
"@react-native-windows/fs": "0.76.0-preview.2",
"@microsoft/1ds-core-js": "^4.3.0",
"@microsoft/1ds-post-js": "^4.3.0",
"@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;
},
) => boolean,
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 @@ -345,58 +341,48 @@ function verifyTestCommandTelemetryProcessor(
caughtErrors: Error[],
expectedResultCode?: errorUtils.CodedErrorType,
expectedError?: Error,
): (
envelope: appInsights.Contracts.EnvelopeTelemetry,
contextObjects?: {
[name: string]: any;
},
) => boolean {
return (envelope, _) => {
): (envelope: coreOneDS.ITelemetryItem) => boolean {
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 +395,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 +413,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 +430,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 +459,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 +488,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 +518,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 +544,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 +570,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 @@ -614,45 +599,39 @@ function a(s: string) {
function getVerifyStackTelemetryProcessor(
caughtErrors: Error[],
expectedError: Error,
): (
envelope: appInsights.Contracts.EnvelopeTelemetry,
contextObjects?: {
[name: string]: any;
},
) => boolean {
return (envelope, _) => {
): (envelope: coreOneDS.ITelemetryItem) => boolean {
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 +654,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 +679,7 @@ test.each(testTelemetryOptions)(

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

Expand Down
Loading