diff --git a/src/vs/workbench/api/browser/mainThreadTelemetry.ts b/src/vs/workbench/api/browser/mainThreadTelemetry.ts index 0a70e6ac9fe..fcb15e9bde9 100644 --- a/src/vs/workbench/api/browser/mainThreadTelemetry.ts +++ b/src/vs/workbench/api/browser/mainThreadTelemetry.ts @@ -19,42 +19,34 @@ export class MainThreadTelemetry extends Disposable implements MainThreadTelemet private static readonly _name = 'pluginHostTelemetry'; - private _oldTelemetryEnabledValue: boolean | undefined; - constructor( extHostContext: IExtHostContext, @ITelemetryService private readonly _telemetryService: ITelemetryService, @IConfigurationService private readonly _configurationService: IConfigurationService, - @IEnvironmentService private readonly _environmenService: IEnvironmentService, + @IEnvironmentService private readonly _environmentService: IEnvironmentService, @IProductService private readonly _productService: IProductService ) { super(); this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTelemetry); - if (supportsTelemetry(this._productService, this._environmenService)) { + if (supportsTelemetry(this._productService, this._environmentService)) { this._register(this._configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration(TELEMETRY_SETTING_ID) || e.affectsConfiguration(TELEMETRY_OLD_SETTING_ID)) { - const telemetryEnabled = this.telemetryEnabled; - // Since changing telemetryLevel from "off" => "error" doesn't change the isEnabled state - // We shouldn't fire a change event - if (telemetryEnabled !== this._oldTelemetryEnabledValue) { - this._oldTelemetryEnabledValue = telemetryEnabled; - this._proxy.$onDidChangeTelemetryEnabled(this.telemetryEnabled); - } + this._proxy.$onDidChangeTelemetryLevel(this.telemetryLevel); } })); } - this._proxy.$initializeTelemetryEnabled(this.telemetryEnabled); + this._proxy.$initializeTelemetryLevel(this.telemetryLevel); } - private get telemetryEnabled(): boolean { - if (!supportsTelemetry(this._productService, this._environmenService)) { - return false; + private get telemetryLevel(): TelemetryLevel { + if (!supportsTelemetry(this._productService, this._environmentService)) { + return TelemetryLevel.NONE; } - return getTelemetryLevel(this._configurationService) === TelemetryLevel.USAGE; + return getTelemetryLevel(this._configurationService); } $publicLog(eventName: string, data: any = Object.create(null)): void { diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 3f432a8d941..0a158227add 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -303,11 +303,19 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I return extHostTerminalService.getDefaultShell(false); }, get isTelemetryEnabled() { - return extHostTelemetry.getTelemetryEnabled(); + return extHostTelemetry.getTelemetryConfiguration(); }, get onDidChangeTelemetryEnabled(): Event { return extHostTelemetry.onDidChangeTelemetryEnabled; }, + get telemetryConfiguration(): vscode.TelemetryConfiguration { + checkProposedApiEnabled(extension, 'telemetry'); + return extHostTelemetry.getTelemetryDetails(); + }, + get onDidChangeTelemetryConfiguration(): Event { + checkProposedApiEnabled(extension, 'telemetry'); + return extHostTelemetry.onDidChangeTelemetryConfiguration; + }, get isNewAppInstall() { const installAge = Date.now() - new Date(initData.telemetryInfo.firstSessionDate).getTime(); return isNaN(installAge) ? false : installAge < 1000 * 60 * 60 * 24; // install age is less than a day diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index f28f9c6adee..624036b6100 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -36,7 +36,7 @@ import * as quickInput from 'vs/platform/quickinput/common/quickInput'; import { IRemoteConnectionData, RemoteAuthorityResolverErrorCode, ResolverResult, TunnelDescription } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { ProvidedPortAttributes, TunnelCreationOptions, TunnelOptions, TunnelProviderFeatures } from 'vs/platform/remote/common/tunnel'; import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings'; -import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry'; +import { ITelemetryInfo, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; import { ICreateContributedTerminalProfileOptions, IProcessProperty, IShellLaunchConfigDto, ITerminalEnvironment, ITerminalLaunchError, ITerminalProfile, TerminalLocation } from 'vs/platform/terminal/common/terminal'; import { ThemeColor, ThemeIcon } from 'vs/platform/theme/common/themeService'; import { IExtensionIdWithVersion } from 'vs/platform/extensionManagement/common/extensionStorage'; @@ -1723,8 +1723,8 @@ export interface ExtHostQuickOpenShape { } export interface ExtHostTelemetryShape { - $initializeTelemetryEnabled(enabled: boolean): void; - $onDidChangeTelemetryEnabled(enabled: boolean): void; + $initializeTelemetryLevel(level: TelemetryLevel): void; + $onDidChangeTelemetryLevel(level: TelemetryLevel): void; } export interface ITerminalLinkDto { diff --git a/src/vs/workbench/api/common/extHostTelemetry.ts b/src/vs/workbench/api/common/extHostTelemetry.ts index 2d14c450b17..5136b494011 100644 --- a/src/vs/workbench/api/common/extHostTelemetry.ts +++ b/src/vs/workbench/api/common/extHostTelemetry.ts @@ -6,24 +6,42 @@ 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 type { TelemetryConfiguration } from 'vscode'; export class ExtHostTelemetry implements ExtHostTelemetryShape { private readonly _onDidChangeTelemetryEnabled = new Emitter(); readonly onDidChangeTelemetryEnabled: Event = this._onDidChangeTelemetryEnabled.event; - private _enabled: boolean = false; + private readonly _onDidChangeTelemetryConfiguration = new Emitter(); + readonly onDidChangeTelemetryConfiguration: Event = this._onDidChangeTelemetryConfiguration.event; - getTelemetryEnabled(): boolean { - return this._enabled; + private _level: TelemetryLevel = TelemetryLevel.NONE; + private _oldTelemetryEnablement: boolean | undefined; + + getTelemetryConfiguration(): boolean { + return this._level === TelemetryLevel.USAGE; } - $initializeTelemetryEnabled(enabled: boolean): void { - this._enabled = enabled; + getTelemetryDetails(): TelemetryConfiguration { + return { + isCrashEnabled: this._level >= TelemetryLevel.CRASH, + isErrorsEnabled: this._level >= TelemetryLevel.ERROR, + isUsageEnabled: this._level >= TelemetryLevel.USAGE + }; } - $onDidChangeTelemetryEnabled(enabled: boolean): void { - this._enabled = enabled; - this._onDidChangeTelemetryEnabled.fire(enabled); + $initializeTelemetryLevel(level: TelemetryLevel): void { + this._level = level; + } + + $onDidChangeTelemetryLevel(level: TelemetryLevel): void { + this._oldTelemetryEnablement = this.getTelemetryConfiguration(); + this._level = level; + if (this._oldTelemetryEnablement !== this.getTelemetryConfiguration()) { + this._onDidChangeTelemetryEnabled.fire(this.getTelemetryConfiguration()); + } + this._onDidChangeTelemetryConfiguration.fire(this.getTelemetryDetails()); } } diff --git a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts index ca0a04329d4..61dd94aa285 100644 --- a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts +++ b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts @@ -49,6 +49,7 @@ export const allApiProposals = Object.freeze({ scmValidation: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.scmValidation.d.ts', tabs: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.tabs.d.ts', taskPresentationGroup: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.taskPresentationGroup.d.ts', + telemetry: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.telemetry.d.ts', terminalDataWriteEvent: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalDataWriteEvent.d.ts', terminalDimensions: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalDimensions.d.ts', terminalDisablePersistence: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalDisablePersistence.d.ts', diff --git a/src/vscode-dts/vscode.proposed.telemetry.d.ts b/src/vscode-dts/vscode.proposed.telemetry.d.ts new file mode 100644 index 00000000000..cf068a7814e --- /dev/null +++ b/src/vscode-dts/vscode.proposed.telemetry.d.ts @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module 'vscode' { + + export interface TelemetryConfiguration { + /** + * Whether or not usage telemetry collection is allowed + */ + isUsageEnabled: boolean; + /** + * Whether or not crash error telemetry collection is allowed + */ + isErrorsEnabled: boolean; + /** + * Whether or not crash report collection is allowed + */ + isCrashEnabled: boolean; + } + + export namespace env { + /** + * Indicates what telemetry is enabled / disabled + * Can be observed to determine what telemetry the extension is allowed to send + */ + export const telemetryConfiguration: TelemetryConfiguration; + + /** + * An {@link Event} which fires when the collectable state of telemetry changes + * Returns a {@link TelemetryConfiguration} object + */ + export const onDidChangeTelemetryConfiguration: Event; + } +}