Merge from vscode 8e0f348413f4f616c23a88ae30030efa85811973 (#6381)

* Merge from vscode 8e0f348413f4f616c23a88ae30030efa85811973

* disable strict null check
This commit is contained in:
Anthony Dresser
2019-07-15 22:35:46 -07:00
committed by GitHub
parent f720ec642f
commit 0b7e7ddbf9
2406 changed files with 59140 additions and 35464 deletions

View File

@@ -5,25 +5,20 @@
import { binarySearch } from 'vs/base/common/arrays';
import * as Errors from 'vs/base/common/errors';
import { dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { safeStringify } from 'vs/base/common/objects';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
/* __GDPR__FRAGMENT__
"ErrorEvent" : {
"stack": { "classification": "CustomerContent", "purpose": "PerformanceAndHealth" },
"message" : { "classification": "CustomerContent", "purpose": "PerformanceAndHealth" },
"filename" : { "classification": "CustomerContent", "purpose": "PerformanceAndHealth" },
"callstack": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
"msg" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
"file" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
"line": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth", "isMeasurement": true },
"column": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth", "isMeasurement": true },
"uncaught_error_name": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
"uncaught_error_msg": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
"count": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth", "isMeasurement": true }
}
*/
type ErrorEventFragment = {
callstack: { classification: 'CallstackOrException', purpose: 'PerformanceAndHealth' };
msg?: { classification: 'CallstackOrException', purpose: 'PerformanceAndHealth' };
file?: { classification: 'CallstackOrException', purpose: 'PerformanceAndHealth' };
line?: { classification: 'CallstackOrException', purpose: 'PerformanceAndHealth', isMeasurement: true };
column?: { classification: 'CallstackOrException', purpose: 'PerformanceAndHealth', isMeasurement: true };
uncaught_error_name?: { classification: 'CallstackOrException', purpose: 'PerformanceAndHealth' };
uncaught_error_msg?: { classification: 'CallstackOrException', purpose: 'PerformanceAndHealth' };
count?: { classification: 'CallstackOrException', purpose: 'PerformanceAndHealth', isMeasurement: true };
};
export interface ErrorEvent {
callstack: string;
msg?: string;
@@ -54,7 +49,7 @@ export default abstract class BaseErrorTelemetry {
private _flushDelay: number;
private _flushHandle: any = -1;
private _buffer: ErrorEvent[] = [];
protected _disposables: IDisposable[] = [];
protected readonly _disposables = new DisposableStore();
constructor(telemetryService: ITelemetryService, flushDelay = BaseErrorTelemetry.ERROR_FLUSH_TIMEOUT) {
this._telemetryService = telemetryService;
@@ -62,7 +57,7 @@ export default abstract class BaseErrorTelemetry {
// (1) check for unexpected but handled errors
const unbind = Errors.errorHandler.addListener((err) => this._onErrorEvent(err));
this._disposables.push(toDisposable(unbind));
this._disposables.add(toDisposable(unbind));
// (2) install implementation-specific error listeners
this.installErrorListeners();
@@ -71,7 +66,7 @@ export default abstract class BaseErrorTelemetry {
dispose() {
clearTimeout(this._flushHandle);
this._flushBuffer();
this._disposables = dispose(this._disposables);
this._disposables.dispose();
}
protected installErrorListeners(): void {
@@ -124,13 +119,8 @@ export default abstract class BaseErrorTelemetry {
private _flushBuffer(): void {
for (let error of this._buffer) {
/* __GDPR__
"UnhandledError" : {
"${include}": [ "${ErrorEvent}" ]
}
*/
// {{SQL CARBON EDIT}}
// this._telemetryService.publicLog('UnhandledError', error, true);
type UnhandledErrorClassification = {} & ErrorEventFragment;
// this._telemetryService.publicLog2<ErrorEvent, UnhandledErrorClassification>('UnhandledError', error, true); {{SQL CARBON EDIT}} comment out log
}
this._buffer.length = 0;
}

View File

@@ -0,0 +1,26 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export interface IPropertyData {
classification: 'SystemMetaData' | 'CallstackOrException' | 'CustomerContent' | 'PublicNonPersonalData';
purpose: 'PerformanceAndHealth' | 'FeatureInsight' | 'BusinessInsight';
endpoint?: string;
isMeasurement?: boolean;
}
export interface IGDPRProperty {
readonly [name: string]: IPropertyData | undefined | IGDPRProperty;
}
export type ClassifiedEvent<T extends IGDPRProperty> = {
[k in keyof T]: any
};
export type StrictPropertyChecker<TEvent, TClassifiedEvent, TError> = keyof TEvent extends keyof TClassifiedEvent ? keyof TClassifiedEvent extends keyof TEvent ? TEvent : TError : TError;
export type StrictPropertyCheckError = 'Type of classified event does not match event properties';
export type StrictPropertyCheck<T extends IGDPRProperty, E> = StrictPropertyChecker<E, ClassifiedEvent<T>, StrictPropertyCheckError>;
export type GDPRClassification<T> = { [_ in keyof T]: IPropertyData | IGDPRProperty | undefined };

View File

@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';
export const ITelemetryService = createDecorator<ITelemetryService>('telemetryService');
@@ -29,9 +30,17 @@ export interface ITelemetryService {
*/
publicLog(eventName: string, data?: ITelemetryData, anonymizeFilePaths?: boolean): Promise<void>;
publicLog2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data?: StrictPropertyCheck<T, E>, anonymizeFilePaths?: boolean): Promise<void>;
setEnabled(value: boolean): void;
getTelemetryInfo(): Promise<ITelemetryInfo>;
isOptedIn: boolean;
}
// Keys
export const instanceStorageKey = 'telemetry.instanceId';
export const currentSessionDateStorageKey = 'telemetry.currentSessionDate';
export const firstSessionDateStorageKey = 'telemetry.firstSessionDate';
export const lastSessionDateStorageKey = 'telemetry.lastSessionDate';

View File

@@ -13,11 +13,13 @@ import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/co
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { cloneAndChange, mixin } from 'vs/base/common/objects';
import { Registry } from 'vs/platform/registry/common/platform';
import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';
export interface ITelemetryServiceConfig {
appender: ITelemetryAppender;
commonProperties?: Promise<{ [name: string]: any }>;
piiPaths?: string[];
trueMachineId?: string;
}
export class TelemetryService implements ITelemetryService {
@@ -56,12 +58,13 @@ export class TelemetryService implements ITelemetryService {
if (this._configurationService) {
this._updateUserOptIn();
this._configurationService.onDidChangeConfiguration(this._updateUserOptIn, this, this._disposables);
/* __GDPR__
"optInStatus" : {
"optIn" : { "classification": "SystemMetaData", "purpose": "BusinessInsight", "isMeasurement": true }
}
*/
this.publicLog('optInStatus', { optIn: this._userOptIn });
type OptInClassification = {
optIn: { classification: 'SystemMetaData', purpose: 'BusinessInsight', isMeasurement: true };
};
type OptInEvent = {
optIn: boolean;
};
this.publicLog2<OptInEvent, OptInClassification>('optInStatus', { optIn: this._userOptIn });
this._commonProperties.then(values => {
const isHashedId = /^[a-f0-9]+$/i.test(values['common.machineId']);
@@ -72,6 +75,15 @@ export class TelemetryService implements ITelemetryService {
}
*/
this.publicLog('machineIdFallback', { usingFallbackGuid: !isHashedId });
if (config.trueMachineId) {
/* __GDPR__
"machineIdDisambiguation" : {
"correctedMachineId" : { "endPoint": "MacAddressHash", "classification": "EndUserPseudonymizedInformation", "purpose": "FeatureInsight" }
}
*/
this.publicLog('machineIdDisambiguation', { correctedMachineId: config.trueMachineId });
}
});
}
}
@@ -131,6 +143,10 @@ export class TelemetryService implements ITelemetryService {
});
}
publicLog2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data?: StrictPropertyCheck<T, E>, anonymizeFilePaths?: boolean): Promise<any> {
return this.publicLog(eventName, data as ITelemetryData, anonymizeFilePaths);
}
private _cleanupInfo(stack: string, anonymizeFilePaths?: boolean): string {
let updatedStack = stack;

View File

@@ -8,12 +8,16 @@ import { IConfigurationService, ConfigurationTarget, ConfigurationTargetToString
import { IKeybindingService, KeybindingSource } from 'vs/platform/keybinding/common/keybinding';
import { ITelemetryService, ITelemetryInfo, ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
import { ILogService } from 'vs/platform/log/common/log';
import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';
export const NullTelemetryService = new class implements ITelemetryService {
_serviceBrand: undefined;
publicLog(eventName: string, data?: ITelemetryData) {
return Promise.resolve(undefined);
}
publicLog2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data?: StrictPropertyCheck<T, E>) {
return this.publicLog(eventName, data as ITelemetryData);
}
setEnabled() { }
isOptedIn: true;
getTelemetryInfo(): Promise<ITelemetryInfo> {
@@ -50,7 +54,7 @@ export class LogAppender implements ITelemetryAppender {
}
log(eventName: string, data: any): void {
const strippedData = {};
const strippedData: { [key: string]: any } = {};
Object.keys(data).forEach(key => {
if (!this.commonPropertiesRegex.test(key)) {
strippedData[key] = data[key];
@@ -175,12 +179,12 @@ const configurationValueWhitelist = [
'terminal.integrated.fontFamily',
'window.openFilesInNewWindow',
'window.restoreWindows',
'window.nativeFullScreen',
'window.zoomLevel',
'workbench.editor.enablePreview',
'workbench.editor.enablePreviewFromQuickOpen',
'workbench.editor.showTabs',
'workbench.editor.highlightModifiedTabs',
'workbench.editor.swipeToNavigate',
'workbench.sideBar.location',
'workbench.startupEditor',
'workbench.statusBar.visible',
@@ -190,23 +194,27 @@ const configurationValueWhitelist = [
export function configurationTelemetry(telemetryService: ITelemetryService, configurationService: IConfigurationService): IDisposable {
return configurationService.onDidChangeConfiguration(event => {
if (event.source !== ConfigurationTarget.DEFAULT) {
/* __GDPR__
"updateConfiguration" : {
"configurationSource" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"configurationKeys": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
telemetryService.publicLog('updateConfiguration', {
type UpdateConfigurationClassification = {
configurationSource: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
configurationKeys: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
};
type UpdateConfigurationEvent = {
configurationSource: string;
configurationKeys: string[];
};
telemetryService.publicLog2<UpdateConfigurationEvent, UpdateConfigurationClassification>('updateConfiguration', {
configurationSource: ConfigurationTargetToString(event.source),
configurationKeys: flattenKeys(event.sourceConfig)
});
/* __GDPR__
"updateConfigurationValues" : {
"configurationSource" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"configurationValues": { "classification": "CustomerContent", "purpose": "FeatureInsight" }
}
*/
telemetryService.publicLog('updateConfigurationValues', {
type UpdateConfigurationValuesClassification = {
configurationSource: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
configurationValues: { classification: 'CustomerContent', purpose: 'FeatureInsight' };
};
type UpdateConfigurationValuesEvent = {
configurationSource: string;
configurationValues: { [key: string]: any }[];
};
telemetryService.publicLog2<UpdateConfigurationValuesEvent, UpdateConfigurationValuesClassification>('updateConfigurationValues', {
configurationSource: ConfigurationTargetToString(event.source),
configurationValues: flattenValues(event.sourceConfig, configurationValueWhitelist)
});
@@ -217,12 +225,13 @@ export function configurationTelemetry(telemetryService: ITelemetryService, conf
export function keybindingsTelemetry(telemetryService: ITelemetryService, keybindingService: IKeybindingService): IDisposable {
return keybindingService.onDidUpdateKeybindings(event => {
if (event.source === KeybindingSource.User && event.keybindings) {
/* __GDPR__
"updateKeybindings" : {
"bindings": { "classification": "CustomerContent", "purpose": "FeatureInsight" }
}
*/
telemetryService.publicLog('updateKeybindings', {
type UpdateKeybindingsClassification = {
bindings: { classification: 'CustomerContent', purpose: 'FeatureInsight' };
};
type UpdateKeybindingsEvents = {
bindings: { key: string, command: string, when: string | undefined, args: boolean | undefined }[];
};
telemetryService.publicLog2<UpdateKeybindingsEvents, UpdateKeybindingsClassification>('updateKeybindings', {
bindings: event.keybindings.map(binding => ({
key: binding.key,
command: binding.command,
@@ -234,7 +243,7 @@ export function keybindingsTelemetry(telemetryService: ITelemetryService, keybin
});
}
function flattenKeys(value: Object): string[] {
function flattenKeys(value: Object | undefined): string[] {
if (!value) {
return [];
}
@@ -243,7 +252,7 @@ function flattenKeys(value: Object): string[] {
return result;
}
function flatKeys(result: string[], prefix: string, value: Object): void {
function flatKeys(result: string[], prefix: string, value: { [key: string]: any } | undefined): void {
if (value && typeof value === 'object' && !Array.isArray(value)) {
Object.keys(value)
.forEach(key => flatKeys(result, prefix ? `${prefix}.${key}` : key, value[key]));
@@ -252,7 +261,7 @@ function flatKeys(result: string[], prefix: string, value: Object): void {
}
}
function flattenValues(value: Object, keys: string[]): { [key: string]: any }[] {
function flattenValues(value: { [key: string]: any } | undefined, keys: string[]): { [key: string]: any }[] {
if (!value) {
return [];
}