diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 185b43fcfb7..3bcae63a760 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -939,7 +939,7 @@ export class CodeApplication extends Disposable { const isInternal = isInternalTelemetry(this.productService, this.configurationService); const channel = getDelayedChannel(sharedProcessReady.then(client => client.getChannel('telemetryAppender'))); const appender = new TelemetryAppenderClient(channel); - const commonProperties = resolveCommonProperties(this.fileService, release(), hostname(), process.arch, this.productService.commit, this.productService.version, machineId, isInternal, this.environmentMainService.installSourcePath); + const commonProperties = resolveCommonProperties(release(), hostname(), process.arch, this.productService.commit, this.productService.version, machineId, isInternal); const piiPaths = getPiiPathsFromEnvironment(this.environmentMainService); const config: ITelemetryServiceConfig = { appenders: [appender], commonProperties, piiPaths, sendErrorTelemetry: true }; diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index 6921d965742..73268f714f7 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -5,7 +5,6 @@ import { hostname, release } from 'os'; import { raceTimeout } from 'vs/base/common/async'; -import { VSBuffer } from 'vs/base/common/buffer'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { isSigPipeError, onUnexpectedError, setUnexpectedErrorHandler } from 'vs/base/common/errors'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -171,6 +170,16 @@ class CliMain extends Disposable { configurationService.initialize() ]); + // Get machine ID + let machineId: string | undefined = undefined; + try { + machineId = await resolveMachineId(stateService, logService); + } catch (error) { + if (error.code !== 'ENOENT') { + logService.error(error); + } + } + // Initialize user data profiles after initializing the state userDataProfilesService.init(); @@ -201,23 +210,10 @@ class CliMain extends Disposable { appenders.push(new OneDataSystemAppender(isInternal, 'monacoworkbench', null, productService.aiConfig.ariaKey)); } - const { installSourcePath } = environmentService; - const config: ITelemetryServiceConfig = { appenders, sendErrorTelemetry: false, - commonProperties: (async () => { - let machineId: string | undefined = undefined; - try { - machineId = await resolveMachineId(stateService, logService); - } catch (error) { - if (error.code !== 'ENOENT') { - logService.error(error); - } - } - - return resolveCommonProperties(fileService, release(), hostname(), process.arch, productService.commit, productService.version, machineId, isInternal, installSourcePath); - })(), + commonProperties: resolveCommonProperties(release(), hostname(), process.arch, productService.commit, productService.version, machineId, isInternal), piiPaths: getPiiPathsFromEnvironment(environmentService) }; @@ -261,11 +257,6 @@ class CliMain extends Disposable { } const profileLocation = (profile ?? userDataProfilesService.defaultProfile).extensionsResource; - // Install Source - if (this.argv['install-source']) { - return this.setInstallSource(environmentService, fileService, this.argv['install-source']); - } - // List Extensions if (this.argv['list-extensions']) { return instantiationService.createInstance(ExtensionManagementCLI, new ConsoleLogger(LogLevel.Info, false)).listExtensions(!!this.argv['show-versions'], this.argv['category'], profileLocation); @@ -296,10 +287,6 @@ class CliMain extends Disposable { private asExtensionIdOrVSIX(inputs: string[]): (string | URI)[] { return inputs.map(input => /\.vsix$/i.test(input) ? URI.file(isAbsolute(input) ? input : join(cwd(), input)) : input); } - - private async setInstallSource(environmentService: INativeEnvironmentService, fileService: IFileService, installSource: string): Promise { - await fileService.writeFile(URI.file(environmentService.installSourcePath), VSBuffer.fromString(installSource.slice(0, 30))); - } } export async function main(argv: NativeParsedArgs): Promise { diff --git a/src/vs/code/node/sharedProcess/sharedProcessMain.ts b/src/vs/code/node/sharedProcess/sharedProcessMain.ts index 5a6882fa5e5..cd4ebe3db1f 100644 --- a/src/vs/code/node/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/node/sharedProcess/sharedProcessMain.ts @@ -319,7 +319,6 @@ class SharedProcessMain extends Disposable { if (supportsTelemetry(productService, environmentService)) { const logAppender = new TelemetryLogAppender(logService, loggerService, environmentService, productService); appenders.push(logAppender); - const { installSourcePath } = environmentService; if (productService.aiConfig?.ariaKey) { const collectorAppender = new OneDataSystemAppender(internalTelemetry, 'monacoworkbench', null, productService.aiConfig.ariaKey); this._register(toDisposable(() => collectorAppender.flush())); // Ensure the 1DS appender is disposed so that it flushes remaining data @@ -328,7 +327,7 @@ class SharedProcessMain extends Disposable { telemetryService = new TelemetryService({ appenders, - commonProperties: resolveCommonProperties(fileService, release(), hostname(), process.arch, productService.commit, productService.version, this.configuration.machineId, internalTelemetry, installSourcePath), + commonProperties: resolveCommonProperties(release(), hostname(), process.arch, productService.commit, productService.version, this.configuration.machineId, internalTelemetry), sendErrorTelemetry: true, piiPaths: getPiiPathsFromEnvironment(environmentService), }, configurationService, productService); diff --git a/src/vs/editor/standalone/browser/standaloneServices.ts b/src/vs/editor/standalone/browser/standaloneServices.ts index 63648f50d06..2f7eb0bc07a 100644 --- a/src/vs/editor/standalone/browser/standaloneServices.ts +++ b/src/vs/editor/standalone/browser/standaloneServices.ts @@ -44,11 +44,10 @@ import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayo import { ILabelService, ResourceLabelFormatter, IFormatterChangeEvent, Verbosity } from 'vs/platform/label/common/label'; import { INotification, INotificationHandle, INotificationService, IPromptChoice, IPromptOptions, NoOpNotification, IStatusMessageOptions } from 'vs/platform/notification/common/notification'; import { IProgressRunner, IEditorProgressService, IProgressService, IProgress, IProgressCompositeOptions, IProgressDialogOptions, IProgressNotificationOptions, IProgressOptions, IProgressStep, IProgressWindowOptions } from 'vs/platform/progress/common/progress'; -import { ITelemetryInfo, ITelemetryService, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; +import { ITelemetryService, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier, IWorkspace, IWorkspaceContextService, IWorkspaceFolder, IWorkspaceFoldersChangeEvent, IWorkspaceFoldersWillChangeEvent, WorkbenchState, WorkspaceFolder, STANDALONE_EDITOR_WORKSPACE_ID } from 'vs/platform/workspace/common/workspace'; import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { StandaloneServicesNLS } from 'vs/editor/common/standaloneStrings'; -import { ClassifiedEvent, StrictPropertyCheck, OmitMetadata, IGDPRProperty } from 'vs/platform/telemetry/common/gdprTypings'; import { basename } from 'vs/base/common/resources'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { ConsoleLogger, ILogService } from 'vs/platform/log/common/log'; @@ -717,35 +716,17 @@ class StandaloneResourcePropertiesService implements ITextResourcePropertiesServ class StandaloneTelemetryService implements ITelemetryService { declare readonly _serviceBrand: undefined; - - public telemetryLevel = TelemetryLevel.NONE; - public sendErrorTelemetry = false; - - public setEnabled(value: boolean): void { - } - - public setExperimentProperty(name: string, value: string): void { - } - - public publicLog(eventName: string, data?: any): Promise { - return Promise.resolve(undefined); - } - - publicLog2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck) { - return this.publicLog(eventName, data as any); - } - - public publicLogError(eventName: string, data?: any): Promise { - return Promise.resolve(undefined); - } - - publicLogError2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck) { - return this.publicLogError(eventName, data as any); - } - - public getTelemetryInfo(): Promise { - throw new Error(`Not available`); - } + readonly telemetryLevel = TelemetryLevel.NONE; + readonly sessionId = 'someValue.sessionId'; + readonly machineId = 'someValue.machineId'; + readonly firstSessionDate = 'someValue.firstSessionDate'; + readonly sendErrorTelemetry = false; + setEnabled(): void { } + setExperimentProperty(): void { } + publicLog() { } + publicLog2() { } + publicLogError() { } + publicLogError2() { } } class StandaloneWorkspaceContextService implements IWorkspaceContextService { diff --git a/src/vs/platform/assignment/common/assignmentService.ts b/src/vs/platform/assignment/common/assignmentService.ts index ca98ef69341..b7cf3a1127c 100644 --- a/src/vs/platform/assignment/common/assignmentService.ts +++ b/src/vs/platform/assignment/common/assignmentService.ts @@ -21,7 +21,7 @@ export abstract class BaseAssignmentService implements IAssignmentService { } constructor( - private readonly getMachineId: () => Promise, + private readonly machineId: string, protected readonly configurationService: IConfigurationService, protected readonly productService: IProductService, protected telemetry: IExperimentationTelemetry, @@ -77,11 +77,10 @@ export abstract class BaseAssignmentService implements IAssignmentService { TargetPopulation.Public : (this.productService.quality === 'exploration' ? TargetPopulation.Exploration : TargetPopulation.Insiders); - const machineId = await this.getMachineId(); const filterProvider = new AssignmentFilterProvider( this.productService.version, this.productService.nameLong, - machineId, + this.machineId, targetPopulation ); diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index 66e37b69e3a..dbec787f077 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -135,7 +135,6 @@ export interface INativeEnvironmentService extends IEnvironmentService { tmpDir: URI; userDataPath: string; machineSettingsResource: URI; - installSourcePath: string; // --- extensions extensionsPath: string; diff --git a/src/vs/platform/environment/common/environmentService.ts b/src/vs/platform/environment/common/environmentService.ts index cabac5aa087..7f2e8e93b3e 100644 --- a/src/vs/platform/environment/common/environmentService.ts +++ b/src/vs/platform/environment/common/environmentService.ts @@ -110,9 +110,6 @@ export abstract class AbstractNativeEnvironmentService implements INativeEnviron @memoize get untitledWorkspacesHome(): URI { return URI.file(join(this.userDataPath, 'Workspaces')); } - @memoize - get installSourcePath(): string { return join(this.userDataPath, 'installSource'); } - @memoize get builtinExtensionsPath(): string { const cliBuiltinExtensionsDir = this.args['builtin-extensions-dir']; diff --git a/src/vs/platform/externalServices/common/marketplace.ts b/src/vs/platform/externalServices/common/marketplace.ts index 4a5239870f6..abb5e379869 100644 --- a/src/vs/platform/externalServices/common/marketplace.ts +++ b/src/vs/platform/externalServices/common/marketplace.ts @@ -28,12 +28,11 @@ export async function resolveMarketplaceHeaders(version: string, if (supportsTelemetry(productService, environmentService) && getTelemetryLevel(configurationService) === TelemetryLevel.USAGE) { const serviceMachineId = await getServiceMachineId(environmentService, fileService, storageService); - const { machineId } = await telemetryService.getTelemetryInfo(); headers['X-Market-User-Id'] = serviceMachineId; // Send machineId as VSCode-SessionId so we can correlate telemetry events across different services // machineId can be undefined sometimes (eg: when launching from CLI), so send serviceMachineId instead otherwise // Marketplace will reject the request if there is no VSCode-SessionId header - headers['VSCode-SessionId'] = machineId || serviceMachineId; + headers['VSCode-SessionId'] = telemetryService.machineId || serviceMachineId; } return headers; diff --git a/src/vs/platform/telemetry/common/commonProperties.ts b/src/vs/platform/telemetry/common/commonProperties.ts index 1b1df77de55..7ee1e0b7705 100644 --- a/src/vs/platform/telemetry/common/commonProperties.ts +++ b/src/vs/platform/telemetry/common/commonProperties.ts @@ -5,9 +5,8 @@ import { isLinuxSnap, platform, Platform, PlatformToString } from 'vs/base/common/platform'; import { env, platform as nodePlatform } from 'vs/base/common/process'; -import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; -import { IFileService } from 'vs/platform/files/common/files'; +import { ICommonProperties } from 'vs/platform/telemetry/common/telemetry'; function getPlatformDetail(hostname: string): string | undefined { if (platform === Platform.Linux && /^penguin(\.|$)/i.test(hostname)) { @@ -17,8 +16,7 @@ function getPlatformDetail(hostname: string): string | undefined { return undefined; } -export async function resolveCommonProperties( - fileService: IFileService, +export function resolveCommonProperties( release: string, hostname: string, arch: string, @@ -26,10 +24,9 @@ export async function resolveCommonProperties( version: string | undefined, machineId: string | undefined, isInternalTelemetry: boolean, - installSourcePath: string, product?: string -): Promise<{ [name: string]: string | boolean | undefined }> { - const result: { [name: string]: string | boolean | undefined } = Object.create(null); +): ICommonProperties { + const result: ICommonProperties = Object.create(null); // __GDPR__COMMON__ "common.machineId" : { "endPoint": "MacAddressHash", "classification": "EndUserPseudonymizedInformation", "purpose": "FeatureInsight" } result['common.machineId'] = machineId; @@ -88,15 +85,6 @@ export async function resolveCommonProperties( result['common.platformDetail'] = platformDetail; } - try { - const contents = await fileService.readFile(URI.file(installSourcePath)); - - // __GDPR__COMMON__ "common.source" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - result['common.source'] = contents.value.toString().slice(0, 30); - } catch (error) { - // ignore error - } - return result; } diff --git a/src/vs/platform/telemetry/common/serverTelemetryService.ts b/src/vs/platform/telemetry/common/serverTelemetryService.ts index dd9fd5359ed..9581af7e0f9 100644 --- a/src/vs/platform/telemetry/common/serverTelemetryService.ts +++ b/src/vs/platform/telemetry/common/serverTelemetryService.ts @@ -30,25 +30,25 @@ export class ServerTelemetryService extends TelemetryService implements IServerT this._injectedTelemetryLevel = injectedTelemetryLevel; } - override publicLog(eventName: string, data?: ITelemetryData): Promise { + override publicLog(eventName: string, data?: ITelemetryData) { if (this._injectedTelemetryLevel < TelemetryLevel.USAGE) { - return Promise.resolve(undefined); + return; } return super.publicLog(eventName, data); } - override publicLog2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck): Promise { + override publicLog2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck) { return this.publicLog(eventName, data as ITelemetryData | undefined); } - override publicLogError(errorEventName: string, data?: ITelemetryData): Promise { + override publicLogError(errorEventName: string, data?: ITelemetryData) { if (this._injectedTelemetryLevel < TelemetryLevel.ERROR) { return Promise.resolve(undefined); } return super.publicLogError(errorEventName, data); } - override publicLogError2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck): Promise { + override publicLogError2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck) { return this.publicLogError(eventName, data as ITelemetryData | undefined); } diff --git a/src/vs/platform/telemetry/common/telemetry.ts b/src/vs/platform/telemetry/common/telemetry.ts index d0338e17c06..f19c01188ee 100644 --- a/src/vs/platform/telemetry/common/telemetry.ts +++ b/src/vs/platform/telemetry/common/telemetry.ts @@ -8,13 +8,6 @@ import { ClassifiedEvent, IGDPRProperty, OmitMetadata, StrictPropertyCheck } fro export const ITelemetryService = createDecorator('telemetryService'); -export interface ITelemetryInfo { - sessionId: string; - machineId: string; - firstSessionDate: string; - msftInternal?: boolean; -} - export interface ITelemetryData { from?: string; target?: string; @@ -23,36 +16,39 @@ export interface ITelemetryData { export interface ITelemetryService { + readonly _serviceBrand: undefined; + + readonly telemetryLevel: TelemetryLevel; + + readonly sessionId: string; + readonly machineId: string; + readonly firstSessionDate: string; + readonly msftInternal?: boolean; + /** * Whether error telemetry will get sent. If false, `publicLogError` will no-op. */ readonly sendErrorTelemetry: boolean; - readonly _serviceBrand: undefined; - /** * @deprecated Use publicLog2 and the typescript GDPR annotation where possible */ - publicLog(eventName: string, data?: ITelemetryData): Promise; + publicLog(eventName: string, data?: ITelemetryData): void; /** * Sends a telemetry event that has been privacy approved. * Do not call this unless you have been given approval. */ - publicLog2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck): Promise; + publicLog2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck): void; /** * @deprecated Use publicLogError2 and the typescript GDPR annotation where possible */ - publicLogError(errorEventName: string, data?: ITelemetryData): Promise; + publicLogError(errorEventName: string, data?: ITelemetryData): void; - publicLogError2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck): Promise; - - getTelemetryInfo(): Promise; + publicLogError2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck): void; setExperimentProperty(name: string, value: string): void; - - readonly telemetryLevel: TelemetryLevel; } export interface ITelemetryEndpoint { @@ -66,8 +62,8 @@ export const ICustomEndpointTelemetryService = createDecorator; - publicLogError(endpoint: ITelemetryEndpoint, errorEventName: string, data?: ITelemetryData): Promise; + publicLog(endpoint: ITelemetryEndpoint, eventName: string, data?: ITelemetryData): void; + publicLogError(endpoint: ITelemetryEndpoint, errorEventName: string, data?: ITelemetryData): void; } // Keys @@ -95,3 +91,7 @@ export const enum TelemetryConfiguration { ERROR = 'error', ON = 'all' } + +export interface ICommonProperties { + [name: string]: string | boolean | undefined; +} diff --git a/src/vs/platform/telemetry/common/telemetryService.ts b/src/vs/platform/telemetry/common/telemetryService.ts index 960ebc45dc1..e10d846b083 100644 --- a/src/vs/platform/telemetry/common/telemetryService.ts +++ b/src/vs/platform/telemetry/common/telemetryService.ts @@ -14,13 +14,13 @@ import product from 'vs/platform/product/common/product'; import { IProductService } from 'vs/platform/product/common/productService'; import { Registry } from 'vs/platform/registry/common/platform'; import { ClassifiedEvent, IGDPRProperty, OmitMetadata, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings'; -import { ITelemetryData, ITelemetryInfo, ITelemetryService, TelemetryConfiguration, TelemetryLevel, TELEMETRY_CRASH_REPORTER_SETTING_ID, TELEMETRY_OLD_SETTING_ID, TELEMETRY_SECTION_ID, TELEMETRY_SETTING_ID } from 'vs/platform/telemetry/common/telemetry'; +import { ITelemetryData, ITelemetryService, TelemetryConfiguration, TelemetryLevel, TELEMETRY_CRASH_REPORTER_SETTING_ID, TELEMETRY_OLD_SETTING_ID, TELEMETRY_SECTION_ID, TELEMETRY_SETTING_ID, ICommonProperties } from 'vs/platform/telemetry/common/telemetry'; import { cleanData, getTelemetryLevel, ITelemetryAppender } from 'vs/platform/telemetry/common/telemetryUtils'; export interface ITelemetryServiceConfig { appenders: ITelemetryAppender[]; sendErrorTelemetry?: boolean; - commonProperties?: Promise<{ [name: string]: any }>; + commonProperties?: ICommonProperties; piiPaths?: string[]; } @@ -31,14 +31,18 @@ export class TelemetryService implements ITelemetryService { declare readonly _serviceBrand: undefined; + readonly sessionId: string; + readonly machineId: string; + readonly firstSessionDate: string; + readonly msftInternal: boolean | undefined; + private _appenders: ITelemetryAppender[]; - private _commonProperties: Promise<{ [name: string]: any }>; + private _commonProperties: ICommonProperties; private _experimentProperties: { [name: string]: string } = {}; private _piiPaths: string[]; private _telemetryLevel: TelemetryLevel; private _sendErrorTelemetry: boolean; - private readonly _disposables = new DisposableStore(); private _cleanupPatterns: RegExp[] = []; @@ -48,7 +52,13 @@ export class TelemetryService implements ITelemetryService { @IProductService private _productService: IProductService ) { this._appenders = config.appenders; - this._commonProperties = config.commonProperties || Promise.resolve({}); + this._commonProperties = config.commonProperties ?? Object.create(null); + + this.sessionId = this._commonProperties['sessionID'] as string; + this.machineId = this._commonProperties['common.machineId'] as string; + this.firstSessionDate = this._commonProperties['common.firstSessionDate'] as string; + this.msftInternal = this._commonProperties['common.msftInternal'] as boolean | undefined; + this._piiPaths = config.piiPaths || []; this._telemetryLevel = TelemetryLevel.USAGE; this._sendErrorTelemetry = !!config.sendErrorTelemetry; @@ -103,67 +113,48 @@ export class TelemetryService implements ITelemetryService { return this._telemetryLevel; } - async getTelemetryInfo(): Promise { - const values = await this._commonProperties; - - // well known properties - const sessionId = values['sessionID']; - const machineId = values['common.machineId']; - const firstSessionDate = values['common.firstSessionDate']; - const msftInternal = values['common.msftInternal']; - - return { sessionId, machineId, firstSessionDate, msftInternal }; - } - dispose(): void { this._disposables.dispose(); } - private _log(eventName: string, eventLevel: TelemetryLevel, data?: ITelemetryData): Promise { + private _log(eventName: string, eventLevel: TelemetryLevel, data?: ITelemetryData) { // don't send events when the user is optout if (this._telemetryLevel < eventLevel) { - return Promise.resolve(undefined); + return; } - return this._commonProperties.then(values => { + // add experiment properties + data = mixin(data, this._experimentProperties); - // add experiment properties - data = mixin(data, this._experimentProperties); + // remove all PII from data + data = cleanData(data as Record, this._cleanupPatterns); - // remove all PII from data - data = cleanData(data as Record, this._cleanupPatterns); + // add common properties + data = mixin(data, this._commonProperties); - // add common properties - data = mixin(data, values); - - // Log to the appenders of sufficient level - this._appenders.forEach(a => a.log(eventName, data)); - - }, err => { - // unsure what to do now... - console.error(err); - }); + // Log to the appenders of sufficient level + this._appenders.forEach(a => a.log(eventName, data)); } - publicLog(eventName: string, data?: ITelemetryData): Promise { - return this._log(eventName, TelemetryLevel.USAGE, data); + publicLog(eventName: string, data?: ITelemetryData) { + this._log(eventName, TelemetryLevel.USAGE, data); } - publicLog2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck): Promise { - return this.publicLog(eventName, data as ITelemetryData); + publicLog2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck) { + this.publicLog(eventName, data as ITelemetryData); } - publicLogError(errorEventName: string, data?: ITelemetryData): Promise { + publicLogError(errorEventName: string, data?: ITelemetryData) { if (!this._sendErrorTelemetry) { - return Promise.resolve(undefined); + return; } // Send error event and anonymize paths - return this._log(errorEventName, TelemetryLevel.ERROR, data); + this._log(errorEventName, TelemetryLevel.ERROR, data); } - publicLogError2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck): Promise { - return this.publicLogError(eventName, data as ITelemetryData); + publicLogError2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck) { + this.publicLogError(eventName, data as ITelemetryData); } } diff --git a/src/vs/platform/telemetry/common/telemetryUtils.ts b/src/vs/platform/telemetry/common/telemetryUtils.ts index 758dec5ab76..e48327d5202 100644 --- a/src/vs/platform/telemetry/common/telemetryUtils.ts +++ b/src/vs/platform/telemetry/common/telemetryUtils.ts @@ -13,8 +13,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { IProductService } from 'vs/platform/product/common/productService'; import { getRemoteName } from 'vs/platform/remote/common/remoteHosts'; import { verifyMicrosoftInternalDomain } from 'vs/platform/telemetry/common/commonProperties'; -import { ClassifiedEvent, IGDPRProperty, OmitMetadata, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings'; -import { ICustomEndpointTelemetryService, ITelemetryData, ITelemetryEndpoint, ITelemetryInfo, ITelemetryService, TelemetryConfiguration, TelemetryLevel, TELEMETRY_CRASH_REPORTER_SETTING_ID, TELEMETRY_OLD_SETTING_ID, TELEMETRY_SETTING_ID } from 'vs/platform/telemetry/common/telemetry'; +import { ICustomEndpointTelemetryService, ITelemetryData, ITelemetryEndpoint, ITelemetryService, TelemetryConfiguration, TelemetryLevel, TELEMETRY_CRASH_REPORTER_SETTING_ID, TELEMETRY_OLD_SETTING_ID, TELEMETRY_SETTING_ID } from 'vs/platform/telemetry/common/telemetry'; /** * A special class used to denoting a telemetry value which should not be clean. @@ -27,31 +26,16 @@ export class TelemetryTrustedValue { export class NullTelemetryServiceShape implements ITelemetryService { declare readonly _serviceBrand: undefined; + readonly telemetryLevel = TelemetryLevel.NONE; + readonly sessionId = 'someValue.sessionId'; + readonly machineId = 'someValue.machineId'; + readonly firstSessionDate = 'someValue.firstSessionDate'; readonly sendErrorTelemetry = false; - - publicLog(eventName: string, data?: ITelemetryData) { - return Promise.resolve(undefined); - } - publicLog2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck) { - return this.publicLog(eventName, data as ITelemetryData); - } - publicLogError(eventName: string, data?: ITelemetryData) { - return Promise.resolve(undefined); - } - publicLogError2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck) { - return this.publicLogError(eventName, data as ITelemetryData); - } - + publicLog() { } + publicLog2() { } + publicLogError() { } + publicLogError2() { } setExperimentProperty() { } - telemetryLevel = TelemetryLevel.NONE; - getTelemetryInfo(): Promise { - return Promise.resolve({ - instanceId: 'someValue.instanceId', - sessionId: 'someValue.sessionId', - machineId: 'someValue.machineId', - firstSessionDate: 'someValue.firstSessionDate' - }); - } } export const NullTelemetryService = new NullTelemetryServiceShape(); diff --git a/src/vs/platform/telemetry/node/customEndpointTelemetryService.ts b/src/vs/platform/telemetry/node/customEndpointTelemetryService.ts index a21bae2c0ab..d697c46cbf3 100644 --- a/src/vs/platform/telemetry/node/customEndpointTelemetryService.ts +++ b/src/vs/platform/telemetry/node/customEndpointTelemetryService.ts @@ -13,6 +13,7 @@ import { ICustomEndpointTelemetryService, ITelemetryData, ITelemetryEndpoint, IT import { TelemetryAppenderClient } from 'vs/platform/telemetry/common/telemetryIpc'; import { TelemetryLogAppender } from 'vs/platform/telemetry/common/telemetryLogAppender'; import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; + export class CustomEndpointTelemetryService implements ICustomEndpointTelemetryService { declare readonly _serviceBrand: undefined; @@ -27,12 +28,11 @@ export class CustomEndpointTelemetryService implements ICustomEndpointTelemetryS @IProductService private readonly productService: IProductService ) { } - private async getCustomTelemetryService(endpoint: ITelemetryEndpoint): Promise { + private getCustomTelemetryService(endpoint: ITelemetryEndpoint): ITelemetryService { if (!this.customTelemetryServices.has(endpoint.id)) { - const { machineId, sessionId } = await this.telemetryService.getTelemetryInfo(); const telemetryInfo: { [key: string]: string } = Object.create(null); - telemetryInfo['common.vscodemachineid'] = machineId; - telemetryInfo['common.vscodesessionid'] = sessionId; + telemetryInfo['common.vscodemachineid'] = this.telemetryService.machineId; + telemetryInfo['common.vscodesessionid'] = this.telemetryService.sessionId; const args = [endpoint.id, JSON.stringify(telemetryInfo), endpoint.aiKey]; const client = new TelemetryClient( FileAccess.asFileUri('bootstrap-fork').fsPath, @@ -63,13 +63,13 @@ export class CustomEndpointTelemetryService implements ICustomEndpointTelemetryS return this.customTelemetryServices.get(endpoint.id)!; } - async publicLog(telemetryEndpoint: ITelemetryEndpoint, eventName: string, data?: ITelemetryData): Promise { - const customTelemetryService = await this.getCustomTelemetryService(telemetryEndpoint); - await customTelemetryService.publicLog(eventName, data); + publicLog(telemetryEndpoint: ITelemetryEndpoint, eventName: string, data?: ITelemetryData) { + const customTelemetryService = this.getCustomTelemetryService(telemetryEndpoint); + customTelemetryService.publicLog(eventName, data); } - async publicLogError(telemetryEndpoint: ITelemetryEndpoint, errorEventName: string, data?: ITelemetryData): Promise { - const customTelemetryService = await this.getCustomTelemetryService(telemetryEndpoint); - await customTelemetryService.publicLogError(errorEventName, data); + publicLogError(telemetryEndpoint: ITelemetryEndpoint, errorEventName: string, data?: ITelemetryData) { + const customTelemetryService = this.getCustomTelemetryService(telemetryEndpoint); + customTelemetryService.publicLogError(errorEventName, data); } } diff --git a/src/vs/platform/telemetry/test/browser/telemetryService.test.ts b/src/vs/platform/telemetry/test/browser/telemetryService.test.ts index 87d524fea52..0c6711e8539 100644 --- a/src/vs/platform/telemetry/test/browser/telemetryService.test.ts +++ b/src/vs/platform/telemetry/test/browser/telemetryService.test.ts @@ -11,8 +11,7 @@ import { TestConfigurationService } from 'vs/platform/configuration/test/common/ import product from 'vs/platform/product/common/product'; import { IProductService } from 'vs/platform/product/common/productService'; import ErrorTelemetry from 'vs/platform/telemetry/browser/errorTelemetry'; -import { ClassifiedEvent, IGDPRProperty, OmitMetadata, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings'; -import { ITelemetryData, TelemetryConfiguration, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; +import { TelemetryConfiguration, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; import { ITelemetryServiceConfig, TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; import { ITelemetryAppender, NullAppender } from 'vs/platform/telemetry/common/telemetryUtils'; @@ -96,12 +95,11 @@ suite('TelemetryService', () => { const testAppender = new TestTelemetryAppender(); const service = new TelemetryService({ appenders: [testAppender] }, new TestConfigurationService(), TestProductService); - return service.publicLog('testPrivateEvent').then(() => { - assert.strictEqual(testAppender.getEventsCount(), 1); + service.publicLog('testPrivateEvent'); + assert.strictEqual(testAppender.getEventsCount(), 1); - service.dispose(); - assert.strictEqual(!testAppender.isDisposed, true); - }); + service.dispose(); + assert.strictEqual(!testAppender.isDisposed, true); })); // event reporting @@ -109,150 +107,114 @@ suite('TelemetryService', () => { const testAppender = new TestTelemetryAppender(); const service = new TelemetryService({ appenders: [testAppender] }, new TestConfigurationService(), TestProductService); - return service.publicLog('testEvent').then(_ => { - assert.strictEqual(testAppender.getEventsCount(), 1); - assert.strictEqual(testAppender.events[0].eventName, 'testEvent'); - assert.notStrictEqual(testAppender.events[0].data, null); + service.publicLog('testEvent'); + assert.strictEqual(testAppender.getEventsCount(), 1); + assert.strictEqual(testAppender.events[0].eventName, 'testEvent'); + assert.notStrictEqual(testAppender.events[0].data, null); - service.dispose(); - }); + service.dispose(); })); test('Event with data', sinonTestFn(function () { const testAppender = new TestTelemetryAppender(); const service = new TelemetryService({ appenders: [testAppender] }, new TestConfigurationService(), TestProductService); - return service.publicLog('testEvent', { + service.publicLog('testEvent', { 'stringProp': 'property', 'numberProp': 1, 'booleanProp': true, 'complexProp': { 'value': 0 } - }).then(() => { - assert.strictEqual(testAppender.getEventsCount(), 1); - assert.strictEqual(testAppender.events[0].eventName, 'testEvent'); - assert.notStrictEqual(testAppender.events[0].data, null); - assert.strictEqual(testAppender.events[0].data['stringProp'], 'property'); - assert.strictEqual(testAppender.events[0].data['numberProp'], 1); - assert.strictEqual(testAppender.events[0].data['booleanProp'], true); - assert.strictEqual(testAppender.events[0].data['complexProp'].value, 0); - - service.dispose(); }); + assert.strictEqual(testAppender.getEventsCount(), 1); + assert.strictEqual(testAppender.events[0].eventName, 'testEvent'); + assert.notStrictEqual(testAppender.events[0].data, null); + assert.strictEqual(testAppender.events[0].data['stringProp'], 'property'); + assert.strictEqual(testAppender.events[0].data['numberProp'], 1); + assert.strictEqual(testAppender.events[0].data['booleanProp'], true); + assert.strictEqual(testAppender.events[0].data['complexProp'].value, 0); + + service.dispose(); })); test('common properties added to *all* events, simple event', function () { const testAppender = new TestTelemetryAppender(); const service = new TelemetryService({ appenders: [testAppender], - commonProperties: Promise.resolve({ foo: 'JA!', get bar() { return Math.random(); } }) + commonProperties: { foo: 'JA!', get bar() { return Math.random() % 2 === 0; } } }, new TestConfigurationService(), TestProductService); - return service.publicLog('testEvent').then(_ => { - const [first] = testAppender.events; + service.publicLog('testEvent'); + const [first] = testAppender.events; - assert.strictEqual(Object.keys(first.data).length, 2); - assert.strictEqual(typeof first.data['foo'], 'string'); - assert.strictEqual(typeof first.data['bar'], 'number'); + assert.strictEqual(Object.keys(first.data).length, 2); + assert.strictEqual(typeof first.data['foo'], 'string'); + assert.strictEqual(typeof first.data['bar'], 'boolean'); - service.dispose(); - }); + service.dispose(); }); test('common properties added to *all* events, event with data', function () { const testAppender = new TestTelemetryAppender(); const service = new TelemetryService({ appenders: [testAppender], - commonProperties: Promise.resolve({ foo: 'JA!', get bar() { return Math.random(); } }) + commonProperties: { foo: 'JA!', get bar() { return Math.random() % 2 === 0; } } }, new TestConfigurationService(), TestProductService); - return service.publicLog('testEvent', { hightower: 'xl', price: 8000 }).then(_ => { - const [first] = testAppender.events; + service.publicLog('testEvent', { hightower: 'xl', price: 8000 }); + const [first] = testAppender.events; - assert.strictEqual(Object.keys(first.data).length, 4); - assert.strictEqual(typeof first.data['foo'], 'string'); - assert.strictEqual(typeof first.data['bar'], 'number'); - assert.strictEqual(typeof first.data['hightower'], 'string'); - assert.strictEqual(typeof first.data['price'], 'number'); + assert.strictEqual(Object.keys(first.data).length, 4); + assert.strictEqual(typeof first.data['foo'], 'string'); + assert.strictEqual(typeof first.data['bar'], 'boolean'); + assert.strictEqual(typeof first.data['hightower'], 'string'); + assert.strictEqual(typeof first.data['price'], 'number'); - service.dispose(); - }); + service.dispose(); }); test('TelemetryInfo comes from properties', function () { const service = new TelemetryService({ appenders: [NullAppender], - commonProperties: Promise.resolve({ + commonProperties: { sessionID: 'one', ['common.machineId']: 'three', - }) + } }, new TestConfigurationService(), TestProductService); - return service.getTelemetryInfo().then(info => { - assert.strictEqual(info.sessionId, 'one'); - assert.strictEqual(info.machineId, 'three'); + assert.strictEqual(service.sessionId, 'one'); + assert.strictEqual(service.machineId, 'three'); - service.dispose(); - }); + service.dispose(); }); - test('telemetry on by default', sinonTestFn(function () { + test('telemetry on by default', function () { const testAppender = new TestTelemetryAppender(); const service = new TelemetryService({ appenders: [testAppender] }, new TestConfigurationService(), TestProductService); - return service.publicLog('testEvent').then(() => { - assert.strictEqual(testAppender.getEventsCount(), 1); - assert.strictEqual(testAppender.events[0].eventName, 'testEvent'); + service.publicLog('testEvent'); + assert.strictEqual(testAppender.getEventsCount(), 1); + assert.strictEqual(testAppender.events[0].eventName, 'testEvent'); - service.dispose(); - }); - })); - - class JoinableTelemetryService extends TelemetryService { - - private promises: Promise[] = []; + service.dispose(); + }); + class TestErrorTelemetryService extends TelemetryService { constructor(config: ITelemetryServiceConfig) { super({ ...config, sendErrorTelemetry: true }, new TestConfigurationService, TestProductService); - this.promises = this.promises ?? []; - this.promises = this.promises ?? []; - } - - join(): Promise { - return Promise.all(this.promises); - } - - override publicLog(eventName: string, data?: ITelemetryData): Promise { - const p = super.publicLog(eventName, data); - // publicLog is called from the ctor and therefore promises can be undefined - this.promises = this.promises ?? []; - this.promises.push(p); - return p; - } - - override publicLogError(errorEventName: string, data?: ITelemetryData): Promise { - const p = super.publicLogError(errorEventName, data); - // publicLogError is called from the ctor and therefore promises can be undefined - this.promises = this.promises ?? []; - this.promises.push(p); - return p; - } - - override publicLogError2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck): Promise { - return this.publicLogError(eventName, data as ITelemetryData); } } - test('Error events', sinonTestFn(async function (this: any) { + test('Error events', sinonTestFn(function (this: any) { const origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler(); Errors.setUnexpectedErrorHandler(() => { }); try { const testAppender = new TestTelemetryAppender(); - const service = new JoinableTelemetryService({ appenders: [testAppender] }); + const service = new TestErrorTelemetryService({ appenders: [testAppender] }); const errorTelemetry = new ErrorTelemetry(service); @@ -264,7 +226,6 @@ suite('TelemetryService', () => { Errors.onUnexpectedError(e); this.clock.tick(ErrorTelemetry.ERROR_FLUSH_TIMEOUT); - await service.join(); assert.strictEqual(testAppender.getEventsCount(), 1); assert.strictEqual(testAppender.events[0].eventName, 'UnhandledError'); @@ -306,18 +267,17 @@ suite('TelemetryService', () => { // } // })); - test('Handle global errors', sinonTestFn(async function (this: any) { + test('Handle global errors', sinonTestFn(function (this: any) { const errorStub = sinon.stub(); window.onerror = errorStub; const testAppender = new TestTelemetryAppender(); - const service = new JoinableTelemetryService({ appenders: [testAppender] }); + const service = new TestErrorTelemetryService({ appenders: [testAppender] }); const errorTelemetry = new ErrorTelemetry(service); const testError = new Error('test'); (window.onerror)('Error Message', 'file.js', 2, 42, testError); this.clock.tick(ErrorTelemetry.ERROR_FLUSH_TIMEOUT); - await service.join(); assert.strictEqual(errorStub.alwaysCalledWithExactly('Error Message', 'file.js', 2, 42, testError), true); assert.strictEqual(errorStub.callCount, 1); @@ -334,12 +294,12 @@ suite('TelemetryService', () => { service.dispose(); })); - test('Error Telemetry removes PII from filename with spaces', sinonTestFn(async function (this: any) { + test('Error Telemetry removes PII from filename with spaces', sinonTestFn(function (this: any) { const errorStub = sinon.stub(); window.onerror = errorStub; const settings = new ErrorTestingSettings(); const testAppender = new TestTelemetryAppender(); - const service = new JoinableTelemetryService({ appenders: [testAppender] }); + const service = new TestErrorTelemetryService({ appenders: [testAppender] }); const errorTelemetry = new ErrorTelemetry(service); const personInfoWithSpaces = settings.personalInfo.slice(0, 2) + ' ' + settings.personalInfo.slice(2); @@ -347,7 +307,6 @@ suite('TelemetryService', () => { dangerousFilenameError.stack = settings.stack; (window.onerror)('dangerousFilename', settings.dangerousPathWithImportantInfo.replace(settings.personalInfo, personInfoWithSpaces) + '/test.js', 2, 42, dangerousFilenameError); this.clock.tick(ErrorTelemetry.ERROR_FLUSH_TIMEOUT); - await service.join(); assert.strictEqual(errorStub.callCount, 1); assert.strictEqual(testAppender.events[0].data.file.indexOf(settings.dangerousPathWithImportantInfo.replace(settings.personalInfo, personInfoWithSpaces)), -1); @@ -363,46 +322,41 @@ suite('TelemetryService', () => { window.onerror = errorStub; const settings = new ErrorTestingSettings(); const testAppender = new TestTelemetryAppender(); - const service = new JoinableTelemetryService({ appenders: [testAppender] }); + const service = new TestErrorTelemetryService({ appenders: [testAppender] }); const errorTelemetry = new ErrorTelemetry(service); let dangerousFilenameError: any = new Error('dangerousFilename'); dangerousFilenameError.stack = settings.stack; (window.onerror)('dangerousFilename', settings.dangerousPathWithImportantInfo + '/test.js', 2, 42, dangerousFilenameError); clock.tick(ErrorTelemetry.ERROR_FLUSH_TIMEOUT); - return service.join().then(() => { - assert.strictEqual(errorStub.callCount, 1); - assert.strictEqual(testAppender.events[0].data.file.indexOf(settings.dangerousPathWithImportantInfo), -1); + assert.strictEqual(errorStub.callCount, 1); + assert.strictEqual(testAppender.events[0].data.file.indexOf(settings.dangerousPathWithImportantInfo), -1); - dangerousFilenameError = new Error('dangerousFilename'); - dangerousFilenameError.stack = settings.stack; - (window.onerror)('dangerousFilename', settings.dangerousPathWithImportantInfo + '/test.js', 2, 42, dangerousFilenameError); - clock.tick(ErrorTelemetry.ERROR_FLUSH_TIMEOUT); - return service.join(); - }).then(() => { - assert.strictEqual(errorStub.callCount, 2); - assert.strictEqual(testAppender.events[0].data.file.indexOf(settings.dangerousPathWithImportantInfo), -1); - assert.strictEqual(testAppender.events[0].data.file, settings.importantInfo + '/test.js'); + dangerousFilenameError = new Error('dangerousFilename'); + dangerousFilenameError.stack = settings.stack; + (window.onerror)('dangerousFilename', settings.dangerousPathWithImportantInfo + '/test.js', 2, 42, dangerousFilenameError); + clock.tick(ErrorTelemetry.ERROR_FLUSH_TIMEOUT); + assert.strictEqual(errorStub.callCount, 2); + assert.strictEqual(testAppender.events[0].data.file.indexOf(settings.dangerousPathWithImportantInfo), -1); + assert.strictEqual(testAppender.events[0].data.file, settings.importantInfo + '/test.js'); - errorTelemetry.dispose(); - service.dispose(); - }); + errorTelemetry.dispose(); + service.dispose(); })); - test('Unexpected Error Telemetry removes PII', sinonTestFn(async function (this: any) { + test('Unexpected Error Telemetry removes PII', sinonTestFn(function (this: any) { const origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler(); Errors.setUnexpectedErrorHandler(() => { }); try { const settings = new ErrorTestingSettings(); const testAppender = new TestTelemetryAppender(); - const service = new JoinableTelemetryService({ appenders: [testAppender] }); + const service = new TestErrorTelemetryService({ appenders: [testAppender] }); const errorTelemetry = new ErrorTelemetry(service); const dangerousPathWithoutImportantInfoError: any = new Error(settings.dangerousPathWithoutImportantInfo); dangerousPathWithoutImportantInfoError.stack = settings.stack; Errors.onUnexpectedError(dangerousPathWithoutImportantInfoError); this.clock.tick(ErrorTelemetry.ERROR_FLUSH_TIMEOUT); - await service.join(); assert.strictEqual(testAppender.events[0].data.msg.indexOf(settings.personalInfo), -1); assert.strictEqual(testAppender.events[0].data.msg.indexOf(settings.filePrefix), -1); @@ -420,19 +374,18 @@ suite('TelemetryService', () => { } })); - test('Uncaught Error Telemetry removes PII', sinonTestFn(async function (this: any) { + test('Uncaught Error Telemetry removes PII', sinonTestFn(function (this: any) { const errorStub = sinon.stub(); window.onerror = errorStub; const settings = new ErrorTestingSettings(); const testAppender = new TestTelemetryAppender(); - const service = new JoinableTelemetryService({ appenders: [testAppender] }); + const service = new TestErrorTelemetryService({ appenders: [testAppender] }); const errorTelemetry = new ErrorTelemetry(service); const dangerousPathWithoutImportantInfoError: any = new Error('dangerousPathWithoutImportantInfo'); dangerousPathWithoutImportantInfoError.stack = settings.stack; (window.onerror)(settings.dangerousPathWithoutImportantInfo, 'test.js', 2, 42, dangerousPathWithoutImportantInfoError); this.clock.tick(ErrorTelemetry.ERROR_FLUSH_TIMEOUT); - await service.join(); assert.strictEqual(errorStub.callCount, 1); // Test that no file information remains, esp. personal info @@ -447,7 +400,7 @@ suite('TelemetryService', () => { service.dispose(); })); - test('Unexpected Error Telemetry removes PII but preserves Code file path', sinonTestFn(async function (this: any) { + test('Unexpected Error Telemetry removes PII but preserves Code file path', sinonTestFn(function (this: any) { const origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler(); Errors.setUnexpectedErrorHandler(() => { }); @@ -455,7 +408,7 @@ suite('TelemetryService', () => { try { const settings = new ErrorTestingSettings(); const testAppender = new TestTelemetryAppender(); - const service = new JoinableTelemetryService({ appenders: [testAppender] }); + const service = new TestErrorTelemetryService({ appenders: [testAppender] }); const errorTelemetry = new ErrorTelemetry(service); const dangerousPathWithImportantInfoError: any = new Error(settings.dangerousPathWithImportantInfo); @@ -464,7 +417,6 @@ suite('TelemetryService', () => { // Test that important information remains but personal info does not Errors.onUnexpectedError(dangerousPathWithImportantInfoError); this.clock.tick(ErrorTelemetry.ERROR_FLUSH_TIMEOUT); - await service.join(); assert.notStrictEqual(testAppender.events[0].data.msg.indexOf(settings.importantInfo), -1); assert.strictEqual(testAppender.events[0].data.msg.indexOf(settings.personalInfo), -1); @@ -483,19 +435,18 @@ suite('TelemetryService', () => { } })); - test('Uncaught Error Telemetry removes PII but preserves Code file path', sinonTestFn(async function (this: any) { + test('Uncaught Error Telemetry removes PII but preserves Code file path', sinonTestFn(function (this: any) { const errorStub = sinon.stub(); window.onerror = errorStub; const settings = new ErrorTestingSettings(); const testAppender = new TestTelemetryAppender(); - const service = new JoinableTelemetryService({ appenders: [testAppender] }); + const service = new TestErrorTelemetryService({ appenders: [testAppender] }); const errorTelemetry = new ErrorTelemetry(service); const dangerousPathWithImportantInfoError: any = new Error('dangerousPathWithImportantInfo'); dangerousPathWithImportantInfoError.stack = settings.stack; (window.onerror)(settings.dangerousPathWithImportantInfo, 'test.js', 2, 42, dangerousPathWithImportantInfoError); this.clock.tick(ErrorTelemetry.ERROR_FLUSH_TIMEOUT); - await service.join(); assert.strictEqual(errorStub.callCount, 1); // Test that important information remains but personal info does not @@ -516,7 +467,7 @@ suite('TelemetryService', () => { service.dispose(); })); - test('Unexpected Error Telemetry removes PII but preserves Code file path with node modules', sinonTestFn(async function (this: any) { + test('Unexpected Error Telemetry removes PII but preserves Code file path with node modules', sinonTestFn(function (this: any) { const origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler(); Errors.setUnexpectedErrorHandler(() => { }); @@ -524,7 +475,7 @@ suite('TelemetryService', () => { try { const settings = new ErrorTestingSettings(); const testAppender = new TestTelemetryAppender(); - const service = new JoinableTelemetryService({ appenders: [testAppender] }); + const service = new TestErrorTelemetryService({ appenders: [testAppender] }); const errorTelemetry = new ErrorTelemetry(service); const dangerousPathWithImportantInfoError: any = new Error(settings.dangerousPathWithImportantInfo); @@ -533,7 +484,6 @@ suite('TelemetryService', () => { Errors.onUnexpectedError(dangerousPathWithImportantInfoError); this.clock.tick(ErrorTelemetry.ERROR_FLUSH_TIMEOUT); - await service.join(); assert.notStrictEqual(testAppender.events[0].data.callstack.indexOf('(' + settings.nodeModuleAsarPathToRetain), -1); assert.notStrictEqual(testAppender.events[0].data.callstack.indexOf('(' + settings.nodeModulePathToRetain), -1); @@ -548,7 +498,7 @@ suite('TelemetryService', () => { } })); - test('Unexpected Error Telemetry removes PII but preserves Code file path when PIIPath is configured', sinonTestFn(async function (this: any) { + test('Unexpected Error Telemetry removes PII but preserves Code file path when PIIPath is configured', sinonTestFn(function (this: any) { const origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler(); Errors.setUnexpectedErrorHandler(() => { }); @@ -556,7 +506,7 @@ suite('TelemetryService', () => { try { const settings = new ErrorTestingSettings(); const testAppender = new TestTelemetryAppender(); - const service = new JoinableTelemetryService({ appenders: [testAppender], piiPaths: [settings.personalInfo + '/resources/app/'] }); + const service = new TestErrorTelemetryService({ appenders: [testAppender], piiPaths: [settings.personalInfo + '/resources/app/'] }); const errorTelemetry = new ErrorTelemetry(service); const dangerousPathWithImportantInfoError: any = new Error(settings.dangerousPathWithImportantInfo); @@ -565,7 +515,6 @@ suite('TelemetryService', () => { // Test that important information remains but personal info does not Errors.onUnexpectedError(dangerousPathWithImportantInfoError); this.clock.tick(ErrorTelemetry.ERROR_FLUSH_TIMEOUT); - await service.join(); assert.notStrictEqual(testAppender.events[0].data.msg.indexOf(settings.importantInfo), -1); assert.strictEqual(testAppender.events[0].data.msg.indexOf(settings.personalInfo), -1); @@ -584,19 +533,18 @@ suite('TelemetryService', () => { } })); - test('Uncaught Error Telemetry removes PII but preserves Code file path when PIIPath is configured', sinonTestFn(async function (this: any) { + test('Uncaught Error Telemetry removes PII but preserves Code file path when PIIPath is configured', sinonTestFn(function (this: any) { const errorStub = sinon.stub(); window.onerror = errorStub; const settings = new ErrorTestingSettings(); const testAppender = new TestTelemetryAppender(); - const service = new JoinableTelemetryService({ appenders: [testAppender], piiPaths: [settings.personalInfo + '/resources/app/'] }); + const service = new TestErrorTelemetryService({ appenders: [testAppender], piiPaths: [settings.personalInfo + '/resources/app/'] }); const errorTelemetry = new ErrorTelemetry(service); const dangerousPathWithImportantInfoError: any = new Error('dangerousPathWithImportantInfo'); dangerousPathWithImportantInfoError.stack = settings.stack; (window.onerror)(settings.dangerousPathWithImportantInfo, 'test.js', 2, 42, dangerousPathWithImportantInfoError); this.clock.tick(ErrorTelemetry.ERROR_FLUSH_TIMEOUT); - await service.join(); assert.strictEqual(errorStub.callCount, 1); // Test that important information remains but personal info does not @@ -613,7 +561,7 @@ suite('TelemetryService', () => { service.dispose(); })); - test('Unexpected Error Telemetry removes PII but preserves Missing Model error message', sinonTestFn(async function (this: any) { + test('Unexpected Error Telemetry removes PII but preserves Missing Model error message', sinonTestFn(function (this: any) { const origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler(); Errors.setUnexpectedErrorHandler(() => { }); @@ -621,7 +569,7 @@ suite('TelemetryService', () => { try { const settings = new ErrorTestingSettings(); const testAppender = new TestTelemetryAppender(); - const service = new JoinableTelemetryService({ appenders: [testAppender] }); + const service = new TestErrorTelemetryService({ appenders: [testAppender] }); const errorTelemetry = new ErrorTelemetry(service); const missingModelError: any = new Error(settings.missingModelMessage); @@ -631,7 +579,6 @@ suite('TelemetryService', () => { // error message does (Received model events for missing model) Errors.onUnexpectedError(missingModelError); this.clock.tick(ErrorTelemetry.ERROR_FLUSH_TIMEOUT); - await service.join(); assert.notStrictEqual(testAppender.events[0].data.msg.indexOf(settings.missingModelPrefix), -1); assert.strictEqual(testAppender.events[0].data.msg.indexOf(settings.personalInfo), -1); @@ -649,19 +596,18 @@ suite('TelemetryService', () => { } })); - test('Uncaught Error Telemetry removes PII but preserves Missing Model error message', sinonTestFn(async function (this: any) { + test('Uncaught Error Telemetry removes PII but preserves Missing Model error message', sinonTestFn(function (this: any) { const errorStub = sinon.stub(); window.onerror = errorStub; const settings = new ErrorTestingSettings(); const testAppender = new TestTelemetryAppender(); - const service = new JoinableTelemetryService({ appenders: [testAppender] }); + const service = new TestErrorTelemetryService({ appenders: [testAppender] }); const errorTelemetry = new ErrorTelemetry(service); const missingModelError: any = new Error('missingModelMessage'); missingModelError.stack = settings.stack; (window.onerror)(settings.missingModelMessage, 'test.js', 2, 42, missingModelError); this.clock.tick(ErrorTelemetry.ERROR_FLUSH_TIMEOUT); - await service.join(); assert.strictEqual(errorStub.callCount, 1); // Test that no file information remains, but this particular @@ -679,7 +625,7 @@ suite('TelemetryService', () => { service.dispose(); })); - test('Unexpected Error Telemetry removes PII but preserves No Such File error message', sinonTestFn(async function (this: any) { + test('Unexpected Error Telemetry removes PII but preserves No Such File error message', sinonTestFn(function (this: any) { const origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler(); Errors.setUnexpectedErrorHandler(() => { }); @@ -687,7 +633,7 @@ suite('TelemetryService', () => { try { const settings = new ErrorTestingSettings(); const testAppender = new TestTelemetryAppender(); - const service = new JoinableTelemetryService({ appenders: [testAppender] }); + const service = new TestErrorTelemetryService({ appenders: [testAppender] }); const errorTelemetry = new ErrorTelemetry(service); const noSuchFileError: any = new Error(settings.noSuchFileMessage); @@ -697,7 +643,6 @@ suite('TelemetryService', () => { // error message does (ENOENT: no such file or directory) Errors.onUnexpectedError(noSuchFileError); this.clock.tick(ErrorTelemetry.ERROR_FLUSH_TIMEOUT); - await service.join(); assert.notStrictEqual(testAppender.events[0].data.msg.indexOf(settings.noSuchFilePrefix), -1); assert.strictEqual(testAppender.events[0].data.msg.indexOf(settings.personalInfo), -1); @@ -715,7 +660,7 @@ suite('TelemetryService', () => { } })); - test('Uncaught Error Telemetry removes PII but preserves No Such File error message', sinonTestFn(async function (this: any) { + test('Uncaught Error Telemetry removes PII but preserves No Such File error message', sinonTestFn(function (this: any) { const origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler(); Errors.setUnexpectedErrorHandler(() => { }); @@ -724,14 +669,13 @@ suite('TelemetryService', () => { window.onerror = errorStub; const settings = new ErrorTestingSettings(); const testAppender = new TestTelemetryAppender(); - const service = new JoinableTelemetryService({ appenders: [testAppender] }); + const service = new TestErrorTelemetryService({ appenders: [testAppender] }); const errorTelemetry = new ErrorTelemetry(service); const noSuchFileError: any = new Error('noSuchFileMessage'); noSuchFileError.stack = settings.stack; (window.onerror)(settings.noSuchFileMessage, 'test.js', 2, 42, noSuchFileError); this.clock.tick(ErrorTelemetry.ERROR_FLUSH_TIMEOUT); - await service.join(); assert.strictEqual(errorStub.callCount, 1); // Test that no file information remains, but this particular @@ -756,11 +700,9 @@ suite('TelemetryService', () => { test('Telemetry Service sends events when telemetry is on', sinonTestFn(function () { const testAppender = new TestTelemetryAppender(); const service = new TelemetryService({ appenders: [testAppender] }, new TestConfigurationService(), TestProductService); - - return service.publicLog('testEvent').then(() => { - assert.strictEqual(testAppender.getEventsCount(), 1); - service.dispose(); - }); + service.publicLog('testEvent'); + assert.strictEqual(testAppender.getEventsCount(), 1); + service.dispose(); })); test('Telemetry Service checks with config service', function () { diff --git a/src/vs/platform/windows/electron-main/windowImpl.ts b/src/vs/platform/windows/electron-main/windowImpl.ts index 11f16a36bb3..71dd70613eb 100644 --- a/src/vs/platform/windows/electron-main/windowImpl.ts +++ b/src/vs/platform/windows/electron-main/windowImpl.ts @@ -799,13 +799,12 @@ export class CodeWindow extends Disposable implements ICodeWindow { appenders.push(new OneDataSystemAppender(isInternal, 'monacoworkbench', null, this.productService.aiConfig.ariaKey)); } - const { installSourcePath } = this.environmentMainService; const machineId = await resolveMachineId(this.stateService, this.logService); const config: ITelemetryServiceConfig = { appenders, sendErrorTelemetry: false, - commonProperties: resolveCommonProperties(this.fileService, release(), hostname(), process.arch, this.productService.commit, this.productService.version, machineId, isInternal, installSourcePath), + commonProperties: resolveCommonProperties(release(), hostname(), process.arch, this.productService.commit, this.productService.version, machineId, isInternal), piiPaths: getPiiPathsFromEnvironment(this.environmentMainService) }; diff --git a/src/vs/server/node/serverServices.ts b/src/vs/server/node/serverServices.ts index 8f541027962..3384aee71bd 100644 --- a/src/vs/server/node/serverServices.ts +++ b/src/vs/server/node/serverServices.ts @@ -157,7 +157,7 @@ export async function setupServerServices(connectionToken: ServerConnectionToken const config: ITelemetryServiceConfig = { appenders: [oneDsAppender], - commonProperties: resolveCommonProperties(fileService, release(), hostname(), process.arch, productService.commit, productService.version + '-remote', machineId, isInternal, environmentService.installSourcePath, 'remoteAgent'), + commonProperties: resolveCommonProperties(release(), hostname(), process.arch, productService.commit, productService.version + '-remote', machineId, isInternal, 'remoteAgent'), piiPaths: getPiiPathsFromEnvironment(environmentService) }; const initialTelemetryLevelArg = environmentService.args['telemetry-level']; diff --git a/src/vs/workbench/api/common/extHostTelemetry.ts b/src/vs/workbench/api/common/extHostTelemetry.ts index ed382978cd0..a1c1a08e8ee 100644 --- a/src/vs/workbench/api/common/extHostTelemetry.ts +++ b/src/vs/workbench/api/common/extHostTelemetry.ts @@ -7,7 +7,7 @@ import type * as vscode from 'vscode'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Event, Emitter } from 'vs/base/common/event'; import { ExtHostTelemetryShape } from 'vs/workbench/api/common/extHost.protocol'; -import { TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; +import { ICommonProperties, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; import { ILogger, ILoggerService, LogLevel, isLogLevel } from 'vs/platform/log/common/log'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; @@ -94,8 +94,8 @@ export class ExtHostTelemetry extends Disposable implements ExtHostTelemetryShap this.updateLoggerVisibility(); } - getBuiltInCommonProperties(extension: IExtensionDescription): Record { - const commonProperties: Record = {}; + getBuiltInCommonProperties(extension: IExtensionDescription): ICommonProperties { + const commonProperties: ICommonProperties = Object.create(null); // TODO @lramos15, does os info like node arch, platform version, etc exist here. // Or will first party extensions just mix this in commonProperties['common.extname'] = `${extension.publisher}.${extension.name}`; diff --git a/src/vs/workbench/api/test/browser/extHostTelemetry.test.ts b/src/vs/workbench/api/test/browser/extHostTelemetry.test.ts index 92e0cc82c83..262ba48a3ef 100644 --- a/src/vs/workbench/api/test/browser/extHostTelemetry.test.ts +++ b/src/vs/workbench/api/test/browser/extHostTelemetry.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import { URI } from 'vs/base/common/uri'; import { ExtensionIdentifier, IExtensionDescription, TargetPlatform } from 'vs/platform/extensions/common/extensions'; import { DEFAULT_LOG_LEVEL, LogLevel } from 'vs/platform/log/common/log'; -import { ITelemetryInfo, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; +import { TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; import { TestTelemetryLoggerService } from 'vs/platform/telemetry/test/common/telemetryLogAppender.test'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; import { ExtHostTelemetry, ExtHostTelemetryLogger } from 'vs/workbench/api/common/extHostTelemetry'; @@ -38,7 +38,7 @@ suite('ExtHostTelemetry', function () { appUriScheme: 'test', }; - const mockTelemetryInfo: ITelemetryInfo = { + const mockTelemetryInfo = { firstSessionDate: '2020-01-01T00:00:00.000Z', sessionId: 'test', machineId: 'test', @@ -66,7 +66,7 @@ suite('ExtHostTelemetry', function () { const createExtHostTelemetry = () => { const extensionTelemetry = new ExtHostTelemetry(new class extends mock() { override environment: IEnvironment = mockEnvironment; - override telemetryInfo: ITelemetryInfo = mockTelemetryInfo; + override telemetryInfo = mockTelemetryInfo; override remote = mockRemote; }, new TestTelemetryLoggerService(DEFAULT_LOG_LEVEL)); extensionTelemetry.$initializeTelemetryLevel(TelemetryLevel.USAGE, true, { usage: true, error: true }); @@ -235,7 +235,7 @@ suite('ExtHostTelemetry', function () { const loggerService = new TestTelemetryLoggerService(LogLevel.Trace); const extensionTelemetry = new ExtHostTelemetry(new class extends mock() { override environment: IEnvironment = mockEnvironment; - override telemetryInfo: ITelemetryInfo = mockTelemetryInfo; + override telemetryInfo = mockTelemetryInfo; override remote = mockRemote; }, loggerService); extensionTelemetry.$initializeTelemetryLevel(TelemetryLevel.USAGE, true, { usage: true, error: true }); diff --git a/src/vs/workbench/browser/actions/helpActions.ts b/src/vs/workbench/browser/actions/helpActions.ts index d05f5a9e391..1e21d7f548c 100644 --- a/src/vs/workbench/browser/actions/helpActions.ts +++ b/src/vs/workbench/browser/actions/helpActions.ts @@ -168,14 +168,11 @@ class OpenNewsletterSignupUrlAction extends Action2 { }); } - async run(accessor: ServicesAccessor): Promise { + run(accessor: ServicesAccessor) { const productService = accessor.get(IProductService); const openerService = accessor.get(IOpenerService); const telemetryService = accessor.get(ITelemetryService); - - const info = await telemetryService.getTelemetryInfo(); - - openerService.open(URI.parse(`${productService.newsletterSignupUrl}?machineId=${encodeURIComponent(info.machineId)}`)); + openerService.open(URI.parse(`${productService.newsletterSignupUrl}?machineId=${encodeURIComponent(telemetryService.machineId)}`)); } } diff --git a/src/vs/workbench/contrib/debug/common/debugTelemetry.ts b/src/vs/workbench/contrib/debug/common/debugTelemetry.ts index a39c0651c55..000e5f5e6a8 100644 --- a/src/vs/workbench/contrib/debug/common/debugTelemetry.ts +++ b/src/vs/workbench/contrib/debug/common/debugTelemetry.ts @@ -14,7 +14,7 @@ export class DebugTelemetry { @ITelemetryService private readonly telemetryService: ITelemetryService, ) { } - logDebugSessionStart(dbgr: Debugger, launchJsonExists: boolean): Promise { + logDebugSessionStart(dbgr: Debugger, launchJsonExists: boolean) { const extension = dbgr.getMainExtensionDescriptor(); /* __GDPR__ "debugSessionStart" : { @@ -28,7 +28,7 @@ export class DebugTelemetry { "launchJsonExists": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } } */ - return this.telemetryService.publicLog('debugSessionStart', { + this.telemetryService.publicLog('debugSessionStart', { type: dbgr.type, breakpointCount: this.model.getBreakpoints().length, exceptionBreakpoints: this.model.getExceptionBreakpoints(), @@ -39,7 +39,7 @@ export class DebugTelemetry { }); } - logDebugSessionStop(session: IDebugSession, adapterExitEvent: AdapterEndEvent): Promise { + logDebugSessionStop(session: IDebugSession, adapterExitEvent: AdapterEndEvent) { const breakpoints = this.model.getBreakpoints(); @@ -53,7 +53,7 @@ export class DebugTelemetry { "watchExpressionsCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } } */ - return this.telemetryService.publicLog('debugSessionStop', { + this.telemetryService.publicLog('debugSessionStop', { type: session && session.configuration.type, success: adapterExitEvent.emittedStopped || breakpoints.length === 0, sessionLengthInSeconds: adapterExitEvent.sessionLengthInSeconds, diff --git a/src/vs/workbench/contrib/performance/browser/startupTimings.ts b/src/vs/workbench/contrib/performance/browser/startupTimings.ts index 3c4333f78f9..62dc27549f7 100644 --- a/src/vs/workbench/contrib/performance/browser/startupTimings.ts +++ b/src/vs/workbench/contrib/performance/browser/startupTimings.ts @@ -96,9 +96,8 @@ export class BrowserStartupTimings extends StartupTimings implements IWorkbenchC const standardStartupError = await this._isStandardStartup(); const perfBaseline = await this.timerService.perfBaseline; - const { sessionId } = await this.telemetryService.getTelemetryInfo(); const [from, to] = this.environmentService.profDurationMarkers; - const content = `${this.timerService.getDuration(from, to)}\t${this.productService.nameShort}\t${(this.productService.commit || '').slice(0, 10) || '0000000000'}\t${sessionId}\t${standardStartupError === undefined ? 'standard_start' : 'NO_standard_start : ' + standardStartupError}\t${String(perfBaseline).padStart(4, '0')}ms\n`; + const content = `${this.timerService.getDuration(from, to)}\t${this.productService.nameShort}\t${(this.productService.commit || '').slice(0, 10) || '0000000000'}\t${this.telemetryService.sessionId}\t${standardStartupError === undefined ? 'standard_start' : 'NO_standard_start : ' + standardStartupError}\t${String(perfBaseline).padStart(4, '0')}ms\n`; this.logService.info(`[prof-timers] ${content}`); } diff --git a/src/vs/workbench/contrib/performance/electron-sandbox/startupTimings.ts b/src/vs/workbench/contrib/performance/electron-sandbox/startupTimings.ts index b5001a8078b..952b68dc613 100644 --- a/src/vs/workbench/contrib/performance/electron-sandbox/startupTimings.ts +++ b/src/vs/workbench/contrib/performance/electron-sandbox/startupTimings.ts @@ -64,8 +64,7 @@ export class NativeStartupTimings extends StartupTimings implements IWorkbenchCo const perfBaseline = await this._timerService.perfBaseline; if (appendTo) { - const { sessionId } = await this._telemetryService.getTelemetryInfo(); - const content = `${this._timerService.startupMetrics.ellapsed}\t${this._productService.nameShort}\t${(this._productService.commit || '').slice(0, 10) || '0000000000'}\t${sessionId}\t${standardStartupError === undefined ? 'standard_start' : 'NO_standard_start : ' + standardStartupError}\t${String(perfBaseline).padStart(4, '0')}ms\n`; + const content = `${this._timerService.startupMetrics.ellapsed}\t${this._productService.nameShort}\t${(this._productService.commit || '').slice(0, 10) || '0000000000'}\t${this._telemetryService.sessionId}\t${standardStartupError === undefined ? 'standard_start' : 'NO_standard_start : ' + standardStartupError}\t${String(perfBaseline).padStart(4, '0')}ms\n`; await this.appendContent(URI.file(appendTo), content); } diff --git a/src/vs/workbench/contrib/search/test/electron-browser/textsearch.perf.integrationTest.ts b/src/vs/workbench/contrib/search/test/electron-browser/textsearch.perf.integrationTest.ts index 28324a6ebd2..f5418ba1766 100644 --- a/src/vs/workbench/contrib/search/test/electron-browser/textsearch.perf.integrationTest.ts +++ b/src/vs/workbench/contrib/search/test/electron-browser/textsearch.perf.integrationTest.ts @@ -26,7 +26,7 @@ import { ILogService, NullLogService } from 'vs/platform/log/common/log'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService'; import { ClassifiedEvent, IGDPRProperty, OmitMetadata, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings'; -import { ITelemetryInfo, ITelemetryService, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; +import { ITelemetryService, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo'; import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; @@ -177,6 +177,9 @@ class TestTelemetryService implements ITelemetryService { public _serviceBrand: undefined; public telemetryLevel = TelemetryLevel.USAGE; public sendErrorTelemetry = true; + readonly sessionId = 'someValue.sessionId'; + readonly machineId = 'someValue.machineId'; + readonly firstSessionDate = 'someValue.firstSessionDate'; public events: any[] = []; @@ -192,31 +195,21 @@ class TestTelemetryService implements ITelemetryService { public setExperimentProperty(name: string, value: string): void { } - public publicLog(eventName: string, data?: any): Promise { + public publicLog(eventName: string, data?: any) { const event = { name: eventName, data: data }; this.events.push(event); this.emitter.fire(event); - return Promise.resolve(); } public publicLog2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck) { return this.publicLog(eventName, data as any); } - public publicLogError(eventName: string, data?: any): Promise { + public publicLogError(eventName: string, data?: any) { return this.publicLog(eventName, data); } public publicLogError2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck) { return this.publicLogError(eventName, data as any); } - - public getTelemetryInfo(): Promise { - return Promise.resolve({ - instanceId: 'someValue.instanceId', - sessionId: 'someValue.sessionId', - machineId: 'someValue.machineId', - firstSessionDate: 'someValue.firstSessionDate' - }); - } } diff --git a/src/vs/workbench/contrib/surveys/browser/ces.contribution.ts b/src/vs/workbench/contrib/surveys/browser/ces.contribution.ts index 3320a020843..386247aa716 100644 --- a/src/vs/workbench/contrib/surveys/browser/ces.contribution.ts +++ b/src/vs/workbench/contrib/surveys/browser/ces.contribution.ts @@ -83,21 +83,19 @@ class CESContribution extends Disposable implements IWorkbenchContribution { label: button, run: () => { sendTelemetry('accept'); - this.telemetryService.getTelemetryInfo().then(info => { - let surveyUrl = `${this.productService.cesSurveyUrl}?o=${encodeURIComponent(platform)}&v=${encodeURIComponent(this.productService.version)}&m=${encodeURIComponent(info.machineId)}`; + let surveyUrl = `${this.productService.cesSurveyUrl}?o=${encodeURIComponent(platform)}&v=${encodeURIComponent(this.productService.version)}&m=${encodeURIComponent(this.telemetryService.machineId)}`; - const usedParams = this.productService.surveys - ?.filter(surveyData => surveyData.surveyId && surveyData.languageId) - // Counts provided by contrib/surveys/browser/languageSurveys - .filter(surveyData => this.storageService.getNumber(`${surveyData.surveyId}.editedCount`, StorageScope.APPLICATION, 0) > 0) - .map(surveyData => `${encodeURIComponent(surveyData.languageId)}Lang=1`) - .join('&'); - if (usedParams) { - surveyUrl += `&${usedParams}`; - } - this.openerService.open(URI.parse(surveyUrl)); - this.skipSurvey(); - }); + const usedParams = this.productService.surveys + ?.filter(surveyData => surveyData.surveyId && surveyData.languageId) + // Counts provided by contrib/surveys/browser/languageSurveys + .filter(surveyData => this.storageService.getNumber(`${surveyData.surveyId}.editedCount`, StorageScope.APPLICATION, 0) > 0) + .map(surveyData => `${encodeURIComponent(surveyData.languageId)}Lang=1`) + .join('&'); + if (usedParams) { + surveyUrl += `&${usedParams}`; + } + this.openerService.open(URI.parse(surveyUrl)); + this.skipSurvey(); } }, { label: nls.localize('remindLater', "Remind Me later"), @@ -128,8 +126,7 @@ class CESContribution extends Disposable implements IWorkbenchContribution { waitTimeToShowSurvey = timeToRemind; } } else { - const info = await this.telemetryService.getTelemetryInfo(); - const timeFromInstall = Date.now() - new Date(info.firstSessionDate).getTime(); + const timeFromInstall = Date.now() - new Date(this.telemetryService.firstSessionDate).getTime(); const isNewInstall = !isNaN(timeFromInstall) && timeFromInstall < MAX_INSTALL_AGE; // Installation is older than MAX_INSTALL_AGE diff --git a/src/vs/workbench/contrib/surveys/browser/languageSurveys.contribution.ts b/src/vs/workbench/contrib/surveys/browser/languageSurveys.contribution.ts index ae6e3b498bc..300123f2761 100644 --- a/src/vs/workbench/contrib/surveys/browser/languageSurveys.contribution.ts +++ b/src/vs/workbench/contrib/surveys/browser/languageSurveys.contribution.ts @@ -100,11 +100,9 @@ class LanguageSurvey extends Disposable { label: localize('takeShortSurvey', "Take Short Survey"), run: () => { telemetryService.publicLog(`${data.surveyId}.survey/takeShortSurvey`); - telemetryService.getTelemetryInfo().then(info => { - openerService.open(URI.parse(`${data.surveyUrl}?o=${encodeURIComponent(platform)}&v=${encodeURIComponent(productService.version)}&m=${encodeURIComponent(info.machineId)}`)); - storageService.store(IS_CANDIDATE_KEY, false, StorageScope.APPLICATION, StorageTarget.USER); - storageService.store(SKIP_VERSION_KEY, productService.version, StorageScope.APPLICATION, StorageTarget.USER); - }); + openerService.open(URI.parse(`${data.surveyUrl}?o=${encodeURIComponent(platform)}&v=${encodeURIComponent(productService.version)}&m=${encodeURIComponent(telemetryService.machineId)}`)); + storageService.store(IS_CANDIDATE_KEY, false, StorageScope.APPLICATION, StorageTarget.USER); + storageService.store(SKIP_VERSION_KEY, productService.version, StorageScope.APPLICATION, StorageTarget.USER); } }, { label: localize('remindLater', "Remind Me later"), diff --git a/src/vs/workbench/contrib/surveys/browser/nps.contribution.ts b/src/vs/workbench/contrib/surveys/browser/nps.contribution.ts index bb1e79f25e4..bf961d2e22f 100644 --- a/src/vs/workbench/contrib/surveys/browser/nps.contribution.ts +++ b/src/vs/workbench/contrib/surveys/browser/nps.contribution.ts @@ -71,11 +71,9 @@ class NPSContribution implements IWorkbenchContribution { [{ label: nls.localize('takeSurvey', "Take Survey"), run: () => { - telemetryService.getTelemetryInfo().then(info => { - openerService.open(URI.parse(`${productService.npsSurveyUrl}?o=${encodeURIComponent(platform)}&v=${encodeURIComponent(productService.version)}&m=${encodeURIComponent(info.machineId)}`)); - storageService.store(IS_CANDIDATE_KEY, false, StorageScope.APPLICATION, StorageTarget.USER); - storageService.store(SKIP_VERSION_KEY, productService.version, StorageScope.APPLICATION, StorageTarget.USER); - }); + openerService.open(URI.parse(`${productService.npsSurveyUrl}?o=${encodeURIComponent(platform)}&v=${encodeURIComponent(productService.version)}&m=${encodeURIComponent(telemetryService.machineId)}`)); + storageService.store(IS_CANDIDATE_KEY, false, StorageScope.APPLICATION, StorageTarget.USER); + storageService.store(SKIP_VERSION_KEY, productService.version, StorageScope.APPLICATION, StorageTarget.USER); } }, { label: nls.localize('remindLater', "Remind Me later"), diff --git a/src/vs/workbench/contrib/tags/electron-sandbox/workspaceTags.ts b/src/vs/workbench/contrib/tags/electron-sandbox/workspaceTags.ts index 3f8bbf321fd..1a74f3ecbc3 100644 --- a/src/vs/workbench/contrib/tags/electron-sandbox/workspaceTags.ts +++ b/src/vs/workbench/contrib/tags/electron-sandbox/workspaceTags.ts @@ -74,16 +74,15 @@ export class WorkspaceTags implements IWorkbenchContribution { const workspace = this.contextService.getWorkspace(); const state = this.contextService.getWorkbenchState(); const telemetryId = await this.workspaceTagsService.getTelemetryWorkspaceId(workspace, state); - return this.telemetryService.getTelemetryInfo().then(info => { - return { - id: workspace.id, - telemetryId, - rendererSessionId: info.sessionId, - folders: workspace.folders, - transient: workspace.transient, - configuration: workspace.configuration - }; - }); + + return { + id: workspace.id, + telemetryId, + rendererSessionId: this.telemetryService.sessionId, + folders: workspace.folders, + transient: workspace.transient, + configuration: workspace.configuration + }; } private reportWorkspaceTags(tags: Tags): void { diff --git a/src/vs/workbench/services/assignment/common/assignmentService.ts b/src/vs/workbench/services/assignment/common/assignmentService.ts index d3d939253f3..74aa4b09860 100644 --- a/src/vs/workbench/services/assignment/common/assignmentService.ts +++ b/src/vs/workbench/services/assignment/common/assignmentService.ts @@ -83,13 +83,13 @@ export class WorkbenchAssignmentService extends BaseAssignmentService { @IProductService productService: IProductService ) { - super(() => { - return telemetryService.getTelemetryInfo().then(telemetryInfo => { - return telemetryInfo.machineId; - }); - }, configurationService, productService, + super( + telemetryService.machineId, + configurationService, + productService, new WorkbenchAssignmentServiceTelemetry(telemetryService, productService), - new MementoKeyValueStorage(new Memento('experiment.service.memento', storageService))); + new MementoKeyValueStorage(new Memento('experiment.service.memento', storageService)) + ); } protected override get experimentsEnabled(): boolean { diff --git a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts index 1936022d6b1..f8c743176ad 100644 --- a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts +++ b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts @@ -266,7 +266,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost } private async _createExtHostInitData(): Promise { - const [telemetryInfo, initData] = await Promise.all([this._telemetryService.getTelemetryInfo(), this._initDataProvider.getInitData()]); + const initData = await this._initDataProvider.getInitData(); const workspace = this._contextService.getWorkspace(); const deltaExtensions = this.extensions.set(initData.allExtensions, initData.myExtensions); const nlsBaseUrl = this._productService.extensionsGallery?.nlsBaseUrl; @@ -307,7 +307,12 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost activationEvents: deltaExtensions.addActivationEvents, myExtensions: deltaExtensions.myToAdd, nlsBaseUrl: nlsUrlWithDetails, - telemetryInfo, + telemetryInfo: { + sessionId: this._telemetryService.sessionId, + machineId: this._telemetryService.machineId, + firstSessionDate: this._telemetryService.firstSessionDate, + msftInternal: this._telemetryService.msftInternal + }, logLevel: this._logService.getLevel(), loggers: [...this._loggerService.getRegisteredLoggers()], logsLocation: this._extensionHostLogsLocation, diff --git a/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts b/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts index 5f96189fac1..26e269fffd5 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts @@ -8,7 +8,6 @@ import { URI, UriComponents, UriDto } from 'vs/base/common/uri'; import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ILoggerResource, LogLevel } from 'vs/platform/log/common/log'; import { IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver'; -import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry'; export interface IExtensionDescriptionDelta { readonly toRemove: ExtensionIdentifier[]; @@ -31,7 +30,12 @@ export interface IExtensionHostInitData { allExtensions: IExtensionDescription[]; myExtensions: ExtensionIdentifier[]; nlsBaseUrl?: URI; - telemetryInfo: ITelemetryInfo; + telemetryInfo: { + readonly sessionId: string; + readonly machineId: string; + readonly firstSessionDate: string; + readonly msftInternal?: boolean; + }; logLevel: LogLevel; loggers: UriDto[]; logsLocation: URI; diff --git a/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts b/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts index 828e980da68..936c7fbeae7 100644 --- a/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts +++ b/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts @@ -201,7 +201,7 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost { } private async _createExtHostInitData(isExtensionDevelopmentDebug: boolean): Promise { - const [telemetryInfo, remoteInitData] = await Promise.all([this._telemetryService.getTelemetryInfo(), this._initDataProvider.getInitData()]); + const remoteInitData = await this._initDataProvider.getInitData(); const workspace = this._contextService.getWorkspace(); const deltaExtensions = this.extensions.set(remoteInitData.allExtensions, remoteInitData.myExtensions); return { @@ -241,7 +241,12 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost { allExtensions: deltaExtensions.toAdd, activationEvents: deltaExtensions.addActivationEvents, myExtensions: deltaExtensions.myToAdd, - telemetryInfo, + telemetryInfo: { + sessionId: this._telemetryService.sessionId, + machineId: this._telemetryService.machineId, + firstSessionDate: this._telemetryService.firstSessionDate, + msftInternal: this._telemetryService.msftInternal + }, logLevel: this._logService.getLevel(), loggers: [...this._loggerService.getRegisteredLoggers()], logsLocation: remoteInitData.extensionHostLogsPath, diff --git a/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts b/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts index be92316722a..0487d6caca9 100644 --- a/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts @@ -423,7 +423,7 @@ export class NativeLocalProcessExtensionHost implements IExtensionHost { } private async _createExtHostInitData(): Promise { - const [telemetryInfo, initData] = await Promise.all([this._telemetryService.getTelemetryInfo(), this._initDataProvider.getInitData()]); + const initData = await this._initDataProvider.getInitData(); const workspace = this._contextService.getWorkspace(); const deltaExtensions = this.extensions.set(initData.allExtensions, initData.myExtensions); return { @@ -464,7 +464,12 @@ export class NativeLocalProcessExtensionHost implements IExtensionHost { allExtensions: deltaExtensions.toAdd, activationEvents: deltaExtensions.addActivationEvents, myExtensions: deltaExtensions.myToAdd, - telemetryInfo, + telemetryInfo: { + sessionId: this._telemetryService.sessionId, + machineId: this._telemetryService.machineId, + firstSessionDate: this._telemetryService.firstSessionDate, + msftInternal: this._telemetryService.msftInternal + }, logLevel: this._logService.getLevel(), loggers: [...this._loggerService.getRegisteredLoggers()], logsLocation: this._environmentService.extHostLogsPath, diff --git a/src/vs/workbench/services/telemetry/browser/telemetryService.ts b/src/vs/workbench/services/telemetry/browser/telemetryService.ts index 20b8948fa3c..dcd2356e566 100644 --- a/src/vs/workbench/services/telemetry/browser/telemetryService.ts +++ b/src/vs/workbench/services/telemetry/browser/telemetryService.ts @@ -11,7 +11,7 @@ import { IProductService } from 'vs/platform/product/common/productService'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { OneDataSystemWebAppender } from 'vs/platform/telemetry/browser/1dsAppender'; import { ClassifiedEvent, IGDPRProperty, OmitMetadata, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings'; -import { ITelemetryData, ITelemetryInfo, ITelemetryService, TelemetryLevel, TELEMETRY_SETTING_ID } from 'vs/platform/telemetry/common/telemetry'; +import { ITelemetryData, ITelemetryService, TelemetryLevel, TELEMETRY_SETTING_ID } from 'vs/platform/telemetry/common/telemetry'; import { TelemetryLogAppender } from 'vs/platform/telemetry/common/telemetryLogAppender'; import { ITelemetryServiceConfig, TelemetryService as BaseTelemetryService } from 'vs/platform/telemetry/common/telemetryService'; import { getTelemetryLevel, isInternalTelemetry, ITelemetryAppender, NullTelemetryService, supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; @@ -26,6 +26,11 @@ export class TelemetryService extends Disposable implements ITelemetryService { private impl: ITelemetryService = NullTelemetryService; public readonly sendErrorTelemetry = true; + get sessionId(): string { return this.impl.sessionId; } + get machineId(): string { return this.impl.machineId; } + get firstSessionDate(): string { return this.impl.firstSessionDate; } + get msftInternal(): boolean | undefined { return this.impl.msftInternal; } + constructor( @IBrowserWorkbenchEnvironmentService environmentService: IBrowserWorkbenchEnvironmentService, @ILogService logService: ILogService, @@ -88,24 +93,20 @@ export class TelemetryService extends Disposable implements ITelemetryService { return this.impl.telemetryLevel; } - publicLog(eventName: string, data?: ITelemetryData): Promise { - return this.impl.publicLog(eventName, data); + publicLog(eventName: string, data?: ITelemetryData) { + this.impl.publicLog(eventName, data); } publicLog2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck) { - return this.publicLog(eventName, data as ITelemetryData); + this.publicLog(eventName, data as ITelemetryData); } - publicLogError(errorEventName: string, data?: ITelemetryData): Promise { - return this.impl.publicLog(errorEventName, data); + publicLogError(errorEventName: string, data?: ITelemetryData) { + this.impl.publicLog(errorEventName, data); } publicLogError2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck) { - return this.publicLogError(eventName, data as ITelemetryData); - } - - getTelemetryInfo(): Promise { - return this.impl.getTelemetryInfo(); + this.publicLogError(eventName, data as ITelemetryData); } } diff --git a/src/vs/workbench/services/telemetry/browser/workbenchCommonProperties.ts b/src/vs/workbench/services/telemetry/browser/workbenchCommonProperties.ts index 81c10410b03..433dadac1a1 100644 --- a/src/vs/workbench/services/telemetry/browser/workbenchCommonProperties.ts +++ b/src/vs/workbench/services/telemetry/browser/workbenchCommonProperties.ts @@ -8,7 +8,7 @@ import * as Platform from 'vs/base/common/platform'; import * as uuid from 'vs/base/common/uuid'; import { cleanRemoteAuthority } from 'vs/platform/telemetry/common/telemetryUtils'; import { mixin } from 'vs/base/common/objects'; -import { firstSessionDateStorageKey, lastSessionDateStorageKey, machineIdKey } from 'vs/platform/telemetry/common/telemetry'; +import { ICommonProperties, firstSessionDateStorageKey, lastSessionDateStorageKey, machineIdKey } from 'vs/platform/telemetry/common/telemetry'; import { Gesture } from 'vs/base/browser/touch'; /** @@ -20,7 +20,7 @@ function cleanUserAgent(userAgent: string): string { return userAgent.replace(/(\d+\.\d+)(\.\d+)+/g, '$1'); } -export async function resolveWorkbenchCommonProperties( +export function resolveWorkbenchCommonProperties( storageService: IStorageService, commit: string | undefined, version: string | undefined, @@ -29,8 +29,8 @@ export async function resolveWorkbenchCommonProperties( productIdentifier?: string, removeMachineId?: boolean, resolveAdditionalProperties?: () => { [key: string]: any } -): Promise<{ [name: string]: string | boolean | undefined }> { - const result: { [name: string]: string | boolean | undefined } = Object.create(null); +): ICommonProperties { + const result: ICommonProperties = Object.create(null); const firstSessionDate = storageService.get(firstSessionDateStorageKey, StorageScope.APPLICATION)!; const lastSessionDate = storageService.get(lastSessionDateStorageKey, StorageScope.APPLICATION)!; diff --git a/src/vs/workbench/services/telemetry/common/workbenchCommonProperties.ts b/src/vs/workbench/services/telemetry/common/workbenchCommonProperties.ts index 22cdbbf92be..ef142595997 100644 --- a/src/vs/workbench/services/telemetry/common/workbenchCommonProperties.ts +++ b/src/vs/workbench/services/telemetry/common/workbenchCommonProperties.ts @@ -5,26 +5,23 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { resolveCommonProperties } from 'vs/platform/telemetry/common/commonProperties'; -import { firstSessionDateStorageKey, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry'; +import { ICommonProperties, firstSessionDateStorageKey, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry'; import { cleanRemoteAuthority } from 'vs/platform/telemetry/common/telemetryUtils'; import { INodeProcess } from 'vs/base/common/platform'; -import { IFileService } from 'vs/platform/files/common/files'; -export async function resolveWorkbenchCommonProperties( +export function resolveWorkbenchCommonProperties( storageService: IStorageService, - fileService: IFileService, release: string, hostname: string, commit: string | undefined, version: string | undefined, machineId: string, isInternalTelemetry: boolean, - installSourcePath: string, process: INodeProcess, sandboxed: boolean, remoteAuthority?: string -): Promise<{ [name: string]: string | boolean | undefined }> { - const result = await resolveCommonProperties(fileService, release, hostname, process.arch, commit, version, machineId, isInternalTelemetry, installSourcePath); +): ICommonProperties { + const result = resolveCommonProperties(release, hostname, process.arch, commit, version, machineId, isInternalTelemetry); const firstSessionDate = storageService.get(firstSessionDateStorageKey, StorageScope.APPLICATION)!; const lastSessionDate = storageService.get(lastSessionDateStorageKey, StorageScope.APPLICATION)!; diff --git a/src/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts b/src/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts index cbb282e36ed..37d2c1b627c 100644 --- a/src/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts +++ b/src/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ITelemetryService, ITelemetryInfo, ITelemetryData, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; +import { ITelemetryService, ITelemetryData, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; import { supportsTelemetry, NullTelemetryService, getPiiPathsFromEnvironment, isInternalTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -16,7 +16,6 @@ import { resolveWorkbenchCommonProperties } from 'vs/workbench/services/telemetr import { TelemetryService as BaseTelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService'; import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ClassifiedEvent, StrictPropertyCheck, OmitMetadata, IGDPRProperty } from 'vs/platform/telemetry/common/gdprTypings'; -import { IFileService } from 'vs/platform/files/common/files'; import { process } from 'vs/base/parts/sandbox/electron-sandbox/globals'; export class TelemetryService extends Disposable implements ITelemetryService { @@ -26,13 +25,17 @@ export class TelemetryService extends Disposable implements ITelemetryService { private impl: ITelemetryService; public readonly sendErrorTelemetry: boolean; + get sessionId(): string { return this.impl.sessionId; } + get machineId(): string { return this.impl.machineId; } + get firstSessionDate(): string { return this.impl.firstSessionDate; } + get msftInternal(): boolean | undefined { return this.impl.msftInternal; } + constructor( @INativeWorkbenchEnvironmentService environmentService: INativeWorkbenchEnvironmentService, @IProductService productService: IProductService, @ISharedProcessService sharedProcessService: ISharedProcessService, @IStorageService storageService: IStorageService, - @IConfigurationService configurationService: IConfigurationService, - @IFileService fileService: IFileService + @IConfigurationService configurationService: IConfigurationService ) { super(); @@ -41,7 +44,7 @@ export class TelemetryService extends Disposable implements ITelemetryService { const channel = sharedProcessService.getChannel('telemetryAppender'); const config: ITelemetryServiceConfig = { appenders: [new TelemetryAppenderClient(channel)], - commonProperties: resolveWorkbenchCommonProperties(storageService, fileService, environmentService.os.release, environmentService.os.hostname, productService.commit, productService.version, environmentService.machineId, isInternal, environmentService.installSourcePath, process, process.sandboxed, environmentService.remoteAuthority), + commonProperties: resolveWorkbenchCommonProperties(storageService, environmentService.os.release, environmentService.os.hostname, productService.commit, productService.version, environmentService.machineId, isInternal, process, process.sandboxed, environmentService.remoteAuthority), piiPaths: getPiiPathsFromEnvironment(environmentService), sendErrorTelemetry: true }; @@ -62,25 +65,20 @@ export class TelemetryService extends Disposable implements ITelemetryService { return this.impl.telemetryLevel; } - publicLog(eventName: string, data?: ITelemetryData): Promise { - return this.impl.publicLog(eventName, data); + publicLog(eventName: string, data?: ITelemetryData) { + this.impl.publicLog(eventName, data); } publicLog2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck) { - return this.publicLog(eventName, data as ITelemetryData); + this.publicLog(eventName, data as ITelemetryData); } - publicLogError(errorEventName: string, data?: ITelemetryData): Promise { - return this.impl.publicLogError(errorEventName, data); + publicLogError(errorEventName: string, data?: ITelemetryData) { + this.impl.publicLogError(errorEventName, data); } publicLogError2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck) { - return this.publicLogError(eventName, data as ITelemetryData); - } - - - getTelemetryInfo(): Promise { - return this.impl.getTelemetryInfo(); + this.publicLogError(eventName, data as ITelemetryData); } } diff --git a/src/vs/workbench/services/telemetry/test/browser/commonProperties.test.ts b/src/vs/workbench/services/telemetry/test/browser/commonProperties.test.ts index 42640f42bc7..e8eb559e97e 100644 --- a/src/vs/workbench/services/telemetry/test/browser/commonProperties.test.ts +++ b/src/vs/workbench/services/telemetry/test/browser/commonProperties.test.ts @@ -23,7 +23,7 @@ suite('Browser Telemetry - common properties', function () { }; }; - const props = await resolveWorkbenchCommonProperties(testStorageService, commit, version, false, undefined, undefined, false, resolveCommonTelemetryProperties); + const props = resolveWorkbenchCommonProperties(testStorageService, commit, version, false, undefined, undefined, false, resolveCommonTelemetryProperties); assert.ok('commitHash' in props); assert.ok('sessionID' in props); @@ -53,10 +53,10 @@ suite('Browser Telemetry - common properties', function () { }); }; - const props = await resolveWorkbenchCommonProperties(testStorageService, commit, version, false, undefined, undefined, false, resolveCommonTelemetryProperties); + const props = resolveWorkbenchCommonProperties(testStorageService, commit, version, false, undefined, undefined, false, resolveCommonTelemetryProperties); assert.strictEqual(props['userId'], 1); - const props2 = await resolveWorkbenchCommonProperties(testStorageService, commit, version, false, undefined, undefined, false, resolveCommonTelemetryProperties); + const props2 = resolveWorkbenchCommonProperties(testStorageService, commit, version, false, undefined, undefined, false, resolveCommonTelemetryProperties); assert.strictEqual(props2['userId'], 2); }); }); diff --git a/src/vs/workbench/services/telemetry/test/node/commonProperties.test.ts b/src/vs/workbench/services/telemetry/test/node/commonProperties.test.ts index 72d34952e0f..8737d659b49 100644 --- a/src/vs/workbench/services/telemetry/test/node/commonProperties.test.ts +++ b/src/vs/workbench/services/telemetry/test/node/commonProperties.test.ts @@ -4,49 +4,22 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import * as fs from 'fs'; -import { join } from 'vs/base/common/path'; -import { release, tmpdir, hostname } from 'os'; +import { release, hostname } from 'os'; import { resolveWorkbenchCommonProperties } from 'vs/workbench/services/telemetry/common/workbenchCommonProperties'; -import { getRandomTestPath } from 'vs/base/test/node/testUtils'; import { IStorageService, StorageScope, InMemoryStorageService, StorageTarget } from 'vs/platform/storage/common/storage'; -import { Promises } from 'vs/base/node/pfs'; import { timeout } from 'vs/base/common/async'; -import { IFileService } from 'vs/platform/files/common/files'; -import { FileService } from 'vs/platform/files/common/fileService'; -import { NullLogService } from 'vs/platform/log/common/log'; -import { Schemas } from 'vs/base/common/network'; -import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; suite('Telemetry - common properties', function () { - const parentDir = getRandomTestPath(tmpdir(), 'vsctests', 'telemetryservice'); - const installSource = join(parentDir, 'installSource'); - const commit: string = (undefined)!; const version: string = (undefined)!; let testStorageService: IStorageService; - let testFileService: IFileService; - let diskFileSystemProvider: DiskFileSystemProvider; setup(() => { testStorageService = new InMemoryStorageService(); - const logService = new NullLogService(); - testFileService = new FileService(logService); - - diskFileSystemProvider = new DiskFileSystemProvider(logService); - testFileService.registerProvider(Schemas.file, diskFileSystemProvider); }); - teardown(() => { - diskFileSystemProvider.dispose(); - - return Promises.rm(parentDir); - }); - - test('default', async function () { - await Promises.mkdir(parentDir, { recursive: true }); - fs.writeFileSync(installSource, 'my.install.source'); - const props = await resolveWorkbenchCommonProperties(testStorageService, testFileService, release(), hostname(), commit, version, 'someMachineId', false, installSource, process, process.sandboxed); + test('default', function () { + const props = resolveWorkbenchCommonProperties(testStorageService, release(), hostname(), commit, version, 'someMachineId', false, process, process.sandboxed); assert.ok('commitHash' in props); assert.ok('sessionID' in props); assert.ok('timestamp' in props); @@ -59,29 +32,25 @@ suite('Telemetry - common properties', function () { // assert.ok('common.version.renderer' in first.data); assert.ok('common.platformVersion' in props, 'platformVersion'); assert.ok('version' in props); - assert.strictEqual(props['common.source'], 'my.install.source'); assert.ok('common.firstSessionDate' in props, 'firstSessionDate'); assert.ok('common.lastSessionDate' in props, 'lastSessionDate'); // conditional, see below, 'lastSessionDate'ow assert.ok('common.isNewSession' in props, 'isNewSession'); // machine id et al assert.ok('common.machineId' in props, 'machineId'); - fs.unlinkSync(installSource); - const props_1 = await resolveWorkbenchCommonProperties(testStorageService, testFileService, release(), hostname(), commit, version, 'someMachineId', false, installSource, process, process.sandboxed); - assert.ok(!('common.source' in props_1)); }); - test('lastSessionDate when available', async function () { + test('lastSessionDate when available', function () { testStorageService.store('telemetry.lastSessionDate', new Date().toUTCString(), StorageScope.APPLICATION, StorageTarget.MACHINE); - const props = await resolveWorkbenchCommonProperties(testStorageService, testFileService, release(), hostname(), commit, version, 'someMachineId', false, installSource, process, process.sandboxed); + const props = resolveWorkbenchCommonProperties(testStorageService, release(), hostname(), commit, version, 'someMachineId', false, process, process.sandboxed); assert.ok('common.lastSessionDate' in props); // conditional, see below assert.ok('common.isNewSession' in props); assert.strictEqual(props['common.isNewSession'], '0'); }); test('values chance on ask', async function () { - const props = await resolveWorkbenchCommonProperties(testStorageService, testFileService, release(), hostname(), commit, version, 'someMachineId', false, installSource, process, process.sandboxed); + const props = resolveWorkbenchCommonProperties(testStorageService, release(), hostname(), commit, version, 'someMachineId', false, process, process.sandboxed); let value1 = props['common.sequence']; let value2 = props['common.sequence']; assert.ok(value1 !== value2, 'seq');