Fix extensions to swallow exceptions when sending telemetry (#5600)

* Fix extensions to swallow exceptions when sending telemetry

* Remove reference to GDPR

* Clean up now-unused code
This commit is contained in:
Charles Gagnon
2019-05-23 16:24:55 -07:00
committed by GitHub
parent db5a0a892a
commit 6d9c95720d
4 changed files with 33 additions and 143 deletions

View File

@@ -39,7 +39,7 @@ export function backEscapeDoubleQuotes(value: string): string {
} }
/** /**
* Map an error message into a GDPR-Compliant short name for the type of error. * Map an error message into a friendly short name for the type of error.
* @param msg The error message to map * @param msg The error message to map
*/ */
export function getTelemetryErrorType(msg: string): string { export function getTelemetryErrorType(msg: string): string {

View File

@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as path from 'path'; import * as path from 'path';
import * as crypto from 'crypto';
import * as os from 'os'; import * as os from 'os';
const baseConfig = require('./config.json'); const baseConfig = require('./config.json');
@@ -48,53 +47,6 @@ export function getPackageInfo(packageJson: any): IPackageInfo {
} }
} }
export function generateUserId(): Promise<string> {
return new Promise<string>(resolve => {
try {
let interfaces = os.networkInterfaces();
let mac;
for (let key of Object.keys(interfaces)) {
let item = interfaces[key][0];
if (!item.internal) {
mac = item.mac;
break;
}
}
if (mac) {
resolve(crypto.createHash('sha256').update(mac + os.homedir(), 'utf8').digest('hex'));
} else {
resolve(generateGuid());
}
} catch (err) {
resolve(generateGuid()); // fallback
}
});
}
export function generateGuid(): string {
let hexValues: string[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];
// c.f. rfc4122 (UUID version 4 = xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx)
let oct: string = '';
let tmp: number;
/* tslint:disable:no-bitwise */
for (let a: number = 0; a < 4; a++) {
tmp = (4294967296 * Math.random()) | 0;
oct += hexValues[tmp & 0xF] +
hexValues[tmp >> 4 & 0xF] +
hexValues[tmp >> 8 & 0xF] +
hexValues[tmp >> 12 & 0xF] +
hexValues[tmp >> 16 & 0xF] +
hexValues[tmp >> 20 & 0xF] +
hexValues[tmp >> 24 & 0xF] +
hexValues[tmp >> 28 & 0xF];
}
// 'Set the two most significant bits (bits 6 and 7) of the clock_seq_hi_and_reserved to zero and one, respectively'
let clockSequenceHi: string = hexValues[8 + (Math.random() * 4) | 0];
return oct.substr(0, 8) + '-' + oct.substr(9, 4) + '-4' + oct.substr(13, 3) + '-' + clockSequenceHi + oct.substr(16, 3) + '-' + oct.substr(19, 12);
/* tslint:enable:no-bitwise */
}
export function verifyPlatform(): Thenable<boolean> { export function verifyPlatform(): Thenable<boolean> {
if (os.platform() === 'darwin' && parseFloat(os.release()) < 16) { if (os.platform() === 'darwin' && parseFloat(os.release()) < 16) {
return Promise.resolve(false); return Promise.resolve(false);

View File

@@ -5,13 +5,11 @@
import { ErrorAction, CloseAction } from 'vscode-languageclient'; import { ErrorAction, CloseAction } from 'vscode-languageclient';
import TelemetryReporter from 'vscode-extension-telemetry'; import TelemetryReporter from 'vscode-extension-telemetry';
import { PlatformInformation } from 'service-downloader/out/platform';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
import * as constants from '../constants'; import * as constants from '../constants';
import * as serviceUtils from './serviceUtils';
import { IMessage, ITelemetryEventProperties, ITelemetryEventMeasures } from './contracts'; import { IMessage, ITelemetryEventProperties, ITelemetryEventMeasures } from './contracts';
@@ -90,39 +88,8 @@ export function FilterErrorPath(line: string): string {
export class Telemetry { export class Telemetry {
private static reporter: TelemetryReporter; private static reporter: TelemetryReporter;
private static userId: string;
private static platformInformation: PlatformInformation;
private static disabled: boolean; private static disabled: boolean;
// Get the unique ID for the current user of the extension
public static getUserId(): Promise<string> {
return new Promise<string>(resolve => {
// Generate the user id if it has not been created already
if (typeof this.userId === 'undefined') {
let id = serviceUtils.generateUserId();
id.then(newId => {
this.userId = newId;
resolve(this.userId);
});
} else {
resolve(this.userId);
}
});
}
public static getPlatformInformation(): Promise<PlatformInformation> {
if (this.platformInformation) {
return Promise.resolve(this.platformInformation);
} else {
return new Promise<PlatformInformation>(resolve => {
PlatformInformation.getCurrent().then(info => {
this.platformInformation = info;
resolve(this.platformInformation);
});
});
}
}
/** /**
* Disable telemetry reporting * Disable telemetry reporting
*/ */
@@ -149,8 +116,7 @@ export class Telemetry {
* Send a telemetry event for an exception * Send a telemetry event for an exception
*/ */
public static sendTelemetryEventForException( public static sendTelemetryEventForException(
err: any, methodName: string, extensionConfigName: string): void { err: any, methodName: string): void {
try {
let stackArray: string[]; let stackArray: string[];
let firstLine: string = ''; let firstLine: string = '';
if (err !== undefined && err.stack !== undefined) { if (err !== undefined && err.stack !== undefined) {
@@ -163,11 +129,6 @@ export class Telemetry {
// Only adding the method name and the fist line of the stack trace. We don't add the error message because it might have PII // Only adding the method name and the fist line of the stack trace. We don't add the error message because it might have PII
this.sendTelemetryEvent('Exception', { methodName: methodName, errorLine: firstLine }); this.sendTelemetryEvent('Exception', { methodName: methodName, errorLine: firstLine });
// Utils.logDebug('Unhandled Exception occurred. error: ' + err + ' method: ' + methodName, extensionConfigName);
} catch (telemetryErr) {
// If sending telemetry event fails ignore it so it won't break the extension
// Utils.logDebug('Failed to send telemetry event. error: ' + telemetryErr, extensionConfigName);
}
} }
/** /**
@@ -191,14 +152,12 @@ export class Telemetry {
properties = {}; properties = {};
} }
// Augment the properties structure with additional common properties before sending try {
Promise.all([this.getUserId(), this.getPlatformInformation()]).then(() => {
properties['userId'] = this.userId;
properties['distribution'] = (this.platformInformation && this.platformInformation.distribution) ?
`${this.platformInformation.distribution.name}, ${this.platformInformation.distribution.version}` : '';
this.reporter.sendTelemetryEvent(eventName, properties, measures); this.reporter.sendTelemetryEvent(eventName, properties, measures);
}); } catch (telemetryErr) {
// If sending telemetry event fails ignore it so it won't break the extension
console.error('Failed to send telemetry event. error: ' + telemetryErr);
}
} }
} }

View File

@@ -5,7 +5,6 @@
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import TelemetryReporter from 'vscode-extension-telemetry'; import TelemetryReporter from 'vscode-extension-telemetry';
import { PlatformInformation } from 'service-downloader/out/platform';
import { ErrorAction, ErrorHandler, Message, CloseAction } from 'vscode-languageclient'; import { ErrorAction, ErrorHandler, Message, CloseAction } from 'vscode-languageclient';
import * as Utils from './utils'; import * as Utils from './utils';
@@ -39,22 +38,8 @@ export function FilterErrorPath(line: string): string {
export class Telemetry { export class Telemetry {
private static reporter: TelemetryReporter; private static reporter: TelemetryReporter;
private static platformInformation: PlatformInformation;
private static disabled: boolean; private static disabled: boolean;
public static getPlatformInformation(): Promise<PlatformInformation> {
if (this.platformInformation) {
return Promise.resolve(this.platformInformation);
} else {
return new Promise<PlatformInformation>(resolve => {
PlatformInformation.getCurrent().then(info => {
this.platformInformation = info;
resolve(this.platformInformation);
});
});
}
}
/** /**
* Disable telemetry reporting * Disable telemetry reporting
*/ */
@@ -83,7 +68,6 @@ export class Telemetry {
*/ */
public static sendTelemetryEventForException( public static sendTelemetryEventForException(
err: any, methodName: string, extensionConfigName: string): void { err: any, methodName: string, extensionConfigName: string): void {
try {
let stackArray: string[]; let stackArray: string[];
let firstLine: string = ''; let firstLine: string = '';
if (err !== undefined && err.stack !== undefined) { if (err !== undefined && err.stack !== undefined) {
@@ -96,11 +80,6 @@ export class Telemetry {
// Only adding the method name and the fist line of the stack trace. We don't add the error message because it might have PII // Only adding the method name and the fist line of the stack trace. We don't add the error message because it might have PII
this.sendTelemetryEvent('Exception', { methodName: methodName, errorLine: firstLine }); this.sendTelemetryEvent('Exception', { methodName: methodName, errorLine: firstLine });
// Utils.logDebug('Unhandled Exception occurred. error: ' + err + ' method: ' + methodName, extensionConfigName);
} catch (telemetryErr) {
// If sending telemetry event fails ignore it so it won't break the extension
// Utils.logDebug('Failed to send telemetry event. error: ' + telemetryErr, extensionConfigName);
}
} }
/** /**
@@ -124,13 +103,13 @@ export class Telemetry {
properties = {}; properties = {};
} }
// Augment the properties structure with additional common properties before sending try {
Promise.all([this.getPlatformInformation()]).then(() => {
properties['distribution'] = (this.platformInformation && this.platformInformation.distribution) ?
`${this.platformInformation.distribution.name}, ${this.platformInformation.distribution.version}` : '';
this.reporter.sendTelemetryEvent(eventName, properties, measures); this.reporter.sendTelemetryEvent(eventName, properties, measures);
}); } catch (telemetryErr) {
// If sending telemetry event fails ignore it so it won't break the extension
console.error('Failed to send telemetry event. error: ' + telemetryErr);
}
} }
} }