Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@react-native-windows/telemetry

Package Overview
Dependencies
Maintainers
0
Versions
194
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@react-native-windows/telemetry - npm Package Compare versions

Comparing version 0.0.0-canary.110 to 0.0.0-canary.112

6

lib-commonjs/e2etest/telemetry.test.d.ts

@@ -7,3 +7,3 @@ /**

*/
import * as appInsights from 'applicationinsights';
import * as coreOneDS from '@microsoft/1ds-core-js';
import { Telemetry, TelemetryOptions } from '../telemetry';

@@ -26,5 +26,3 @@ export declare 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): void;
static addTelemetryInitializer(telemetryInitializer: (envelope: coreOneDS.ITelemetryItem) => boolean): void;
}

@@ -39,2 +39,9 @@ "use strict";

const versionUtils = __importStar(require("../utils/versionUtils"));
class CustomTestError extends Error {
constructor(message) {
super(message);
this.name = 'CustomTestError';
this.errno = '123';
}
}
class TelemetryTest extends telemetry_1.Telemetry {

@@ -49,3 +56,3 @@ /** Run at the beginning of each test. */

// Ensure that we don't actually fire events when testing
telemetry_1.Telemetry.isTest = true;
telemetry_1.Telemetry.isTestEnvironment = true;
await telemetry_1.Telemetry.setup(options);

@@ -56,11 +63,10 @@ }

var _a;
(_a = telemetry_1.Telemetry.client) === null || _a === void 0 ? void 0 : _a.flush({
callback: _ => {
if (TelemetryTest.hasTestTelemetryProviders) {
expect(TelemetryTest.testTelemetryProvidersRan).toBe(true);
}
if (finalCallback) {
finalCallback();
}
},
(_a = telemetry_1.Telemetry.appInsightsCore) === null || _a === void 0 ? void 0 : _a.flush(undefined /* isAsync */, () => {
// Your callback logic here
if (TelemetryTest.hasTestTelemetryProviders) {
expect(TelemetryTest.testTelemetryProvidersRan).toBe(true);
}
if (finalCallback) {
finalCallback();
}
});

@@ -74,4 +80,3 @@ }

static getCommonProperty(key) {
var _a;
return (_a = TelemetryTest.client) === null || _a === void 0 ? void 0 : _a.commonProperties[key];
return TelemetryTest.commonProperties[key];
}

@@ -89,5 +94,5 @@ /** Retrieves the version of the specified tool/package. */

/** Adds a telemetry processor, usually for verifying the envelope. */
static addTelemetryProcessor(telemetryProcessor) {
static addTelemetryInitializer(telemetryInitializer) {
var _a;
(_a = TelemetryTest.client) === null || _a === void 0 ? void 0 : _a.addTelemetryProcessor(telemetryProcessor);
(_a = TelemetryTest.appInsightsCore) === null || _a === void 0 ? void 0 : _a.addTelemetryInitializer(telemetryInitializer);
TelemetryTest.hasTestTelemetryProviders = true;

@@ -125,3 +130,3 @@ }

deviceArchitecture: () => basePropUtils.deviceArchitecture(),
devicePlatform: () => basePropUtils.devicePlatform(),
nodePlatform: () => basePropUtils.nodePlatform(),
deviceNumCPUs: () => basePropUtils.deviceNumCPUs().toString(),

@@ -132,3 +137,2 @@ deviceTotalMemory: () => basePropUtils.deviceTotalMemory().toString(),

isMsftInternal: () => basePropUtils.isMsftInternal().toString(),
sampleRate: () => basePropUtils.sampleRate().toString(),
isTest: () => 'true',

@@ -295,19 +299,15 @@ };

function verifyTestCommandTelemetryProcessor(caughtErrors, expectedResultCode, expectedError) {
return (envelope, _) => {
var _a, _b, _c, _d;
return envelope => {
var _a, _b;
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 = (_a = envelope.data.baseData) === null || _a === void 0 ? void 0 : _a.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);

@@ -317,16 +317,17 @@ for (const key of Object.keys(versions)) {

}
if (envelope.data.baseType === 'ExceptionData') {
// Verify event name
expect(properties.eventName).toBe(telemetry_1.CodedErrorEventName);
// Verify project info
const project = properties.project;
expect(project).toStrictEqual(getTestCommandProjectInfo());
// Verify properties exclusive to error scenarios
if (envelope.name === telemetry_1.CodedErrorEventName) {
// Verify exception info
const exceptions = (_b = envelope.data.baseData) === null || _b === void 0 ? void 0 : _b.exceptions;
expect(exceptions).toBeDefined();
expect(exceptions.length).toBe(1);
expect(exceptions[0].message).toBeDefined();
expect(exceptions[0].message).not.toBe('');
expect(exceptions[0].message).toBe(TelemetryTest.getPreserveErrorMessages()
const exceptionData = envelope.data.exceptionData;
expect(exceptionData).toBeDefined();
expect(exceptionData.message).toBeDefined();
expect(exceptionData.message).not.toBe('');
expect(exceptionData.message).toBe(TelemetryTest.getPreserveErrorMessages()
? errorUtils.sanitizeErrorMessage((expectedError === null || expectedError === void 0 ? void 0 : expectedError.message) || 'None')
: '[Removed]');
// Verify coded error info
const codedError = JSON.parse(properties.codedError);
const codedError = envelope.data.codedError;
expect(codedError).toBeDefined();

@@ -336,11 +337,16 @@ expect(codedError.type).toBe(expectedError instanceof errorUtils.CodedError

: 'Unknown');
expect(codedError.data).toStrictEqual((_c = expectedError.data) !== null && _c !== void 0 ? _c : {});
// If the exception type is not CodedError but any data got copied into envelope.CodedError.data,
// for instance autolinking error info, build the expected CodedError.data.
let expectedCodedErrorData = {};
if (expectedError instanceof CustomTestError) {
expectedCodedErrorData = { errno: expectedError.errno };
}
expect(codedError.data).toStrictEqual((_a = expectedError.data) !== null && _a !== void 0 ? _a : expectedCodedErrorData);
}
else {
// Verify event name
expect((_d = envelope.data.baseData) === null || _d === void 0 ? void 0 : _d.name).toBe(telemetry_1.CommandEventName);
expect(properties.eventName).toBe(telemetry_1.CommandEventName);
// If this is not error scenario, it must be a command successful event.
expect(envelope.name).toBe(telemetry_1.CommandEventName);
// Verify command info
const expectedInfo = getTestCommandStartInfo();
const command = JSON.parse(properties.command);
const command = envelope.data.command;
expect(command).toBeDefined();

@@ -354,3 +360,3 @@ expect(command.args).toStrictEqual(expectedInfo.args);

const extraProps = getExtraProps();
expect(JSON.parse(properties.extraProps)).toStrictEqual(extraProps);
expect((_b = envelope.data) === null || _b === void 0 ? void 0 : _b.additionalData).toStrictEqual(extraProps);
}

@@ -368,3 +374,3 @@ }

const caughtErrors = [];
TelemetryTest.addTelemetryProcessor(verifyTestCommandTelemetryProcessor(caughtErrors));
TelemetryTest.addTelemetryInitializer(verifyTestCommandTelemetryProcessor(caughtErrors));
await runTestCommandE2E(testCommandBody);

@@ -385,3 +391,3 @@ TelemetryTest.endTest(() => {

const caughtErrors = [];
TelemetryTest.addTelemetryProcessor(verifyTestCommandTelemetryProcessor(caughtErrors, expectedError.type, expectedError));
TelemetryTest.addTelemetryInitializer(verifyTestCommandTelemetryProcessor(caughtErrors, expectedError.type, expectedError));
await runTestCommandE2E(() => testCommandBody(expectedError));

@@ -398,3 +404,3 @@ TelemetryTest.endTest(() => {

const caughtErrors = [];
TelemetryTest.addTelemetryProcessor(verifyTestCommandTelemetryProcessor(caughtErrors, expectedError.type, expectedError));
TelemetryTest.addTelemetryInitializer(verifyTestCommandTelemetryProcessor(caughtErrors, expectedError.type, expectedError));
await runTestCommandE2E(() => testCommandBody(expectedError));

@@ -411,3 +417,3 @@ TelemetryTest.endTest(() => {

const caughtErrors = [];
TelemetryTest.addTelemetryProcessor(verifyTestCommandTelemetryProcessor(caughtErrors, expectedError.type, expectedError));
TelemetryTest.addTelemetryInitializer(verifyTestCommandTelemetryProcessor(caughtErrors, expectedError.type, expectedError));
await runTestCommandE2E(() => testCommandBody(expectedError));

@@ -424,3 +430,3 @@ TelemetryTest.endTest(() => {

const caughtErrors = [];
TelemetryTest.addTelemetryProcessor(verifyTestCommandTelemetryProcessor(caughtErrors, 'Unknown', expectedError));
TelemetryTest.addTelemetryInitializer(verifyTestCommandTelemetryProcessor(caughtErrors, 'Unknown', expectedError));
await runTestCommandE2E(() => testCommandBody(expectedError));

@@ -437,3 +443,3 @@ TelemetryTest.endTest(() => {

const caughtErrors = [];
TelemetryTest.addTelemetryProcessor(verifyTestCommandTelemetryProcessor(caughtErrors, 'Unknown', expectedError));
TelemetryTest.addTelemetryInitializer(verifyTestCommandTelemetryProcessor(caughtErrors, 'Unknown', expectedError));
await runTestCommandE2E(() => testCommandBody(expectedError));

@@ -453,25 +459,24 @@ TelemetryTest.endTest(() => {

function getVerifyStackTelemetryProcessor(caughtErrors, expectedError) {
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.baseData;
expect(data.exceptions).toBeDefined();
expect(data.exceptions.length).toBe(1);
expect(data.exceptions[0].message).toBeDefined();
expect(data.exceptions[0].message).not.toBe('');
expect(data.exceptions[0].message).toBe(TelemetryTest.getPreserveErrorMessages()
if (envelope.name === telemetry_1.CodedErrorEventName) {
const data = envelope.data;
expect(data.exceptionData).toBeDefined();
expect(data.exceptionData.message).toBeDefined();
expect(data.exceptionData.message).not.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(`[project_dir]\\???.ts(${filename.length})`);
expect(stack[1].fileName).toEqual(`[project_dir]\\???.ts(${filename.length})`);
expect(stack[2].fileName).toEqual(`[project_dir]\\???.ts(${filename.length})`);
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].filePath).toEqual(`[project_dir]\\???.ts(${filename.length})`);
expect(stack[2].filePath).toEqual(`[project_dir]\\???.ts(${filename.length})`);
}

@@ -490,3 +495,3 @@ }

const caughtErrors = [];
TelemetryTest.addTelemetryProcessor(getVerifyStackTelemetryProcessor(caughtErrors, expectedError));
TelemetryTest.addTelemetryInitializer(getVerifyStackTelemetryProcessor(caughtErrors, expectedError));
await runTestCommandE2E(async () => {

@@ -506,3 +511,3 @@ await promiseDelay(100);

const caughtErrors = [];
TelemetryTest.addTelemetryProcessor(getVerifyStackTelemetryProcessor(caughtErrors, expectedError));
TelemetryTest.addTelemetryInitializer(getVerifyStackTelemetryProcessor(caughtErrors, expectedError));
await runTestCommandE2E(async () => {

@@ -517,2 +522,14 @@ await promiseDelay(100);

});
test.each(testTelemetryOptions)('A custom Error-based object with MS Build error info is copied into codedError.data appropriately by trackException()', async (options) => {
await TelemetryTest.startTest(options);
const expectedError = new CustomTestError('some message');
// AI eats errors thrown in telemetry processors
const caughtErrors = [];
TelemetryTest.addTelemetryInitializer(verifyTestCommandTelemetryProcessor(caughtErrors, 'Unknown', expectedError));
await runTestCommandE2E(() => testCommandBody(expectedError));
TelemetryTest.endTest(() => {
// Check if any errors were thrown
expect(caughtErrors).toHaveLength(0);
});
});
//# sourceMappingURL=telemetry.test.js.map

@@ -6,3 +6,3 @@ /**

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

@@ -39,8 +39,11 @@ import * as projectUtils from './utils/projectUtils';

export declare class Telemetry {
protected static client?: appInsights.TelemetryClient;
protected static appInsightsCore?: coreOneDS.AppInsightsCore;
protected static options: TelemetryOptions;
protected static isTest: boolean;
protected static isTestEnvironment: boolean;
protected static commandInfo: CommandInfo;
protected static versionsProp: Record<string, string>;
protected static projectProp?: projectUtils.AppProjectInfo | projectUtils.DependencyProjectInfo;
protected static commonProperties: {
[key: string]: string;
};
protected static getDefaultSetupString(): string;

@@ -52,22 +55,7 @@ protected static reset(): void;

static setup(options?: Partial<TelemetryOptions>): Promise<void>;
/** Sets up Telemetry.client. */
private static basicTelemetryInitializer;
/** Sets up Telemetry.appInsightsCore. */
private static setupClient;
/** Sets up any base properties that all telemetry events require. */
private static setupBaseProperties;
/** Sets up any telemetry processors. */
private static setupTelemetryProcessors;
/**
* Performs the processing necessary (mostly PII sanitization) for all events.
* @param envelope The ApplicationInsights event envelope.
* @param _contextObjects An optional context object.
* @returns Whether to kee
*/
private static basicTelemetryProcessor;
/**
* Performs the processing necessary (mostly PII sanitization) for error events.
* @param envelope
* @param _contextObjects
* @returns
*/
private static errorTelemetryProcessor;
/** Tries to update the version of the named package/tool by calling getValue(). */

@@ -84,5 +72,7 @@ static tryUpdateVersionsProp(name: string, getValue: () => Promise<string | null>, forceRefresh?: boolean): Promise<boolean>;

static endCommand(info: CommandEndInfo, extraProps?: Record<string, any>): void;
private static trackEvent;
private static trackCommandEvent;
static trackException(error: Error, extraProps?: Record<string, any>): void;
static convertErrorIntoExceptionData(error: Error): Record<string, any>;
}
export {};

@@ -32,8 +32,9 @@ "use strict";

exports.Telemetry = exports.NuGetPackagesWeTrack = exports.NpmPackagesWeTrack = exports.EventNamesWeTrack = exports.CodedErrorEventName = exports.CommandEventName = void 0;
const appInsights = __importStar(require("applicationinsights"));
const coreOneDS = __importStar(require("@microsoft/1ds-core-js"));
const _1ds_post_js_1 = require("@microsoft/1ds-post-js");
const basePropUtils = __importStar(require("./utils/basePropUtils"));
const versionUtils = __importStar(require("./utils/versionUtils"));
const errorUtils = __importStar(require("./utils/errorUtils"));
// This is our key with the AI backend
const RNWSetupString = '795006ca-cf54-40ee-8bc6-03deb91401c3';
// 1DS instrumentation key
const RNW_1DS_INSTRUMENTATION_KEY = '49ff6d3ef12f4578a7b75a2573d9dba8-026332b2-2d50-452f-ad0d-50f921c97a9d-7145';
// Environment variable to override the default setup string

@@ -74,9 +75,9 @@ const ENV_SETUP_OVERRIDE = 'RNW_TELEMETRY_SETUP';

// Enable overriding the default setup string via an environment variable
return (_a = process.env[ENV_SETUP_OVERRIDE]) !== null && _a !== void 0 ? _a : RNWSetupString;
return (_a = process.env[ENV_SETUP_OVERRIDE]) !== null && _a !== void 0 ? _a : RNW_1DS_INSTRUMENTATION_KEY;
}
static reset() {
// Reset client
if (Telemetry.client) {
Telemetry.client.flush();
Telemetry.client = undefined;
if (Telemetry.appInsightsCore) {
Telemetry.appInsightsCore.flush();
Telemetry.appInsightsCore = undefined;
}

@@ -94,3 +95,3 @@ // Reset local members

static isEnabled() {
return Telemetry.client !== undefined;
return Telemetry.appInsightsCore !== undefined;
}

@@ -102,3 +103,3 @@ static getSessionId() {

static async setup(options) {
if (Telemetry.client) {
if (Telemetry.appInsightsCore) {
// Bail since we've already setup

@@ -108,3 +109,5 @@ return;

// Bail if we're in CI and not capturing CI
if (!this.isTest && basePropUtils.isCI() && !basePropUtils.captureCI()) {
if (!Telemetry.isTestEnvironment &&
basePropUtils.isCI() &&
!basePropUtils.captureCI()) {
return;

@@ -116,56 +119,61 @@ }

await Telemetry.setupBaseProperties();
Telemetry.setupTelemetryProcessors();
}
/** Sets up Telemetry.client. */
static basicTelemetryInitializer(envelope) {
// Filter out "legacy" events from older stable branches
if (envelope.name && exports.EventNamesWeTrack.includes(envelope.name)) {
return true;
}
return false;
}
/** Sets up Telemetry.appInsightsCore. */
static setupClient() {
var _a;
appInsights.Configuration.setInternalLogging(false, false);
Telemetry.client = new appInsights.TelemetryClient(Telemetry.options.setupString);
// Allow overriding the proxy server via an environment variable
const proxyServer = process.env[ENV_PROXY_OVERRIDE];
if (proxyServer) {
Telemetry.client.config.proxyHttpUrl = proxyServer;
Telemetry.client.config.proxyHttpsUrl = proxyServer;
const postChannel = new _1ds_post_js_1.PostChannel();
const coreConfiguration = {
instrumentationKey: Telemetry.getDefaultSetupString(),
};
const postChannelConfig = {
eventsLimitInMem: 5000,
};
coreConfiguration.extensionConfig = {};
coreConfiguration.extensionConfig[postChannel.identifier] =
postChannelConfig;
// Allow overriding the endpoint URL via an environment variable.
if (process.env[ENV_PROXY_OVERRIDE] !== undefined) {
coreConfiguration.endpointUrl = process.env[ENV_PROXY_OVERRIDE];
}
Telemetry.client.config.disableAppInsights = Telemetry.isTest;
Telemetry.client.config.disableStatsbeat = true;
// Despite trying to disable the statsbeat, it might still be running: https://github.com/microsoft/ApplicationInsights-node.js/issues/943
// So we want to disable it, and despite the method's typing, getStatsbeat() _can_ return undefined
(_a = Telemetry.client.getStatsbeat()) === null || _a === void 0 ? void 0 : _a.enable(false);
Telemetry.client.channel.setUseDiskRetryCaching(!Telemetry.isTest);
Telemetry.appInsightsCore = new coreOneDS.AppInsightsCore();
Telemetry.appInsightsCore.initialize(coreConfiguration, [postChannel] /* extensions */);
Telemetry.appInsightsCore.addTelemetryInitializer(Telemetry.basicTelemetryInitializer);
}
/** Sets up any base properties that all telemetry events require. */
static async setupBaseProperties() {
Telemetry.client.commonProperties.deviceId =
await basePropUtils.deviceId();
Telemetry.client.commonProperties.deviceArchitecture =
Telemetry.commonProperties.deviceId = await basePropUtils.deviceId();
Telemetry.commonProperties.fullBuildInfo =
await basePropUtils.fullBuildInfo();
Telemetry.commonProperties.deviceArchitecture =
basePropUtils.deviceArchitecture();
Telemetry.client.commonProperties.nodeArchitecture =
Telemetry.commonProperties.nodeArchitecture =
basePropUtils.nodeArchitecture();
Telemetry.client.commonProperties.devicePlatform =
basePropUtils.devicePlatform();
Telemetry.client.commonProperties.deviceLocale =
Telemetry.commonProperties.nodePlatform = basePropUtils.nodePlatform();
Telemetry.commonProperties.deviceClass = basePropUtils.deviceClass();
Telemetry.commonProperties.deviceLocale =
await basePropUtils.deviceLocale();
Telemetry.client.commonProperties.deviceNumCPUs = basePropUtils
Telemetry.commonProperties.deviceNumCPUs = basePropUtils
.deviceNumCPUs()
.toString();
Telemetry.client.commonProperties.deviceTotalMemory = basePropUtils
Telemetry.commonProperties.deviceTotalMemory = basePropUtils
.deviceTotalMemory()
.toString();
Telemetry.client.commonProperties.deviceDiskFreeSpace = basePropUtils
Telemetry.commonProperties.deviceDiskFreeSpace = basePropUtils
.deviceDiskFreeSpace()
.toString();
Telemetry.client.commonProperties.ciCaptured = basePropUtils
Telemetry.commonProperties.ciCaptured = basePropUtils
.captureCI()
.toString();
Telemetry.client.commonProperties.ciType = basePropUtils.ciType();
Telemetry.client.commonProperties.isMsftInternal = basePropUtils
Telemetry.commonProperties.ciType = basePropUtils.ciType();
Telemetry.commonProperties.isMsftInternal = basePropUtils
.isMsftInternal()
.toString();
Telemetry.client.commonProperties.sampleRate = basePropUtils
.sampleRate()
.toString();
Telemetry.client.commonProperties.isTest = Telemetry.isTest.toString();
Telemetry.client.commonProperties.sessionId = Telemetry.getSessionId();
Telemetry.client.config.samplingPercentage = basePropUtils.sampleRate();
Telemetry.commonProperties.isTest = Telemetry.isTestEnvironment.toString();
Telemetry.commonProperties.sessionId = Telemetry.getSessionId();
await Telemetry.populateToolsVersions();

@@ -176,58 +184,5 @@ if (Telemetry.options.populateNpmPackageVersions) {

}
/** Sets up any telemetry processors. */
static setupTelemetryProcessors() {
Telemetry.client.addTelemetryProcessor(Telemetry.basicTelemetryProcessor);
Telemetry.client.addTelemetryProcessor(Telemetry.errorTelemetryProcessor);
}
/**
* Performs the processing necessary (mostly PII sanitization) for all events.
* @param envelope The ApplicationInsights event envelope.
* @param _contextObjects An optional context object.
* @returns Whether to kee
*/
static basicTelemetryProcessor(envelope, _contextObjects) {
var _a;
delete envelope.tags['ai.cloud.roleInstance'];
// Filter out "legacy" events from older stable branches
const properties = (_a = envelope.data.baseData) === null || _a === void 0 ? void 0 : _a.properties;
if ((properties === null || properties === void 0 ? void 0 : properties.eventName) &&
exports.EventNamesWeTrack.includes(properties.eventName)) {
return true;
}
return false;
}
/**
* Performs the processing necessary (mostly PII sanitization) for error events.
* @param envelope
* @param _contextObjects
* @returns
*/
static errorTelemetryProcessor(envelope, _contextObjects) {
if (envelope.data.baseType === 'ExceptionData') {
const data = envelope.data.baseData;
if (data === null || data === void 0 ? void 0 : data.exceptions) {
for (const exception of data.exceptions) {
for (const frame of exception.parsedStack) {
errorUtils.sanitizeErrorStackFrame(frame);
}
// Exception message must never be blank, or AI will reject it
exception.message = exception.message || '[None]';
// CodedError has non-PII information in its 'type' member, plus optionally some more info in its 'data'.
// The message may contain PII information. This can be sanitized, but for now delete it.
// Note that the type of data.exceptions[0] is always going to be ExceptionDetails. It is not the original thrown exception.
// https://github.com/microsoft/ApplicationInsights-node.js/issues/707
if (Telemetry.options.preserveErrorMessages) {
exception.message = errorUtils.sanitizeErrorMessage(exception.message);
}
else {
exception.message = '[Removed]';
}
}
}
}
return true;
}
/** Tries to update the version of the named package/tool by calling getValue(). */
static async tryUpdateVersionsProp(name, getValue, forceRefresh) {
if (!Telemetry.client) {
if (!Telemetry.appInsightsCore) {
return true;

@@ -265,3 +220,3 @@ }

static setProjectInfo(info) {
if (!Telemetry.client) {
if (!Telemetry.appInsightsCore) {
return;

@@ -272,5 +227,6 @@ }

static startCommand(info) {
if (!Telemetry.client) {
if (!Telemetry.appInsightsCore) {
return;
}
// startCommand() was called before invoking endCommand(), bail out.
if (Telemetry.commandInfo.startInfo) {

@@ -282,8 +238,9 @@ return;

// Set common command props
Telemetry.client.commonProperties.commandName = info.commandName;
Telemetry.commonProperties.commandName = info.commandName;
}
static endCommand(info, extraProps) {
if (!Telemetry.client) {
if (!Telemetry.appInsightsCore) {
return;
}
// startCommand() wasn't called, bail out.
if (!Telemetry.commandInfo.startInfo) {

@@ -296,9 +253,48 @@ return;

}
static trackEvent(telemetryItem) {
// Populate Part A
telemetryItem.ver = '4.0'; // Current Common Schema version
telemetryItem.time = new Date().toISOString();
telemetryItem.iKey = RNW_1DS_INSTRUMENTATION_KEY;
// Populate Part A extensions
telemetryItem.ext = {};
telemetryItem.ext.device = {
id: Telemetry.commonProperties.deviceId,
deviceClass: Telemetry.commonProperties.deviceClass,
};
telemetryItem.ext.os = {
locale: Telemetry.commonProperties.deviceLocale,
ver: Telemetry.commonProperties.fullBuildInfo,
};
// Populate most of "common" properties into Part B.
telemetryItem.baseData = {
common: {
device: {
architecture: Telemetry.commonProperties.deviceArchitecture,
numCPUs: Telemetry.commonProperties.numCPUs,
totalMemory: Telemetry.commonProperties.totalMemory,
diskFreeSpace: Telemetry.commonProperties.deviceDiskFreeSpace,
},
nodePlatform: Telemetry.commonProperties.nodePlatform,
nodeArchitecture: Telemetry.commonProperties.nodeArchitecture,
ciCaptured: Telemetry.commonProperties.ciCaptured,
ciType: Telemetry.commonProperties.ciType,
isMsftInternal: Telemetry.commonProperties.isMsftInternal,
isCliTest: Telemetry.commonProperties.isTest,
sessionId: Telemetry.commonProperties.sessionId,
commandName: Telemetry.commonProperties.commandName,
},
// Set project and versions props, belonging to Part B.
project: Telemetry.projectProp,
versions: Telemetry.versionsProp,
};
// Send and post the telemetry event!
Telemetry.appInsightsCore.track(telemetryItem);
Telemetry.appInsightsCore.flush();
}
static trackCommandEvent(extraProps) {
var _a, _b, _c, _d;
const props = {
eventName: exports.CommandEventName,
};
// Set command props
props.command = {
const telemetryItem = { name: exports.CommandEventName };
// This is logged in Part C.
const command = {
options: (_a = Telemetry.commandInfo.startInfo) === null || _a === void 0 ? void 0 : _a.options,

@@ -311,25 +307,22 @@ defaultOptions: (_b = Telemetry.commandInfo.startInfo) === null || _b === void 0 ? void 0 : _b.defaultOptions,

};
// Set remaining common props
props.project = Telemetry.projectProp;
props.versions = Telemetry.versionsProp;
// Set extra props
props.extraProps = {};
Object.assign(props.extraProps, extraProps);
// Fire event
Telemetry.client.trackEvent({ name: props.eventName, properties: props });
Telemetry.client.flush();
telemetryItem.data = {
command: command,
};
if (extraProps) {
telemetryItem.data.additionalData = extraProps;
}
// Populate common properties and fire event
Telemetry.trackEvent(telemetryItem);
}
static trackException(error, extraProps) {
var _a, _b;
if (!Telemetry.client) {
if (!Telemetry.appInsightsCore) {
return;
}
const props = {
eventName: exports.CodedErrorEventName,
};
// Save off CodedError info
const telemetryItem = { name: exports.CodedErrorEventName };
// Save off CodedError info in Part C.
const codedError = error instanceof errorUtils.CodedError
? error
: null;
props.codedError = {
const codedErrorStruct = {
type: (_a = codedError === null || codedError === void 0 ? void 0 : codedError.type) !== null && _a !== void 0 ? _a : 'Unknown',

@@ -341,3 +334,3 @@ data: (_b = codedError === null || codedError === void 0 ? void 0 : codedError.data) !== null && _b !== void 0 ? _b : {},

// Always grab MSBuild error codes if possible
props.codedError.data.msBuildErrors = error.msBuildErrorMessages
codedErrorStruct.data.msBuildErrors = error.msBuildErrorMessages
.map(errorUtils.tryGetErrorCode)

@@ -347,3 +340,3 @@ .filter((msg) => msg);

if (Telemetry.options.preserveErrorMessages) {
props.codedError.data.msBuildErrorMessages = error.msBuildErrorMessages
codedErrorStruct.data.msBuildErrorMessages = error.msBuildErrorMessages
.map(errorUtils.sanitizeErrorMessage)

@@ -357,20 +350,58 @@ .filter((msg) => msg);

if (error[f]) {
props.codedError.data[f] = error[f];
codedErrorStruct.data[f] = error[f];
}
}
// Set remaining common props
props.project = Telemetry.projectProp;
props.versions = Telemetry.versionsProp;
// Set extra props
props.extraProps = {};
Object.assign(props.extraProps, extraProps);
// Fire event
Telemetry.client.trackException({
exception: error,
properties: props,
// Break down TS Error object into Exception Data
const exceptionData = Telemetry.convertErrorIntoExceptionData(error);
telemetryItem.data = {
codedError: codedErrorStruct,
exceptionData: exceptionData,
};
Telemetry.trackEvent(telemetryItem);
}
static convertErrorIntoExceptionData(error) {
var _a;
const exceptionData = {
hasFullStack: false,
message: error.message,
parsedStack: {},
};
exceptionData.message = exceptionData.message || '[None]';
// CodedError has non-PII information in its 'type' member, plus optionally some more info in its 'data'.
// The message may contain PII information. This can be sanitized, but for now delete it.
if (Telemetry.options.preserveErrorMessages) {
exceptionData.message = errorUtils.sanitizeErrorMessage(exceptionData.message);
}
else {
exceptionData.message = '[Removed]';
}
const lines = (_a = error.stack) === null || _a === void 0 ? void 0 : _a.split('\n');
const parsedStack = lines === null || lines === void 0 ? void 0 : lines.slice(1).map(line => {
const errorStackFrame = {};
const match = line
.trim()
.match(/^\s*at\s+(?:(.*?)\s+\((.*):(\d+):(\d+)\)|(.*):(\d+):(\d+))$/);
if (match) {
errorStackFrame.functionName = match[1] || 'N/A'; // Use a default value if no function name
errorStackFrame.filePath = match[2] || match[5];
errorStackFrame.lineNumber =
parseInt(match[3], 10) || parseInt(match[6], 10);
errorStackFrame.columnNumber =
parseInt(match[4], 10) || parseInt(match[7], 10);
}
return errorStackFrame;
});
Telemetry.client.flush();
if (parsedStack) {
parsedStack.filter(Boolean);
// Sanitize parsed error stack frames
for (const frame of parsedStack) {
errorUtils.sanitizeErrorStackFrame(frame);
}
exceptionData.hasFullStack = true;
exceptionData.parsedStack = parsedStack;
}
return exceptionData;
}
}
Telemetry.client = undefined;
Telemetry.appInsightsCore = undefined;
Telemetry.options = {

@@ -381,7 +412,10 @@ setupString: Telemetry.getDefaultSetupString(),

};
Telemetry.isTest = basePropUtils.isCliTest();
Telemetry.isTestEnvironment = basePropUtils.isCliTest();
Telemetry.commandInfo = {};
// Stores the version of a list of packages used by the RNW app project.
Telemetry.versionsProp = {};
Telemetry.projectProp = undefined;
// Store "Common Properties" in a single object. This will be logged in all telemetry events.
Telemetry.commonProperties = {};
exports.Telemetry = Telemetry;
//# sourceMappingURL=telemetry.js.map

@@ -54,4 +54,4 @@ "use strict";

});
test('devicePlatform() is valid', () => {
const value = basePropUtils.devicePlatform();
test('deviceClass() is valid', () => {
const value = basePropUtils.deviceClass();
expect(value).toBeDefined();

@@ -61,2 +61,8 @@ expect(value).not.toBe('');

});
test('nodePlatform() is valid', () => {
const value = basePropUtils.nodePlatform();
expect(value).toBeDefined();
expect(value).not.toBe('');
expect(value).not.toBeNull();
});
test('deviceLocale() is valid', async () => {

@@ -83,7 +89,2 @@ const value = await basePropUtils.deviceLocale();

});
test('sampleRate() is within valid range', () => {
const value = basePropUtils.sampleRate();
expect(value).toBeGreaterThanOrEqual(0);
expect(value).toBeLessThanOrEqual(100);
});
test('ciType() is valid', () => {

@@ -141,2 +142,8 @@ const value = basePropUtils.ciType();

});
test('fullBuildInfo() is valid', () => {
const value = basePropUtils.fullBuildInfo();
expect(value).toBeDefined();
expect(value).not.toBe('');
expect(value).not.toBeNull();
});
//# sourceMappingURL=basePropUtils.test.js.map

@@ -116,52 +116,46 @@ "use strict";

test('sanitizeErrorStackFrame() with empty frame', () => {
const emptyFrame = {
level: 0,
method: '',
fileName: '',
assembly: 'asdf',
line: 0,
const stackFrame = {
functionName: '',
filePath: '',
lineNumber: 0,
columnNumber: 0,
};
errorUtils.sanitizeErrorStackFrame(emptyFrame);
expect(emptyFrame).toEqual({
level: 0,
assembly: '',
fileName: '[path]',
method: '',
line: 0,
errorUtils.sanitizeErrorStackFrame(stackFrame);
expect(stackFrame).toEqual({
functionName: '',
filePath: '[path]',
lineNumber: 0,
columnNumber: 0,
});
});
test('sanitizeErrorStackFrame() with assembly name', () => {
const frame1 = {
method: '',
fileName: `${process.cwd()}\\foo.js`,
assembly: 'asdf',
level: 0,
line: 0,
const stackFrame = {
functionName: '',
filePath: `${process.cwd()}\\foo.js`,
lineNumber: 10,
columnNumber: 14,
};
errorUtils.sanitizeErrorStackFrame(frame1);
expect(frame1).toEqual({
assembly: '',
fileName: '[project_dir]\\???.js(6)',
method: '',
level: 0,
line: 0,
errorUtils.sanitizeErrorStackFrame(stackFrame);
expect(stackFrame).toEqual({
functionName: '',
filePath: '[project_dir]\\???.js(6)',
lineNumber: 10,
columnNumber: 14,
});
});
test('sanitizeErrorStackFrame() with method name', () => {
const frame2 = {
method: `myMethod (something ${process.cwd()}`,
fileName: `${process.cwd()}\\telemetry\\foo.js`,
assembly: 'asdf',
level: 1,
line: 42,
const stackFrame = {
functionName: `myMethod (something ${process.cwd()}`,
filePath: `${process.cwd()}\\telemetry\\foo.js`,
lineNumber: 10,
columnNumber: 14,
};
errorUtils.sanitizeErrorStackFrame(frame2);
expect(frame2).toEqual({
assembly: '',
fileName: '[project_dir]\\???.js(16)',
method: 'myMethod',
level: 1,
line: 42,
errorUtils.sanitizeErrorStackFrame(stackFrame);
expect(stackFrame).toEqual({
functionName: 'myMethod',
filePath: '[project_dir]\\???.js(16)',
lineNumber: 10,
columnNumber: 14,
});
});
//# sourceMappingURL=errorUtils.test.js.map

@@ -7,2 +7,7 @@ /**

/**
* Given a path and a key, retrieves the value from the Registry.
* @returns If the path and key exist, the requested value from the Registry; empty string otherwise.
*/
export declare function getValueFromRegistry(path: string, key: string): Promise<string>;
/**
* Gets a telemetry-safe stable device ID.

@@ -13,2 +18,8 @@ * @returns A telemetry-safe stable device ID.

/**
* Gets the Windows build name, number and architecture.
* @returns A string containing the Windows build name, number and architecture.
* e.g. 19569.1000.amd64fre.rs_prerelease.200214-1419
*/
export declare function fullBuildInfo(): Promise<string>;
/**
* Gets the device architecture, like x86/x64/arm64.

@@ -24,7 +35,12 @@ * @returns The device architecture.

/**
* Gets the device platform, like darwin/linux/win32.
* Gets the node platform, like darwin/linux/win32.
* @returns The device platform.
*/
export declare function devicePlatform(): string;
export declare function nodePlatform(): string;
/**
* Gets the OS name, to be filled in the PartA device.deviceClass field.
* @returns The device class.
*/
export declare function deviceClass(): string;
/**
* Gets the device locale.

@@ -51,7 +67,2 @@ * @returns The device locale.

/**
* Gets the telemetry sample rate.
* @returns The telemetry sample rate.
*/
export declare function sampleRate(): number;
/**
* Gets whether or not telemetry events are captured when running in CI.

@@ -58,0 +69,0 @@ * @returns Whether or not telemetry events are captured when running in CI.

@@ -11,3 +11,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.getSessionId = exports.isCliTest = exports.isMsftInternal = exports.ciType = exports.isCI = exports.captureCI = exports.sampleRate = exports.deviceDiskFreeSpace = exports.deviceTotalMemory = exports.deviceNumCPUs = exports.deviceLocale = exports.devicePlatform = exports.nodeArchitecture = exports.deviceArchitecture = exports.deviceId = void 0;
exports.getSessionId = exports.isCliTest = exports.isMsftInternal = exports.ciType = exports.isCI = exports.captureCI = exports.deviceDiskFreeSpace = exports.deviceTotalMemory = exports.deviceNumCPUs = exports.deviceLocale = exports.deviceClass = exports.nodePlatform = exports.nodeArchitecture = exports.deviceArchitecture = exports.fullBuildInfo = exports.deviceId = exports.getValueFromRegistry = void 0;
const child_process_1 = require("child_process");

@@ -20,9 +20,11 @@ const os_1 = require("os");

const DeviceIdRegKey = 'MachineId';
const DeviceIdBuildPath = '"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"';
const DeviceIdBuildKey = 'BuildLabEx';
/**
* Gets a telemetry-safe stable device ID.
* @returns A telemetry-safe stable device ID.
* Given a path and a key, retrieves the value from the Registry.
* @returns If the path and key exist, the requested value from the Registry; empty string otherwise.
*/
async function deviceId() {
async function getValueFromRegistry(path, key) {
try {
let regCommand = `${process.env.windir}\\System32\\reg.exe query ${DeviceIdRegPath} /v ${DeviceIdRegKey}`;
let regCommand = `${process.env.windir}\\System32\\reg.exe query ${path} /v ${key}`;
if (deviceArchitecture() === 'x64') {

@@ -33,3 +35,16 @@ // Ensure we query the correct registry

const output = (0, child_process_1.execSync)(regCommand).toString();
const result = output.match(/\{([0-9A-Fa-f-]{36})\}/);
return output;
}
catch (_a) { }
return '';
}
exports.getValueFromRegistry = getValueFromRegistry;
/**
* Gets a telemetry-safe stable device ID.
* @returns A telemetry-safe stable device ID.
*/
async function deviceId() {
try {
const deviceIdValue = await getValueFromRegistry(DeviceIdRegPath, DeviceIdRegKey);
const result = deviceIdValue.match(/\{([0-9A-Fa-f-]{36})\}/);
if (result && result.length > 1) {

@@ -44,2 +59,20 @@ return `s:${result[1]}`;

/**
* Gets the Windows build name, number and architecture.
* @returns A string containing the Windows build name, number and architecture.
* e.g. 19569.1000.amd64fre.rs_prerelease.200214-1419
*/
async function fullBuildInfo() {
try {
const fullBuildValue = await getValueFromRegistry(DeviceIdBuildPath, DeviceIdBuildKey);
// Retrieve the build info
const match = fullBuildValue.match(/BuildLabEx\s+REG_SZ\s+([^\r\n]+)/);
if (match && match.length > 1) {
return match[1];
}
}
catch (_a) { }
return '';
}
exports.fullBuildInfo = fullBuildInfo;
/**
* Gets the device architecture, like x86/x64/arm64.

@@ -66,10 +99,28 @@ * @returns The device architecture.

/**
* Gets the device platform, like darwin/linux/win32.
* Gets the node platform, like darwin/linux/win32.
* @returns The device platform.
*/
function devicePlatform() {
function nodePlatform() {
return (0, os_1.platform)();
}
exports.devicePlatform = devicePlatform;
exports.nodePlatform = nodePlatform;
/**
* Gets the OS name, to be filled in the PartA device.deviceClass field.
* @returns The device class.
*/
function deviceClass() {
const node = nodePlatform();
switch (node) {
case 'darwin':
return 'Mac';
case 'linux':
return 'Linux';
case 'win32':
return 'Windows';
default:
return node;
}
}
exports.deviceClass = deviceClass;
/**
* Gets the device locale.

@@ -119,10 +170,2 @@ * @returns The device locale.

/**
* Gets the telemetry sample rate.
* @returns The telemetry sample rate.
*/
function sampleRate() {
return 100;
}
exports.sampleRate = sampleRate;
/**
* Gets whether or not telemetry events are captured when running in CI.

@@ -129,0 +172,0 @@ * @returns Whether or not telemetry events are captured when running in CI.

@@ -6,3 +6,2 @@ /**

*/
import * as appInsights from 'applicationinsights';
export declare const CodedErrors: {

@@ -73,2 +72,8 @@ Success: number;

}
export interface ErrorStackFrame {
functionName?: string;
filePath?: string;
lineNumber?: number;
columnNumber?: number;
}
/**

@@ -90,2 +95,2 @@ * Tries to parse an error code out of an error message.

*/
export declare function sanitizeErrorStackFrame(frame: appInsights.Contracts.StackFrame): void;
export declare function sanitizeErrorStackFrame(frame: ErrorStackFrame): void;

@@ -167,15 +167,18 @@ "use strict";

function sanitizeErrorStackFrame(frame) {
const parens = frame.method.indexOf('(');
if (parens !== -1) {
// case 1: method === 'methodName (rootOfThePath'
frame.method = frame.method.substr(0, parens).trim();
if (frame.functionName) {
const leftParenthesisIndex = frame.functionName.indexOf('(');
if (leftParenthesisIndex !== -1) {
// case 1: method === 'methodName (rootOfThePath'
frame.functionName = frame.functionName
.substr(0, leftParenthesisIndex)
.trim();
}
else {
// case 2: method === <no_method> or something without '(', fileName is full path
}
}
else {
// case 2: method === <no_method> or something without '(', fileName is full path
}
// anonymize the filename
frame.fileName = sanitizeUtils.getAnonymizedPath(frame.fileName);
frame.assembly = '';
// anonymize the filePath
frame.filePath = sanitizeUtils.getAnonymizedPath(frame.filePath);
}
exports.sanitizeErrorStackFrame = sanitizeErrorStackFrame;
//# sourceMappingURL=errorUtils.js.map

@@ -12,2 +12,2 @@ /**

*/
export declare function getAnonymizedPath(filepath: string, projectRoot?: string): string;
export declare function getAnonymizedPath(filepath: string | undefined, projectRoot?: string): string;

@@ -28,2 +28,5 @@ "use strict";

function getAnonymizedPath(filepath, projectRoot) {
if (filepath === undefined) {
return '[path]';
}
projectRoot = (projectRoot !== null && projectRoot !== void 0 ? projectRoot : process.cwd())

@@ -30,0 +33,0 @@ .replace(/\//g, '\\')

{
"name": "@react-native-windows/telemetry",
"version": "0.0.0-canary.110",
"version": "0.0.0-canary.112",
"license": "MIT",

@@ -22,5 +22,6 @@ "main": "lib-commonjs/index.js",

"@azure/core-auth": "1.5.0",
"@react-native-windows/fs": "0.0.0-canary.58",
"@microsoft/1ds-core-js": "^4.3.0",
"@microsoft/1ds-post-js": "^4.3.0",
"@react-native-windows/fs": "0.0.0-canary.59",
"@xmldom/xmldom": "^0.7.7",
"applicationinsights": "2.9.1",
"ci-info": "^3.2.0",

@@ -33,5 +34,5 @@ "envinfo": "^7.8.1",

"devDependencies": {
"@rnw-scripts/eslint-config": "1.2.29",
"@rnw-scripts/eslint-config": "1.2.30",
"@rnw-scripts/jest-unittest-config": "1.5.11",
"@rnw-scripts/just-task": "2.3.46",
"@rnw-scripts/just-task": "2.3.47",
"@rnw-scripts/ts-config": "2.0.5",

@@ -42,4 +43,4 @@ "@types/envinfo": "^7.8.1",

"@types/semver": "^7.3.3",
"@typescript-eslint/eslint-plugin": "^5.30.5",
"@typescript-eslint/parser": "^5.57.1",
"@typescript-eslint/eslint-plugin": "^7.1.1",
"@typescript-eslint/parser": "^7.1.1",
"babel-jest": "^29.6.3",

@@ -46,0 +47,0 @@ "eslint": "^8.19.0",

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc