Skip to content
This repository was archived by the owner on Oct 2, 2021. It is now read-only.
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
41 changes: 30 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 21 additions & 9 deletions src/telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ import { fillErrorDetails } from './utils';
"IExecutionResultTelemetryProperties" : {
"successful" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" },
"exceptionType" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" },
"exceptionMessage" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
"!exceptionMessage" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
"exceptionName" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
"exceptionStack" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
"exceptionId" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
"!exceptionStack" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
"!exceptionId" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
"startTime" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" },
"timeTakenInMilliseconds" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
}
*/
export type ExceptionType = 'uncaughtException' | 'unhandledRejection' | 'firstChance';
export interface IExecutionResultTelemetryProperties {
export interface IExecutionResultTelemetryProperties {
// There is an issue on some clients and reportEvent only currently accept strings properties,
// hence all the following properties must be strings.
successful?: 'true' | 'false';
Expand All @@ -32,6 +32,9 @@ export interface IExecutionResultTelemetryProperties {
timeTakenInMilliseconds?: string;
}

// telemetry keys to prefix with `!` over DAP for classification in VS Code.
const prefixTelemetryKeys: ReadonlyArray<keyof IExecutionResultTelemetryProperties> = ['exceptionStack', 'exceptionMessage', 'exceptionId'];

export interface ITelemetryReporter {
reportEvent(name: string, data?: any): void;
setupEventHandler(_sendEvent: (event: DebugProtocol.Event) => void): void;
Expand All @@ -42,11 +45,20 @@ export class TelemetryReporter implements ITelemetryReporter {
private _globalTelemetryProperties: any = {};

reportEvent(name: string, data?: any): void {
if (this._sendEvent) {
const combinedData = Object.assign({}, this._globalTelemetryProperties, data);
const event = new OutputEvent(name, 'telemetry', combinedData);
this._sendEvent(event);
if (!this._sendEvent) {
return;
}

const combinedData = Object.assign({}, this._globalTelemetryProperties, data);
for (const key of prefixTelemetryKeys) {
if (combinedData.hasOwnProperty(key)) {
combinedData[`!${key}`] = combinedData[key];
delete combinedData[key];
}
}

const event = new OutputEvent(name, 'telemetry', combinedData);
this._sendEvent(event);
}

setupEventHandler(_sendEvent: (event: DebugProtocol.Event) => void): void {
Expand Down Expand Up @@ -247,4 +259,4 @@ export class TelemetryPropertyCollector implements ITelemetryPropertyCollector {
}
}

export const telemetry = new AsyncGlobalPropertiesTelemetryReporter(new TelemetryReporter());
export const telemetry = new AsyncGlobalPropertiesTelemetryReporter(new TelemetryReporter());
31 changes: 31 additions & 0 deletions test/telemetry.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/

import * as assert from 'assert';
import { TelemetryReporter, IExecutionResultTelemetryProperties } from '../src/telemetry';

suite('telemetry', () => {
test('remaps exception keys', callback => {
const reporter = new TelemetryReporter();
reporter.setupEventHandler(event => {
callback();

assert.deepStrictEqual(event, {
successful: 'false',
exceptionType: 'uncaughtException',
'!exceptionMessage': 'some error',
exceptionName: 'SomeError',
'!exceptionStack': 'foo.js:123',
});
});

reporter.reportEvent('error', {
successful: 'false',
exceptionType: 'uncaughtException',
exceptionMessage: 'some error',
exceptionName: 'SomeError',
exceptionStack: 'foo.js:123',
} as IExecutionResultTelemetryProperties);
});
});