Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added strictly typed telemetry function #75915

Merged
merged 2 commits into from Jun 21, 2019
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/vs/editor/standalone/browser/simpleServices.ts
Expand Up @@ -44,6 +44,7 @@ import { IWorkspace, IWorkspaceContextService, IWorkspaceFolder, IWorkspaceFolde
import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { ILayoutService, IDimension } from 'vs/platform/layout/browser/layoutService';
import { SimpleServicesNLS } from 'vs/editor/common/standaloneStrings';
import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';

export class SimpleModel implements IResolvedTextEditorModel {

Expand Down Expand Up @@ -525,6 +526,10 @@ export class StandaloneTelemetryService implements ITelemetryService {
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 any);
}

public getTelemetryInfo(): Promise<ITelemetryInfo> {
throw new Error(`Not available`);
}
Expand Down
26 changes: 26 additions & 0 deletions src/vs/platform/telemetry/common/gdprTypings.ts
@@ -0,0 +1,26 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. 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 };
3 changes: 3 additions & 0 deletions src/vs/platform/telemetry/common/telemetry.ts
Expand Up @@ -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');

Expand All @@ -29,6 +30,8 @@ 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>;
Expand Down
5 changes: 5 additions & 0 deletions src/vs/platform/telemetry/common/telemetryService.ts
Expand Up @@ -13,6 +13,7 @@ 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;
Expand Down Expand Up @@ -131,6 +132,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;

Expand Down
4 changes: 4 additions & 0 deletions src/vs/platform/telemetry/common/telemetryUtils.ts
Expand Up @@ -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> {
Expand Down
7 changes: 7 additions & 0 deletions src/vs/workbench/api/browser/mainThreadTelemetry.ts
Expand Up @@ -6,6 +6,7 @@
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { MainThreadTelemetryShape, MainContext, IExtHostContext } from '../common/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';

@extHostNamedCustomer(MainContext.MainThreadTelemetry)
export class MainThreadTelemetry implements MainThreadTelemetryShape {
Expand All @@ -28,4 +29,10 @@ export class MainThreadTelemetry implements MainThreadTelemetryShape {
data[MainThreadTelemetry._name] = true;
this._telemetryService.publicLog(eventName, data);
}

$publicLog2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data: StrictPropertyCheck<T, E>): void {
this.$publicLog(eventName, data as any);
}
}


2 changes: 2 additions & 0 deletions src/vs/workbench/api/common/extHost.protocol.ts
Expand Up @@ -46,6 +46,7 @@ import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHi
import { IRelativePattern } from 'vs/base/common/glob';
import { IRemoteConsoleLog } from 'vs/base/common/console';
import { VSBuffer } from 'vs/base/common/buffer';
import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';

export interface IEnvironment {
isExtensionDevelopmentDebug: boolean;
Expand Down Expand Up @@ -508,6 +509,7 @@ export interface MainThreadStorageShape extends IDisposable {

export interface MainThreadTelemetryShape extends IDisposable {
$publicLog(eventName: string, data?: any): void;
$publicLog2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data?: StrictPropertyCheck<T, E>): void;
}

export interface MainThreadEditorInsetsShape extends IDisposable {
Expand Down
5 changes: 5 additions & 0 deletions src/vs/workbench/browser/web.simpleservices.ts
Expand Up @@ -50,6 +50,7 @@ import { pathsToEditors } from 'vs/workbench/common/editor';
import { IFileService } from 'vs/platform/files/common/files';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ParsedArgs } from 'vs/platform/environment/common/environment';
import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';

//#region Backup File

Expand Down Expand Up @@ -659,6 +660,10 @@ export class SimpleTelemetryService implements ITelemetryService {
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(value: boolean): void {
}

Expand Down
Expand Up @@ -16,6 +16,7 @@ import { IStorageService } from 'vs/platform/storage/common/storage';
import { resolveWorkbenchCommonProperties } from 'vs/platform/telemetry/node/workbenchCommonProperties';
import { TelemetryService as BaseTelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';

export class TelemetryService extends Disposable implements ITelemetryService {

Expand Down Expand Up @@ -59,6 +60,10 @@ export class TelemetryService extends Disposable implements ITelemetryService {
return this.impl.publicLog(eventName, data, anonymizeFilePaths);
}

publicLog2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data?: StrictPropertyCheck<T, E>, anonymizeFilePaths?: boolean) {
return this.publicLog(eventName, data as ITelemetryData, anonymizeFilePaths);
}

getTelemetryInfo(): Promise<ITelemetryInfo> {
return this.impl.getTelemetryInfo();
}
Expand Down
Expand Up @@ -29,6 +29,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor
import { LocalSearchService } from 'vs/workbench/services/search/node/searchService';
import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { TestContextService, TestEditorGroupsService, TestEditorService, TestEnvironmentService, TestTextResourcePropertiesService } from 'vs/workbench/test/workbenchTestServices';
import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';

namespace Timer {
export interface ITimerEvent {
Expand Down Expand Up @@ -172,6 +173,10 @@ class TestTelemetryService implements ITelemetryService {
return Promise.resolve(undefined);
}

public publicLog2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data?: StrictPropertyCheck<T, E>) {
return this.publicLog(eventName, data as any);
}

public getTelemetryInfo(): Promise<ITelemetryInfo> {
return Promise.resolve({
instanceId: 'someValue.instanceId',
Expand Down
Expand Up @@ -33,6 +33,7 @@ import { Event, Emitter } from 'vs/base/common/event';
import { testWorkspace } from 'vs/platform/workspace/test/common/testWorkspace';
import { NullLogService, ILogService } from 'vs/platform/log/common/log';
import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration';
import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';

declare var __dirname: string;

Expand Down Expand Up @@ -165,6 +166,10 @@ class TestTelemetryService implements ITelemetryService {
return Promise.resolve();
}

public publicLog2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data?: StrictPropertyCheck<T, E>) {
return this.publicLog(eventName, data as any);
}

public getTelemetryInfo(): Promise<ITelemetryInfo> {
return Promise.resolve({
instanceId: 'someValue.instanceId',
Expand Down