Initial first run of telemetry output API (#157807)

* Initial first run of telemetry output API

* Add proposed api check
This commit is contained in:
Logan Ramos 2022-08-10 13:26:12 -04:00 committed by GitHub
parent f6a746fc46
commit dbbf24add8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 91 additions and 5 deletions

View file

@ -86,6 +86,7 @@ export interface IEnvironmentService {
// --- telemetry
disableTelemetry: boolean;
telemetryLogResource: URI;
extensionTelemetryLogResource: URI;
serviceMachineIdResource: URI;
// --- Policy

View file

@ -226,6 +226,7 @@ export abstract class AbstractNativeEnvironmentService implements INativeEnviron
@memoize
get telemetryLogResource(): URI { return URI.file(join(this.logsPath, 'telemetry.log')); }
get extensionTelemetryLogResource(): URI { return URI.file(join(this.logsPath, 'extensionTelemetry.log')); }
get disableTelemetry(): boolean { return !!this.args['disable-telemetry']; }
@memoize

View file

@ -24,7 +24,7 @@ export class TelemetryLogAppender extends Disposable implements ITelemetryAppend
this.logger = this._register(logger);
} else {
this.logger = this._register(loggerService.createLogger(environmentService.telemetryLogResource));
this.logger.info('The below are logs for every telemetry event sent from VS Code once the log level is set to trace.');
this.logger.info('Below are logs for every telemetry event sent from VS Code once the log level is set to trace.');
this.logger.info('===========================================================');
}
}

View file

@ -5,6 +5,7 @@
import { Disposable } from 'vs/base/common/lifecycle';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ILogger, ILoggerService } from 'vs/platform/log/common/log';
import { IProductService } from 'vs/platform/product/common/productService';
import { ClassifiedEvent, IGDPRProperty, OmitMetadata, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings';
import { ITelemetryService, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry';
@ -18,14 +19,26 @@ export class MainThreadTelemetry extends Disposable implements MainThreadTelemet
private static readonly _name = 'pluginHostTelemetry';
private readonly _extensionTelemetryLog: ILogger;
constructor(
extHostContext: IExtHostContext,
@ITelemetryService private readonly _telemetryService: ITelemetryService,
@IEnvironmentService private readonly _environmentService: IEnvironmentService,
@IProductService private readonly _productService: IProductService
@IProductService private readonly _productService: IProductService,
@ILoggerService loggerService: ILoggerService,
) {
super();
const logger = loggerService.getLogger(this._environmentService.extensionTelemetryLogResource);
if (logger) {
this._extensionTelemetryLog = this._register(logger);
} else {
this._extensionTelemetryLog = this._register(loggerService.createLogger(this._environmentService.extensionTelemetryLogResource));
this._extensionTelemetryLog.info('Below are logs for extension telemetry events sent to the telemetry output channel API once the log level is set to trace.');
this._extensionTelemetryLog.info('===========================================================');
}
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTelemetry);
if (supportsTelemetry(this._productService, this._environmentService)) {
@ -54,6 +67,11 @@ export class MainThreadTelemetry extends Disposable implements MainThreadTelemet
$publicLog2<E extends ClassifiedEvent<OmitMetadata<T>> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck<T, E>): void {
this.$publicLog(eventName, data as any);
}
$logTelemetryToOutputChannel(eventName: string, data: Record<string, any>) {
this._extensionTelemetryLog.trace(eventName, data);
this._extensionTelemetryLog.flush();
}
}

View file

@ -93,6 +93,7 @@ import { combinedDisposable } from 'vs/base/common/lifecycle';
import { checkProposedApiEnabled, ExtensionIdentifierSet, isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
import { DebugConfigurationProviderTriggerKind } from 'vs/workbench/contrib/debug/common/debug';
import { equalsIgnoreCase } from 'vs/base/common/strings';
import { IExtHostTelemetryLogService } from 'vs/workbench/api/common/extHostTelemetryLogService';
export interface IExtensionRegistries {
mine: ExtensionDescriptionRegistry;
@ -123,6 +124,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostLoggerService = accessor.get(ILoggerService);
const extHostLogService = accessor.get(ILogService);
const extHostTunnelService = accessor.get(IExtHostTunnelService);
const extHostTelemetryLogService = accessor.get(IExtHostTelemetryLogService);
const extHostApiDeprecation = accessor.get(IExtHostApiDeprecationService);
const extHostWindow = accessor.get(IExtHostWindow);
const extHostSecretState = accessor.get(IExtHostSecretState);
@ -795,6 +797,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
get tabGroups(): vscode.TabGroups {
return extHostEditorTabs.tabGroups;
},
logTelemetryToOutputChannel(eventName: string, data: Record<string, any>): void {
checkProposedApiEnabled(extension, 'telemetryLog');
extHostTelemetryLogService.logToTelemetryOutputChannel(extension, eventName, data);
}
};
// namespace: workspace

View file

@ -27,6 +27,7 @@ import { ExtHostLoggerService } from 'vs/workbench/api/common/extHostLoggerServi
import { ILoggerService, ILogService } from 'vs/platform/log/common/log';
import { ExtHostLogService } from 'vs/workbench/api/common/extHostLogService';
import { ExtHostVariableResolverProviderService, IExtHostVariableResolverProvider } from 'vs/workbench/api/common/extHostVariableResolverService';
import { ExtHostTelemetryLogService, IExtHostTelemetryLogService } from 'vs/workbench/api/common/extHostTelemetryLogService';
registerSingleton(ILoggerService, ExtHostLoggerService);
registerSingleton(ILogService, ExtHostLogService);
@ -48,5 +49,6 @@ registerSingleton(IExtHostWindow, ExtHostWindow);
registerSingleton(IExtHostWorkspace, ExtHostWorkspace);
registerSingleton(IExtHostSecretState, ExtHostSecretState);
registerSingleton(IExtHostTelemetry, ExtHostTelemetry);
registerSingleton(IExtHostTelemetryLogService, ExtHostTelemetryLogService);
registerSingleton(IExtHostEditorTabs, ExtHostEditorTabs);
registerSingleton(IExtHostVariableResolverProvider, ExtHostVariableResolverProviderService);

View file

@ -599,6 +599,7 @@ export interface MainThreadStorageShape extends IDisposable {
export interface MainThreadTelemetryShape extends IDisposable {
$publicLog(eventName: string, data?: any): void;
$publicLog2<E extends ClassifiedEvent<OmitMetadata<T>> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck<T, E>): void;
$logTelemetryToOutputChannel(eventName: string, data: Record<string, any>): void;
}
export interface MainThreadEditorInsetsShape extends IDisposable {

View file

@ -0,0 +1,34 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
export interface IExtHostTelemetryLogService {
readonly _serviceBrand: undefined;
logToTelemetryOutputChannel(extension: IExtensionDescription, eventName: string, data: Record<string, any>): void;
}
export const IExtHostTelemetryLogService = createDecorator<IExtHostTelemetryLogService>('IExtHostTelemetryLogService');
export class ExtHostTelemetryLogService implements IExtHostTelemetryLogService {
declare readonly _serviceBrand: undefined;
private readonly _telemetryShape: extHostProtocol.MainThreadTelemetryShape;
constructor(
@IExtHostRpcService rpc: IExtHostRpcService,
) {
this._telemetryShape = rpc.getProxy(extHostProtocol.MainContext.MainThreadTelemetry);
}
public logToTelemetryOutputChannel(extension: IExtensionDescription, eventName: string, data: Record<string, any>): void {
this._telemetryShape.$logTelemetryToOutputChannel(`${extension.identifier.value}/${eventName}`, data);
}
}

View file

@ -8,6 +8,7 @@ export const sharedLogChannelId = 'sharedLog';
export const rendererLogChannelId = 'rendererLog';
export const extHostLogChannelId = 'extHostLog';
export const telemetryLogChannelId = 'telemetryLog';
export const extensionTelemetryLogChannelId = 'extensionTelemetryLog';
export const userDataSyncLogChannelId = 'userDataSyncLog';
export const editSessionsLogChannelId = 'editSessionsSyncLog';

View file

@ -44,6 +44,7 @@ class LogOutputChannels extends Disposable implements IWorkbenchContribution {
const registerTelemetryChannel = () => {
if (supportsTelemetry(this.productService, this.environmentService) && this.logService.getLevel() === LogLevel.Trace) {
this.registerLogChannel(Constants.telemetryLogChannelId, nls.localize('telemetryLog', "Telemetry"), this.environmentService.telemetryLogResource);
this.registerLogChannel(Constants.extensionTelemetryLogChannelId, nls.localize('extensionTelemetryLog', "Extension Telemetry"), this.environmentService.extensionTelemetryLogResource);
return true;
}
return false;

View file

@ -189,6 +189,7 @@ export class BrowserWorkbenchEnvironmentService implements IBrowserWorkbenchEnvi
@memoize
get telemetryLogResource(): URI { return joinPath(this.logsHome, 'telemetry.log'); }
get extensionTelemetryLogResource(): URI { return joinPath(this.logsHome, 'extensionTelemetry.log'); }
@memoize
get disableTelemetry(): boolean { return false; }

View file

@ -58,6 +58,7 @@ export const allApiProposals = Object.freeze({
tabInputTextMerge: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.tabInputTextMerge.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',
telemetryLog: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.telemetryLog.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',
testCoverage: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.testCoverage.d.ts',

View file

@ -9,15 +9,15 @@ declare module 'vscode' {
/**
* Whether or not usage telemetry collection is allowed
*/
isUsageEnabled: boolean;
readonly isUsageEnabled: boolean;
/**
* Whether or not crash error telemetry collection is allowed
*/
isErrorsEnabled: boolean;
readonly isErrorsEnabled: boolean;
/**
* Whether or not crash report collection is allowed
*/
isCrashEnabled: boolean;
readonly isCrashEnabled: boolean;
}
export namespace env {

View file

@ -0,0 +1,19 @@
/*---------------------------------------------------------------------------------------------
* 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 namespace window {
/**
* Logs a telemetry event to a shared extension output channel when the log level is set to trace.
* This is similar in function to cores' telemetry output channel that can be seen when log level is set to trace.
* Extension authors should only log to the output channel when sending telemetry.
*
* @param eventName The name of the telemetry event
* @param data The data associated with the telemetry event
*/
export function logTelemetryToOutputChannel(eventName: string, data: Record<string, any>): void;
}
}