@react-native-windows/telemetry 0.0.0-canary.7 → 0.0.0-canary.70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/lib-commonjs/e2etest/telemetry.test.d.ts +28 -0
  2. package/lib-commonjs/e2etest/telemetry.test.js +497 -0
  3. package/lib-commonjs/e2etest/telemetry.test.js.map +1 -0
  4. package/lib-commonjs/index.d.ts +5 -1
  5. package/lib-commonjs/index.js +14 -2
  6. package/lib-commonjs/index.js.map +1 -1
  7. package/lib-commonjs/telemetry.d.ts +75 -17
  8. package/lib-commonjs/telemetry.js +338 -130
  9. package/lib-commonjs/telemetry.js.map +1 -1
  10. package/lib-commonjs/test/basePropUtils.test.js +132 -0
  11. package/lib-commonjs/test/basePropUtils.test.js.map +1 -0
  12. package/lib-commonjs/test/errorUtils.test.d.ts +7 -0
  13. package/lib-commonjs/test/errorUtils.test.js +166 -0
  14. package/lib-commonjs/test/errorUtils.test.js.map +1 -0
  15. package/lib-commonjs/test/projectUtils.test.d.ts +7 -0
  16. package/lib-commonjs/test/projectUtils.test.js +88 -0
  17. package/lib-commonjs/test/projectUtils.test.js.map +1 -0
  18. package/lib-commonjs/test/sanitizeUtils.test.d.ts +7 -0
  19. package/lib-commonjs/test/sanitizeUtils.test.js +98 -0
  20. package/lib-commonjs/test/sanitizeUtils.test.js.map +1 -0
  21. package/lib-commonjs/test/versionUtils.test.d.ts +7 -0
  22. package/lib-commonjs/test/versionUtils.test.js +115 -0
  23. package/lib-commonjs/test/versionUtils.test.js.map +1 -0
  24. package/lib-commonjs/utils/basePropUtils.d.ts +76 -0
  25. package/lib-commonjs/utils/basePropUtils.js +156 -0
  26. package/lib-commonjs/utils/basePropUtils.js.map +1 -0
  27. package/lib-commonjs/utils/errorUtils.d.ts +82 -0
  28. package/lib-commonjs/utils/errorUtils.js +173 -0
  29. package/lib-commonjs/utils/errorUtils.js.map +1 -0
  30. package/lib-commonjs/utils/optionUtils.d.ts +45 -0
  31. package/lib-commonjs/utils/optionUtils.js +96 -0
  32. package/lib-commonjs/utils/optionUtils.js.map +1 -0
  33. package/lib-commonjs/utils/projectUtils.d.ts +50 -0
  34. package/lib-commonjs/utils/projectUtils.js +187 -0
  35. package/lib-commonjs/utils/projectUtils.js.map +1 -0
  36. package/lib-commonjs/utils/sanitizeUtils.d.ts +12 -0
  37. package/lib-commonjs/utils/sanitizeUtils.js +82 -0
  38. package/lib-commonjs/utils/sanitizeUtils.js.map +1 -0
  39. package/lib-commonjs/utils/versionUtils.d.ts +38 -0
  40. package/lib-commonjs/utils/versionUtils.js +156 -0
  41. package/lib-commonjs/utils/versionUtils.js.map +1 -0
  42. package/package.json +37 -21
  43. package/CHANGELOG.json +0 -95
  44. package/CHANGELOG.md +0 -55
  45. package/lib-commonjs/test/sanitize.test.js +0 -189
  46. package/lib-commonjs/test/sanitize.test.js.map +0 -1
  47. /package/lib-commonjs/test/{sanitize.test.d.ts → basePropUtils.test.d.ts} +0 -0
@@ -4,23 +4,81 @@
4
4
  * @format
5
5
  */
6
6
  import * as appInsights from 'applicationinsights';
7
- export declare class Telemetry {
8
- static client?: appInsights.TelemetryClient | undefined;
9
- static disable(): void;
10
- static setup(): void;
11
- static isCI(): boolean;
12
- static shouldDisable: boolean;
7
+ import * as errorUtils from './utils/errorUtils';
8
+ import * as projectUtils from './utils/projectUtils';
9
+ export interface TelemetryOptions {
10
+ setupString: string;
11
+ preserveErrorMessages: boolean;
12
+ populateNpmPackageVersions: boolean;
13
13
  }
14
+ export interface CommandStartInfo {
15
+ commandName: string;
16
+ args: Record<string, any>;
17
+ options: Record<string, any>;
18
+ defaultOptions: Record<string, any>;
19
+ }
20
+ export interface CommandEndInfo {
21
+ resultCode: errorUtils.CodedErrorType;
22
+ }
23
+ interface CommandInfo {
24
+ startTime?: number;
25
+ endTime?: number;
26
+ startInfo?: CommandStartInfo;
27
+ endInfo?: CommandEndInfo;
28
+ }
29
+ export declare const CommandEventName = "RNWCLI.Command";
30
+ export declare const CodedErrorEventName = "RNWCLI.CodedError";
31
+ export declare const EventNamesWeTrack: string[];
32
+ export declare const NpmPackagesWeTrack: string[];
33
+ export declare const NuGetPackagesWeTrack: string[];
14
34
  /**
15
- * Sanitize any paths that appear between quotes (''), brackets ([]), or double quotes ("").
16
- * @param msg the string to sanitize
17
- */
18
- export declare function sanitizeMessage(msg: string): string;
19
- export declare function sanitizeFrame(frame: any): void;
20
- /**
21
- * Remove PII from exceptions' stack traces and messages
22
- * @param envelope the telemetry envelope. Provided by AppInsights.
35
+ * The Telemetry class is responsible for reporting telemetry for RNW CLI.
23
36
  */
24
- export declare function sanitizeEnvelope(envelope: any): boolean;
25
- export declare function isMSFTInternal(): boolean;
26
- export declare function getDiskFreeSpace(drivePath: string | null): number;
37
+ export declare class Telemetry {
38
+ protected static client?: appInsights.TelemetryClient;
39
+ protected static options: TelemetryOptions;
40
+ protected static isTest: boolean;
41
+ protected static commandInfo: CommandInfo;
42
+ protected static versionsProp: Record<string, string>;
43
+ protected static projectProp?: projectUtils.AppProjectInfo | projectUtils.DependencyProjectInfo;
44
+ protected static getDefaultSetupString(): string;
45
+ protected static reset(): void;
46
+ static isEnabled(): boolean;
47
+ static getSessionId(): string;
48
+ /** Sets up the Telemetry static to be used elsewhere. */
49
+ static setup(options?: Partial<TelemetryOptions>): Promise<void>;
50
+ /** Sets up Telemetry.client. */
51
+ private static setupClient;
52
+ /** Sets up any base properties that all telemetry events require. */
53
+ private static setupBaseProperties;
54
+ /** Sets up any telemetry processors. */
55
+ private static setupTelemetryProcessors;
56
+ /**
57
+ * Performs the processing necessary (mostly PII sanitization) for all events.
58
+ * @param envelope The ApplicationInsights event envelope.
59
+ * @param _contextObjects An optional context object.
60
+ * @returns Whether to kee
61
+ */
62
+ private static basicTelemetryProcessor;
63
+ /**
64
+ * Performs the processing necessary (mostly PII sanitization) for error events.
65
+ * @param envelope
66
+ * @param _contextObjects
67
+ * @returns
68
+ */
69
+ private static errorTelemetryProcessor;
70
+ /** Tries to update the version of the named package/tool by calling getValue(). */
71
+ static tryUpdateVersionsProp(name: string, getValue: () => Promise<string | null>, forceRefresh?: boolean): Promise<boolean>;
72
+ /** Populates the versions property of tools we care to track. */
73
+ static populateToolsVersions(refresh?: boolean): Promise<void>;
74
+ /** Populates the versions property of npm packages we care to track. */
75
+ static populateNpmPackageVersions(refresh?: boolean): Promise<void>;
76
+ /** Populates the versions property of nuget packages we care to track. */
77
+ static populateNuGetPackageVersions(projectFile: string, refresh?: boolean): Promise<void>;
78
+ static setProjectInfo(info: projectUtils.AppProjectInfo | projectUtils.DependencyProjectInfo): void;
79
+ static startCommand(info: CommandStartInfo): void;
80
+ static endCommand(info: CommandEndInfo, extraProps?: Record<string, any>): void;
81
+ private static trackCommandEvent;
82
+ static trackException(error: Error, extraProps?: Record<string, any>): void;
83
+ }
84
+ export {};
@@ -4,158 +4,366 @@
4
4
  * Licensed under the MIT License.
5
5
  * @format
6
6
  */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || function (mod) {
24
+ if (mod && mod.__esModule) return mod;
25
+ var result = {};
26
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
27
+ __setModuleDefault(result, mod);
28
+ return result;
29
+ };
7
30
  Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.getDiskFreeSpace = exports.isMSFTInternal = exports.sanitizeEnvelope = exports.sanitizeFrame = exports.sanitizeMessage = exports.Telemetry = void 0;
9
- const path = require("path");
10
- const crypto_1 = require("crypto");
11
- const appInsights = require("applicationinsights");
12
- const child_process_1 = require("child_process");
31
+ exports.Telemetry = exports.NuGetPackagesWeTrack = exports.NpmPackagesWeTrack = exports.EventNamesWeTrack = exports.CodedErrorEventName = exports.CommandEventName = void 0;
32
+ const appInsights = __importStar(require("applicationinsights"));
33
+ const basePropUtils = __importStar(require("./utils/basePropUtils"));
34
+ const versionUtils = __importStar(require("./utils/versionUtils"));
35
+ const errorUtils = __importStar(require("./utils/errorUtils"));
36
+ // This is our key with the AI backend
37
+ const RNWSetupString = '795006ca-cf54-40ee-8bc6-03deb91401c3';
38
+ // Environment variable to override the default setup string
39
+ const ENV_SETUP_OVERRIDE = 'RNW_TELEMETRY_SETUP';
40
+ // Environment variable to override the http proxy (such as http://localhost:8888 for Fiddler debugging)
41
+ const ENV_PROXY_OVERRIDE = 'RNW_TELEMETRY_PROXY';
42
+ exports.CommandEventName = 'RNWCLI.Command';
43
+ exports.CodedErrorEventName = 'RNWCLI.CodedError';
44
+ // These are the event names we're tracking
45
+ exports.EventNamesWeTrack = [
46
+ exports.CommandEventName,
47
+ exports.CodedErrorEventName,
48
+ ];
49
+ // These are NPM packages we care about, in terms of capturing versions used
50
+ // and getting more details about when reporting errors
51
+ exports.NpmPackagesWeTrack = [
52
+ '@react-native-community/cli',
53
+ '@react-native-windows/cli',
54
+ '@react-native-windows/telemetry',
55
+ 'react',
56
+ 'react-native',
57
+ 'react-native-windows',
58
+ 'react-native-windows-init',
59
+ ];
60
+ // These are NPM packages we care about, in terms of capturing versions used
61
+ exports.NuGetPackagesWeTrack = [
62
+ 'Microsoft.UI.Xaml',
63
+ 'Microsoft.Windows.CppWinRT',
64
+ 'Microsoft.WinUI',
65
+ ];
66
+ /**
67
+ * The Telemetry class is responsible for reporting telemetry for RNW CLI.
68
+ */
13
69
  class Telemetry {
14
- static disable() {
70
+ static getDefaultSetupString() {
71
+ var _a;
72
+ // Enable overriding the default setup string via an environment variable
73
+ return (_a = process.env[ENV_SETUP_OVERRIDE]) !== null && _a !== void 0 ? _a : RNWSetupString;
74
+ }
75
+ static reset() {
76
+ // Reset client
15
77
  if (Telemetry.client) {
16
- Telemetry.client.config.disableAppInsights = true;
78
+ Telemetry.client.flush();
79
+ Telemetry.client = undefined;
17
80
  }
18
- Telemetry.shouldDisable = true;
81
+ // Reset local members
82
+ Telemetry.options = {
83
+ setupString: Telemetry.getDefaultSetupString(),
84
+ preserveErrorMessages: false,
85
+ populateNpmPackageVersions: true,
86
+ };
87
+ Telemetry.commandInfo = {};
88
+ Telemetry.versionsProp = {};
89
+ Telemetry.projectProp = undefined;
19
90
  }
20
- static setup() {
21
- if (Telemetry.isCI()) {
22
- this.disable();
23
- return;
24
- }
91
+ static isEnabled() {
92
+ return Telemetry.client !== undefined;
93
+ }
94
+ static getSessionId() {
95
+ return basePropUtils.getSessionId();
96
+ }
97
+ /** Sets up the Telemetry static to be used elsewhere. */
98
+ static async setup(options) {
25
99
  if (Telemetry.client) {
100
+ // Bail since we've already setup
26
101
  return;
27
102
  }
28
- if (!process.env.RNW_CLI_TEST) {
29
- appInsights.Configuration.setInternalLogging(false, false);
30
- }
31
- appInsights.setup('795006ca-cf54-40ee-8bc6-03deb91401c3');
32
- Telemetry.client = appInsights.defaultClient;
33
- if (Telemetry.shouldDisable) {
34
- Telemetry.disable();
103
+ // Bail if we're in CI and not capturing CI
104
+ if (!this.isTest && basePropUtils.isCI() && !basePropUtils.captureCI()) {
105
+ return;
35
106
  }
36
- if (process.env.RNW_CLI_TEST) {
37
- Telemetry.client.commonProperties.isTest = process.env.RNW_CLI_TEST;
107
+ // Save off options for later
108
+ Object.assign(Telemetry.options, options);
109
+ Telemetry.setupClient();
110
+ await Telemetry.setupBaseProperties();
111
+ Telemetry.setupTelemetryProcessors();
112
+ }
113
+ /** Sets up Telemetry.client. */
114
+ static setupClient() {
115
+ var _a;
116
+ appInsights.Configuration.setInternalLogging(false, false);
117
+ Telemetry.client = new appInsights.TelemetryClient(Telemetry.options.setupString);
118
+ // Allow overriding the proxy server via an environment variable
119
+ const proxyServer = process.env[ENV_PROXY_OVERRIDE];
120
+ if (proxyServer) {
121
+ Telemetry.client.config.proxyHttpUrl = proxyServer;
122
+ Telemetry.client.config.proxyHttpsUrl = proxyServer;
38
123
  }
39
- if (!Telemetry.client.commonProperties.sessionId) {
40
- Telemetry.client.commonProperties.sessionId = crypto_1.randomBytes(16).toString('hex');
41
- Telemetry.client.addTelemetryProcessor(sanitizeEnvelope);
124
+ Telemetry.client.config.disableAppInsights = Telemetry.isTest;
125
+ Telemetry.client.config.disableStatsbeat = true;
126
+ // Despite trying to disable the statsbeat, it might still be running: https://github.com/microsoft/ApplicationInsights-node.js/issues/943
127
+ // So we want to disable it, and despite the method's typing, getStatsbeat() _can_ return undefined
128
+ (_a = Telemetry.client.getStatsbeat()) === null || _a === void 0 ? void 0 : _a.enable(false);
129
+ Telemetry.client.channel.setUseDiskRetryCaching(!Telemetry.isTest);
130
+ }
131
+ /** Sets up any base properties that all telemetry events require. */
132
+ static async setupBaseProperties() {
133
+ Telemetry.client.commonProperties.deviceId =
134
+ await basePropUtils.deviceId();
135
+ Telemetry.client.commonProperties.deviceArchitecture =
136
+ basePropUtils.deviceArchitecture();
137
+ Telemetry.client.commonProperties.devicePlatform =
138
+ basePropUtils.devicePlatform();
139
+ Telemetry.client.commonProperties.deviceLocale =
140
+ await basePropUtils.deviceLocale();
141
+ Telemetry.client.commonProperties.deviceNumCPUs = basePropUtils
142
+ .deviceNumCPUs()
143
+ .toString();
144
+ Telemetry.client.commonProperties.deviceTotalMemory = basePropUtils
145
+ .deviceTotalMemory()
146
+ .toString();
147
+ Telemetry.client.commonProperties.deviceDiskFreeSpace = basePropUtils
148
+ .deviceDiskFreeSpace()
149
+ .toString();
150
+ Telemetry.client.commonProperties.ciCaptured = basePropUtils
151
+ .captureCI()
152
+ .toString();
153
+ Telemetry.client.commonProperties.ciType = basePropUtils.ciType();
154
+ Telemetry.client.commonProperties.isMsftInternal = basePropUtils
155
+ .isMsftInternal()
156
+ .toString();
157
+ Telemetry.client.commonProperties.sampleRate = basePropUtils
158
+ .sampleRate()
159
+ .toString();
160
+ Telemetry.client.commonProperties.isTest = Telemetry.isTest.toString();
161
+ Telemetry.client.commonProperties.sessionId = Telemetry.getSessionId();
162
+ Telemetry.client.config.samplingPercentage = basePropUtils.sampleRate();
163
+ await Telemetry.populateToolsVersions();
164
+ if (Telemetry.options.populateNpmPackageVersions) {
165
+ await Telemetry.populateNpmPackageVersions();
42
166
  }
43
167
  }
44
- static isCI() {
45
- return (process.env.AGENT_NAME !== undefined || // Azure DevOps
46
- process.env.CIRCLECI === 'true' || // CircleCI
47
- process.env.TRAVIS === 'true' || // Travis
48
- process.env.CI === 'true' // other CIs
49
- );
168
+ /** Sets up any telemetry processors. */
169
+ static setupTelemetryProcessors() {
170
+ Telemetry.client.addTelemetryProcessor(Telemetry.basicTelemetryProcessor);
171
+ Telemetry.client.addTelemetryProcessor(Telemetry.errorTelemetryProcessor);
50
172
  }
51
- }
52
- exports.Telemetry = Telemetry;
53
- Telemetry.client = undefined;
54
- Telemetry.shouldDisable = false;
55
- function getAnonymizedPath(filepath) {
56
- const projectRoot = process.cwd().toLowerCase();
57
- const knownPathsVars = ['appdata', 'localappdata', 'userprofile'];
58
- if (filepath.toLowerCase().startsWith(projectRoot)) {
59
- const ext = path.extname(filepath);
60
- const rest = filepath.slice(projectRoot.length);
61
- const node_modules = '\\node_modules\\';
62
- // this is in the project dir but not under node_modules
63
- if (rest.toLowerCase().startsWith('\\windows\\')) {
64
- return `[windows]\\???${ext}(${filepath.length})`;
65
- }
66
- else if (rest.toLowerCase().startsWith(node_modules)) {
67
- return 'node_modules' + rest.slice(node_modules.length - 1);
68
- }
69
- else {
70
- return `[project_dir]\\???${ext}(${filepath.length})`;
71
- }
72
- }
73
- else {
74
- for (const knownPath of knownPathsVars) {
75
- if (process.env[knownPath] &&
76
- filepath.toLowerCase().startsWith(process.env[knownPath].toLowerCase())) {
77
- return `[${knownPath}]\\???(${filepath.length})`;
173
+ /**
174
+ * Performs the processing necessary (mostly PII sanitization) for all events.
175
+ * @param envelope The ApplicationInsights event envelope.
176
+ * @param _contextObjects An optional context object.
177
+ * @returns Whether to kee
178
+ */
179
+ static basicTelemetryProcessor(envelope, _contextObjects) {
180
+ var _a;
181
+ delete envelope.tags['ai.cloud.roleInstance'];
182
+ // Filter out "legacy" events from older stable branches
183
+ const properties = (_a = envelope.data.baseData) === null || _a === void 0 ? void 0 : _a.properties;
184
+ if ((properties === null || properties === void 0 ? void 0 : properties.eventName) &&
185
+ exports.EventNamesWeTrack.includes(properties.eventName)) {
186
+ return true;
187
+ }
188
+ return false;
189
+ }
190
+ /**
191
+ * Performs the processing necessary (mostly PII sanitization) for error events.
192
+ * @param envelope
193
+ * @param _contextObjects
194
+ * @returns
195
+ */
196
+ static errorTelemetryProcessor(envelope, _contextObjects) {
197
+ if (envelope.data.baseType === 'ExceptionData') {
198
+ const data = envelope.data.baseData;
199
+ if (data === null || data === void 0 ? void 0 : data.exceptions) {
200
+ for (const exception of data.exceptions) {
201
+ for (const frame of exception.parsedStack) {
202
+ errorUtils.sanitizeErrorStackFrame(frame);
203
+ }
204
+ // Exception message must never be blank, or AI will reject it
205
+ exception.message = exception.message || '[None]';
206
+ // CodedError has non-PII information in its 'type' member, plus optionally some more info in its 'data'.
207
+ // The message may contain PII information. This can be sanitized, but for now delete it.
208
+ // Note that the type of data.exceptions[0] is always going to be ExceptionDetails. It is not the original thrown exception.
209
+ // https://github.com/microsoft/ApplicationInsights-node.js/issues/707
210
+ if (Telemetry.options.preserveErrorMessages) {
211
+ exception.message = errorUtils.sanitizeErrorMessage(exception.message);
212
+ }
213
+ else {
214
+ exception.message = '[Removed]';
215
+ }
216
+ }
78
217
  }
79
218
  }
219
+ return true;
80
220
  }
81
- return '[path]';
82
- }
83
- /**
84
- * Sanitize any paths that appear between quotes (''), brackets ([]), or double quotes ("").
85
- * @param msg the string to sanitize
86
- */
87
- function sanitizeMessage(msg) {
88
- const parts = msg.split(/['[\]"]/g);
89
- const clean = [];
90
- const pathRegEx = /[A-Za-z]:\\([^<>:;,?"*\t\r\n|/\\]+\\)+([^<>:;,?"*\t\r\n|/]+)/gi;
91
- for (const part of parts) {
92
- if (pathRegEx.test(part)) {
93
- pathRegEx.lastIndex = -1;
94
- let matches;
95
- let noPath = '';
96
- let last = 0;
97
- while ((matches = pathRegEx.exec(part))) {
98
- noPath +=
99
- part.substr(last, matches.index - last) +
100
- getAnonymizedPath(matches[0]);
101
- last = matches.index + matches[0].length;
221
+ /** Tries to update the version of the named package/tool by calling getValue(). */
222
+ static async tryUpdateVersionsProp(name, getValue, forceRefresh) {
223
+ if (!Telemetry.client) {
224
+ return true;
225
+ }
226
+ if (forceRefresh === true || !Telemetry.versionsProp[name]) {
227
+ const value = await getValue();
228
+ if (value) {
229
+ Telemetry.versionsProp[name] = value;
230
+ return true;
102
231
  }
103
- clean.push(noPath);
104
232
  }
105
- else if (part !== '') {
106
- clean.push(part);
233
+ return false;
234
+ }
235
+ /** Populates the versions property of tools we care to track. */
236
+ static async populateToolsVersions(refresh) {
237
+ await Telemetry.tryUpdateVersionsProp('node', versionUtils.getNodeVersion, refresh);
238
+ await Telemetry.tryUpdateVersionsProp('npm', versionUtils.getNpmVersion, refresh);
239
+ await Telemetry.tryUpdateVersionsProp('yarn', versionUtils.getYarnVersion, refresh);
240
+ await Telemetry.tryUpdateVersionsProp('VisualStudio', versionUtils.getVisualStudioVersion, refresh);
241
+ }
242
+ /** Populates the versions property of npm packages we care to track. */
243
+ static async populateNpmPackageVersions(refresh) {
244
+ for (const npmPackage of exports.NpmPackagesWeTrack) {
245
+ await Telemetry.tryUpdateVersionsProp(npmPackage, async () => await versionUtils.getVersionOfNpmPackage(npmPackage), refresh);
107
246
  }
108
247
  }
109
- return clean.join(' ').trim();
110
- }
111
- exports.sanitizeMessage = sanitizeMessage;
112
- function sanitizeFrame(frame) {
113
- const parens = frame.method.indexOf('(');
114
- if (parens !== -1) {
115
- // case 1: method === 'methodName (rootOfThePath'
116
- frame.method = frame.method.substr(0, parens).trim();
117
- }
118
- else {
119
- // case 2: method === <no_method> or something without '(', fileName is full path
120
- }
121
- // preserve only the last_directory/filename
122
- frame.fileName = path.join(path.basename(path.dirname(frame.fileName)), path.basename(frame.fileName));
123
- frame.assembly = '';
124
- }
125
- exports.sanitizeFrame = sanitizeFrame;
126
- /**
127
- * Remove PII from exceptions' stack traces and messages
128
- * @param envelope the telemetry envelope. Provided by AppInsights.
129
- */
130
- function sanitizeEnvelope(envelope /*context: any*/) {
131
- if (envelope.data.baseType === 'ExceptionData') {
132
- const data = envelope.data.baseData;
133
- for (const exception of data.exceptions || []) {
134
- for (const frame of exception.parsedStack) {
135
- sanitizeFrame(frame);
248
+ /** Populates the versions property of nuget packages we care to track. */
249
+ static async populateNuGetPackageVersions(projectFile, refresh) {
250
+ const nugetVersions = await versionUtils.getVersionsOfNuGetPackages(projectFile, exports.NuGetPackagesWeTrack);
251
+ for (const nugetPackage of exports.NuGetPackagesWeTrack) {
252
+ await Telemetry.tryUpdateVersionsProp(nugetPackage, async () => nugetVersions[nugetPackage], refresh);
253
+ }
254
+ }
255
+ static setProjectInfo(info) {
256
+ if (!Telemetry.client) {
257
+ return;
258
+ }
259
+ Telemetry.projectProp = info;
260
+ }
261
+ static startCommand(info) {
262
+ if (!Telemetry.client) {
263
+ return;
264
+ }
265
+ if (Telemetry.commandInfo.startInfo) {
266
+ return;
267
+ }
268
+ Telemetry.commandInfo.startTime = Date.now();
269
+ Telemetry.commandInfo.startInfo = info;
270
+ // Set common command props
271
+ Telemetry.client.commonProperties.commandName = info.commandName;
272
+ }
273
+ static endCommand(info, extraProps) {
274
+ if (!Telemetry.client) {
275
+ return;
276
+ }
277
+ if (!Telemetry.commandInfo.startInfo) {
278
+ return;
279
+ }
280
+ Telemetry.commandInfo.endTime = Date.now();
281
+ Telemetry.commandInfo.endInfo = info;
282
+ Telemetry.trackCommandEvent(extraProps);
283
+ }
284
+ static trackCommandEvent(extraProps) {
285
+ var _a, _b, _c, _d;
286
+ const props = {
287
+ eventName: exports.CommandEventName,
288
+ };
289
+ // Set command props
290
+ props.command = {
291
+ options: (_a = Telemetry.commandInfo.startInfo) === null || _a === void 0 ? void 0 : _a.options,
292
+ defaultOptions: (_b = Telemetry.commandInfo.startInfo) === null || _b === void 0 ? void 0 : _b.defaultOptions,
293
+ args: (_c = Telemetry.commandInfo.startInfo) === null || _c === void 0 ? void 0 : _c.args,
294
+ durationInSecs: (Telemetry.commandInfo.endTime - Telemetry.commandInfo.startTime) /
295
+ 1000,
296
+ resultCode: (_d = Telemetry.commandInfo.endInfo) === null || _d === void 0 ? void 0 : _d.resultCode,
297
+ };
298
+ // Set remaining common props
299
+ props.project = Telemetry.projectProp;
300
+ props.versions = Telemetry.versionsProp;
301
+ // Set extra props
302
+ props.extraProps = {};
303
+ Object.assign(props.extraProps, extraProps);
304
+ // Fire event
305
+ Telemetry.client.trackEvent({ name: props.eventName, properties: props });
306
+ Telemetry.client.flush();
307
+ }
308
+ static trackException(error, extraProps) {
309
+ var _a, _b;
310
+ if (!Telemetry.client) {
311
+ return;
312
+ }
313
+ const props = {
314
+ eventName: exports.CodedErrorEventName,
315
+ };
316
+ // Save off CodedError info
317
+ const codedError = error instanceof errorUtils.CodedError
318
+ ? error
319
+ : null;
320
+ props.codedError = {
321
+ type: (_a = codedError === null || codedError === void 0 ? void 0 : codedError.type) !== null && _a !== void 0 ? _a : 'Unknown',
322
+ data: (_b = codedError === null || codedError === void 0 ? void 0 : codedError.data) !== null && _b !== void 0 ? _b : {},
323
+ };
324
+ // Copy msBuildErrorMessages into the codedError.data object
325
+ if (error.msBuildErrorMessages) {
326
+ // Always grab MSBuild error codes if possible
327
+ props.codedError.data.msBuildErrors = error.msBuildErrorMessages
328
+ .map(errorUtils.tryGetErrorCode)
329
+ .filter((msg) => msg);
330
+ // Grab sanitized MSBuild error messages if we're preserving them
331
+ if (Telemetry.options.preserveErrorMessages) {
332
+ props.codedError.data.msBuildErrorMessages = error.msBuildErrorMessages
333
+ .map(errorUtils.sanitizeErrorMessage)
334
+ .filter((msg) => msg);
136
335
  }
137
- exception.message = sanitizeMessage(exception.message);
138
336
  }
337
+ // Copy miscellaneous system error fields into the codedError.data object
338
+ const syscallExceptionFieldsToCopy = ['errno', 'syscall', 'code'];
339
+ for (const f of syscallExceptionFieldsToCopy) {
340
+ if (error[f]) {
341
+ props.codedError.data[f] = error[f];
342
+ }
343
+ }
344
+ // Set remaining common props
345
+ props.project = Telemetry.projectProp;
346
+ props.versions = Telemetry.versionsProp;
347
+ // Set extra props
348
+ props.extraProps = {};
349
+ Object.assign(props.extraProps, extraProps);
350
+ // Fire event
351
+ Telemetry.client.trackException({
352
+ exception: error,
353
+ properties: props,
354
+ });
355
+ Telemetry.client.flush();
139
356
  }
140
- delete envelope.tags['ai.cloud.roleInstance'];
141
- return true;
142
- }
143
- exports.sanitizeEnvelope = sanitizeEnvelope;
144
- function isMSFTInternal() {
145
- return (process.env.USERDNSDOMAIN !== undefined &&
146
- process.env.USERDNSDOMAIN.toLowerCase().endsWith('.microsoft.com'));
147
357
  }
148
- exports.isMSFTInternal = isMSFTInternal;
149
- function getDiskFreeSpace(drivePath) {
150
- const out = child_process_1.execSync(`dir /-C ${drivePath}`)
151
- .toString()
152
- .split('\r\n');
153
- const line = out[out.length - 2];
154
- const result = line.match(/(\d+) [^\d]+(\d+) /);
155
- if (result && result.length > 2) {
156
- return Number(result[2]);
157
- }
158
- return -1;
159
- }
160
- exports.getDiskFreeSpace = getDiskFreeSpace;
358
+ exports.Telemetry = Telemetry;
359
+ Telemetry.client = undefined;
360
+ Telemetry.options = {
361
+ setupString: Telemetry.getDefaultSetupString(),
362
+ preserveErrorMessages: false,
363
+ populateNpmPackageVersions: true,
364
+ };
365
+ Telemetry.isTest = basePropUtils.isCliTest();
366
+ Telemetry.commandInfo = {};
367
+ Telemetry.versionsProp = {};
368
+ Telemetry.projectProp = undefined;
161
369
  //# sourceMappingURL=telemetry.js.map