Cleanup some eslint exemptions (#276581)

* Cleanup some eslint exemptions

* Fix test

* More test fix
This commit is contained in:
Logan Ramos
2025-11-10 16:21:14 -05:00
committed by GitHub
parent f15832ecb0
commit 6d5752bd0c
16 changed files with 88 additions and 86 deletions

View File

@@ -249,7 +249,6 @@ export default tseslint.config(
'src/vs/workbench/api/common/extHostNotebookKernels.ts', 'src/vs/workbench/api/common/extHostNotebookKernels.ts',
'src/vs/workbench/api/common/extHostQuickOpen.ts', 'src/vs/workbench/api/common/extHostQuickOpen.ts',
'src/vs/workbench/api/common/extHostRequireInterceptor.ts', 'src/vs/workbench/api/common/extHostRequireInterceptor.ts',
'src/vs/workbench/api/common/extHostTelemetry.ts',
'src/vs/workbench/api/common/extHostTypeConverters.ts', 'src/vs/workbench/api/common/extHostTypeConverters.ts',
'src/vs/workbench/api/common/extHostTypes.ts', 'src/vs/workbench/api/common/extHostTypes.ts',
'src/vs/workbench/api/node/loopbackServer.ts', 'src/vs/workbench/api/node/loopbackServer.ts',
@@ -341,8 +340,6 @@ export default tseslint.config(
'src/vs/workbench/services/preferences/common/preferencesValidation.ts', 'src/vs/workbench/services/preferences/common/preferencesValidation.ts',
'src/vs/workbench/services/remote/common/tunnelModel.ts', 'src/vs/workbench/services/remote/common/tunnelModel.ts',
'src/vs/workbench/services/search/common/textSearchManager.ts', 'src/vs/workbench/services/search/common/textSearchManager.ts',
'src/vs/workbench/services/telemetry/test/browser/commonProperties.test.ts',
'src/vs/workbench/services/telemetry/test/node/commonProperties.test.ts',
'src/vs/workbench/test/browser/workbenchTestServices.ts', 'src/vs/workbench/test/browser/workbenchTestServices.ts',
'test/automation/src/playwrightDriver.ts', 'test/automation/src/playwrightDriver.ts',
'.eslint-plugin-local/**/*', '.eslint-plugin-local/**/*',
@@ -524,18 +521,9 @@ export default tseslint.config(
'src/vs/platform/request/common/requestIpc.ts', 'src/vs/platform/request/common/requestIpc.ts',
'src/vs/platform/request/electron-utility/requestService.ts', 'src/vs/platform/request/electron-utility/requestService.ts',
'src/vs/platform/request/node/proxy.ts', 'src/vs/platform/request/node/proxy.ts',
'src/vs/platform/telemetry/browser/1dsAppender.ts',
'src/vs/platform/telemetry/browser/errorTelemetry.ts', 'src/vs/platform/telemetry/browser/errorTelemetry.ts',
'src/vs/platform/telemetry/common/1dsAppender.ts',
'src/vs/platform/telemetry/common/errorTelemetry.ts', 'src/vs/platform/telemetry/common/errorTelemetry.ts',
'src/vs/platform/telemetry/common/gdprTypings.ts',
'src/vs/platform/telemetry/common/remoteTelemetryChannel.ts', 'src/vs/platform/telemetry/common/remoteTelemetryChannel.ts',
'src/vs/platform/telemetry/common/telemetry.ts',
'src/vs/platform/telemetry/common/telemetryIpc.ts',
'src/vs/platform/telemetry/common/telemetryLogAppender.ts',
'src/vs/platform/telemetry/common/telemetryService.ts',
'src/vs/platform/telemetry/common/telemetryUtils.ts',
'src/vs/platform/telemetry/node/1dsAppender.ts',
'src/vs/platform/telemetry/node/errorTelemetry.ts', 'src/vs/platform/telemetry/node/errorTelemetry.ts',
'src/vs/platform/theme/common/iconRegistry.ts', 'src/vs/platform/theme/common/iconRegistry.ts',
'src/vs/platform/theme/common/tokenClassificationRegistry.ts', 'src/vs/platform/theme/common/tokenClassificationRegistry.ts',

View File

@@ -10,7 +10,7 @@ export class OneDataSystemWebAppender extends AbstractOneDataSystemAppender {
constructor( constructor(
isInternalTelemetry: boolean, isInternalTelemetry: boolean,
eventPrefix: string, eventPrefix: string,
defaultData: { [key: string]: any } | null, defaultData: { [key: string]: unknown } | null,
iKeyOrClientFactory: string | (() => IAppInsightsCore), // allow factory function for testing iKeyOrClientFactory: string | (() => IAppInsightsCore), // allow factory function for testing
) { ) {
super(isInternalTelemetry, eventPrefix, defaultData, iKeyOrClientFactory); super(isInternalTelemetry, eventPrefix, defaultData, iKeyOrClientFactory);

View File

@@ -57,7 +57,7 @@ async function getClient(instrumentationKey: string, addInternalFlag?: boolean,
appInsightsCore.initialize(coreConfig, []); appInsightsCore.initialize(coreConfig, []);
appInsightsCore.addTelemetryInitializer((envelope: any) => { appInsightsCore.addTelemetryInitializer((envelope) => {
// Opt the user out of 1DS data sharing // Opt the user out of 1DS data sharing
envelope['ext'] = envelope['ext'] ?? {}; envelope['ext'] = envelope['ext'] ?? {};
envelope['ext']['web'] = envelope['ext']['web'] ?? {}; envelope['ext']['web'] = envelope['ext']['web'] ?? {};
@@ -84,7 +84,7 @@ export abstract class AbstractOneDataSystemAppender implements ITelemetryAppende
constructor( constructor(
private readonly _isInternalTelemetry: boolean, private readonly _isInternalTelemetry: boolean,
private _eventPrefix: string, private _eventPrefix: string,
private _defaultData: { [key: string]: any } | null, private _defaultData: { [key: string]: unknown } | null,
iKeyOrClientFactory: string | (() => IAppInsightsCore), // allow factory function for testing iKeyOrClientFactory: string | (() => IAppInsightsCore), // allow factory function for testing
private _xhrOverride?: IXHROverride private _xhrOverride?: IXHROverride
) { ) {
@@ -125,20 +125,20 @@ export abstract class AbstractOneDataSystemAppender implements ITelemetryAppende
); );
} }
log(eventName: string, data?: any): void { log(eventName: string, data?: unknown): void {
if (!this._aiCoreOrKey) { if (!this._aiCoreOrKey) {
return; return;
} }
data = mixin(data, this._defaultData); data = mixin(data, this._defaultData);
data = validateTelemetryData(data); const validatedData = validateTelemetryData(data);
const name = this._eventPrefix + '/' + eventName; const name = this._eventPrefix + '/' + eventName;
try { try {
this._withAIClient((aiClient) => { this._withAIClient((aiClient) => {
aiClient.pluginVersionString = data?.properties.version ?? 'Unknown'; aiClient.pluginVersionString = validatedData?.properties.version ?? 'Unknown';
aiClient.track({ aiClient.track({
name, name,
baseData: { name, properties: data?.properties, measurements: data?.measurements } baseData: { name, properties: validatedData?.properties, measurements: validatedData?.measurements }
}); });
}); });
} catch { } } catch { }

View File

@@ -21,7 +21,7 @@ type IGDPRPropertyWithoutMetadata = Omit<IGDPRProperty, 'owner' | 'comment' | 'e
export type OmitMetadata<T> = Omit<T, 'owner' | 'comment' | 'expiration'>; export type OmitMetadata<T> = Omit<T, 'owner' | 'comment' | 'expiration'>;
export type ClassifiedEvent<T extends IGDPRPropertyWithoutMetadata> = { export type ClassifiedEvent<T extends IGDPRPropertyWithoutMetadata> = {
[k in keyof T]: any [k in keyof T]: unknown;
}; };
export type StrictPropertyChecker<TEvent, TClassification, TError> = keyof TEvent extends keyof OmitMetadata<TClassification> ? keyof OmitMetadata<TClassification> extends keyof TEvent ? TEvent : TError : TError; export type StrictPropertyChecker<TEvent, TClassification, TError> = keyof TEvent extends keyof OmitMetadata<TClassification> ? keyof OmitMetadata<TClassification> extends keyof TEvent ? TEvent : TError : TError;

View File

@@ -11,7 +11,7 @@ export const ITelemetryService = createDecorator<ITelemetryService>('telemetrySe
export interface ITelemetryData { export interface ITelemetryData {
from?: string; from?: string;
target?: string; target?: string;
[key: string]: any; [key: string]: string | unknown | undefined;
} }
export interface ITelemetryService { export interface ITelemetryService {

View File

@@ -5,11 +5,12 @@
import { Event } from '../../../base/common/event.js'; import { Event } from '../../../base/common/event.js';
import { IChannel, IServerChannel } from '../../../base/parts/ipc/common/ipc.js'; import { IChannel, IServerChannel } from '../../../base/parts/ipc/common/ipc.js';
import { ITelemetryData } from './telemetry.js';
import { ITelemetryAppender } from './telemetryUtils.js'; import { ITelemetryAppender } from './telemetryUtils.js';
export interface ITelemetryLog { export interface ITelemetryLog {
eventName: string; eventName: string;
data?: any; data?: ITelemetryData;
} }
export class TelemetryAppenderChannel implements IServerChannel { export class TelemetryAppenderChannel implements IServerChannel {
@@ -20,9 +21,9 @@ export class TelemetryAppenderChannel implements IServerChannel {
throw new Error(`Event not found: ${event}`); throw new Error(`Event not found: ${event}`);
} }
call(_: unknown, command: string, { eventName, data }: ITelemetryLog): Promise<any> { call<T>(_: unknown, command: string, { eventName, data }: ITelemetryLog) {
this.appenders.forEach(a => a.log(eventName, data)); this.appenders.forEach(a => a.log(eventName, data ?? {}));
return Promise.resolve(null); return Promise.resolve(null as unknown as T);
} }
} }
@@ -30,7 +31,7 @@ export class TelemetryAppenderClient implements ITelemetryAppender {
constructor(private channel: IChannel) { } constructor(private channel: IChannel) { }
log(eventName: string, data?: any): any { log(eventName: string, data?: unknown): unknown {
this.channel.call('log', { eventName, data }) this.channel.call('log', { eventName, data })
.then(undefined, err => `Failed to log telemetry: ${console.warn(err)}`); .then(undefined, err => `Failed to log telemetry: ${console.warn(err)}`);

View File

@@ -44,7 +44,7 @@ export class TelemetryLogAppender extends Disposable implements ITelemetryAppend
return Promise.resolve(); return Promise.resolve();
} }
log(eventName: string, data: any): void { log(eventName: string, data: unknown): void {
this.logger.trace(`${this.prefix}telemetry/${eventName}`, validateTelemetryData(data)); this.logger.trace(`${this.prefix}telemetry/${eventName}`, validateTelemetryData(data));
} }
} }

View File

@@ -132,13 +132,13 @@ export class TelemetryService implements ITelemetryService {
data = mixin(data, this._experimentProperties); data = mixin(data, this._experimentProperties);
// remove all PII from data // remove all PII from data
data = cleanData(data as Record<string, any>, this._cleanupPatterns); data = cleanData(data, this._cleanupPatterns);
// add common properties // add common properties
data = mixin(data, this._commonProperties); data = mixin(data, this._commonProperties);
// Log to the appenders of sufficient level // Log to the appenders of sufficient level
this._appenders.forEach(a => a.log(eventName, data)); this._appenders.forEach(a => a.log(eventName, data ?? {}));
} }
publicLog(eventName: string, data?: ITelemetryData) { publicLog(eventName: string, data?: ITelemetryData) {

View File

@@ -60,7 +60,7 @@ export const telemetryLogId = 'telemetry';
export const TelemetryLogGroup: LoggerGroup = { id: telemetryLogId, name: localize('telemetryLogName', "Telemetry") }; export const TelemetryLogGroup: LoggerGroup = { id: telemetryLogId, name: localize('telemetryLogName', "Telemetry") };
export interface ITelemetryAppender { export interface ITelemetryAppender {
log(eventName: string, data: any): void; log(eventName: string, data: ITelemetryData): void;
flush(): Promise<void>; flush(): Promise<void>;
} }
@@ -165,12 +165,12 @@ export interface Measurements {
[key: string]: number; [key: string]: number;
} }
export function validateTelemetryData(data?: any): { properties: Properties; measurements: Measurements } { export function validateTelemetryData(data?: unknown): { properties: Properties; measurements: Measurements } {
const properties: Properties = {}; const properties: Properties = {};
const measurements: Measurements = {}; const measurements: Measurements = {};
const flat: Record<string, any> = {}; const flat: Record<string, unknown> = {};
flatten(data, flat); flatten(data, flat);
for (let prop in flat) { for (let prop in flat) {
@@ -193,7 +193,7 @@ export function validateTelemetryData(data?: any): { properties: Properties; mea
properties[prop] = value.substring(0, 8191); properties[prop] = value.substring(0, 8191);
} else if (typeof value !== 'undefined' && value !== null) { } else if (typeof value !== 'undefined' && value !== null) {
properties[prop] = value; properties[prop] = String(value);
} }
} }
@@ -213,13 +213,14 @@ export function cleanRemoteAuthority(remoteAuthority?: string): string {
return telemetryAllowedAuthorities.has(remoteName) ? remoteName : 'other'; return telemetryAllowedAuthorities.has(remoteName) ? remoteName : 'other';
} }
function flatten(obj: any, result: { [key: string]: any }, order: number = 0, prefix?: string): void { function flatten(obj: unknown, result: Record<string, unknown>, order: number = 0, prefix?: string): void {
if (!obj) { if (!obj || (typeof obj !== 'object' && typeof obj !== 'function')) {
return; return;
} }
for (const item of Object.getOwnPropertyNames(obj)) { const source = obj as Record<string, unknown>;
const value = obj[item]; for (const item of Object.getOwnPropertyNames(source)) {
const value = source[item];
const index = prefix ? prefix + item : item; const index = prefix ? prefix + item : item;
if (Array.isArray(value)) { if (Array.isArray(value)) {
@@ -360,7 +361,10 @@ function removePropertiesWithPossibleUserInfo(property: string): string {
* @param paths Any additional patterns that should be removed from the data set * @param paths Any additional patterns that should be removed from the data set
* @returns A new object with the PII removed * @returns A new object with the PII removed
*/ */
export function cleanData(data: Record<string, any>, cleanUpPatterns: RegExp[]): Record<string, any> { export function cleanData(data: ITelemetryData | undefined, cleanUpPatterns: RegExp[]): Record<string, unknown> {
if (!data) {
return {};
}
return cloneAndChange(data, value => { return cloneAndChange(data, value => {
// If it's a trusted value it means it's okay to skip cleaning so we don't clean it // If it's a trusted value it means it's okay to skip cleaning so we don't clean it

View File

@@ -28,7 +28,7 @@ async function makeTelemetryRequest(options: IRequestOptions, requestService: IR
const response = await requestService.request(options, CancellationToken.None); const response = await requestService.request(options, CancellationToken.None);
const responseData = (await streamToBuffer(response.stream)).toString(); const responseData = (await streamToBuffer(response.stream)).toString();
const statusCode = response.res.statusCode ?? 200; const statusCode = response.res.statusCode ?? 200;
const headers = response.res.headers as Record<string, any>; const headers = response.res.headers as Record<string, string>;
return { return {
headers, headers,
statusCode, statusCode,
@@ -51,7 +51,7 @@ async function makeLegacyTelemetryRequest(options: IRequestOptions): Promise<IRe
const req = https.request(options.url ?? '', httpsOptions, res => { const req = https.request(options.url ?? '', httpsOptions, res => {
res.on('data', function (responseData) { res.on('data', function (responseData) {
resolve({ resolve({
headers: res.headers as Record<string, any>, headers: res.headers as Record<string, string>,
statusCode: res.statusCode ?? 200, statusCode: res.statusCode ?? 200,
responseData: responseData.toString() responseData: responseData.toString()
}); });
@@ -100,7 +100,7 @@ export class OneDataSystemAppender extends AbstractOneDataSystemAppender {
requestService: IRequestService | undefined, requestService: IRequestService | undefined,
isInternalTelemetry: boolean, isInternalTelemetry: boolean,
eventPrefix: string, eventPrefix: string,
defaultData: { [key: string]: any } | null, defaultData: { [key: string]: unknown } | null,
iKeyOrClientFactory: string | (() => IAppInsightsCore), // allow factory function for testing iKeyOrClientFactory: string | (() => IAppInsightsCore), // allow factory function for testing
) { ) {
// Override the way events get sent since node doesn't have XHTMLRequest // Override the way events get sent since node doesn't have XHTMLRequest

View File

@@ -13,8 +13,8 @@ export default class ErrorTelemetry extends BaseErrorTelemetry {
// Print a console message when rejection isn't handled within N seconds. For details: // Print a console message when rejection isn't handled within N seconds. For details:
// see https://nodejs.org/api/process.html#process_event_unhandledrejection // see https://nodejs.org/api/process.html#process_event_unhandledrejection
// and https://nodejs.org/api/process.html#process_event_rejectionhandled // and https://nodejs.org/api/process.html#process_event_rejectionhandled
const unhandledPromises: Promise<any>[] = []; const unhandledPromises: Promise<unknown>[] = [];
process.on('unhandledRejection', (reason: any, promise: Promise<any>) => { process.on('unhandledRejection', (reason: unknown, promise: Promise<unknown>) => {
unhandledPromises.push(promise); unhandledPromises.push(promise);
setTimeout(() => { setTimeout(() => {
const idx = unhandledPromises.indexOf(promise); const idx = unhandledPromises.indexOf(promise);
@@ -35,7 +35,7 @@ export default class ErrorTelemetry extends BaseErrorTelemetry {
}, 1000); }, 1000);
}); });
process.on('rejectionHandled', (promise: Promise<any>) => { process.on('rejectionHandled', (promise: Promise<unknown>) => {
const idx = unhandledPromises.indexOf(promise); const idx = unhandledPromises.indexOf(promise);
if (idx >= 0) { if (idx >= 0) {
unhandledPromises.splice(idx, 1); unhandledPromises.splice(idx, 1);

View File

@@ -18,6 +18,11 @@ import { mixin } from '../../../base/common/objects.js';
import { Disposable } from '../../../base/common/lifecycle.js'; import { Disposable } from '../../../base/common/lifecycle.js';
import { localize } from '../../../nls.js'; import { localize } from '../../../nls.js';
type ExtHostTelemetryEventData = Record<string, any> & {
properties?: Record<string, any>;
measurements?: Record<string, number>;
};
export class ExtHostTelemetry extends Disposable implements ExtHostTelemetryShape { export class ExtHostTelemetry extends Disposable implements ExtHostTelemetryShape {
readonly _serviceBrand: undefined; readonly _serviceBrand: undefined;
@@ -210,10 +215,10 @@ export class ExtHostTelemetryLogger {
} }
} }
mixInCommonPropsAndCleanData(data: Record<string, any>): Record<string, any> { mixInCommonPropsAndCleanData(data: ExtHostTelemetryEventData): Record<string, any> {
// Some telemetry modules prefer to break properties and measurmements up // Some telemetry modules prefer to break properties and measurmements up
// We mix common properties into the properties tab. // We mix common properties into the properties tab.
let updatedData = 'properties' in data ? (data.properties ?? {}) : data; let updatedData = data.properties ? (data.properties ?? {}) : data;
// We don't clean measurements since they are just numbers // We don't clean measurements since they are just numbers
updatedData = cleanData(updatedData, []); updatedData = cleanData(updatedData, []);
@@ -226,7 +231,7 @@ export class ExtHostTelemetryLogger {
updatedData = mixin(updatedData, this._commonProperties); updatedData = mixin(updatedData, this._commonProperties);
} }
if ('properties' in data) { if (data.properties) {
data.properties = updatedData; data.properties = updatedData;
} else { } else {
data = updatedData; data = updatedData;
@@ -275,11 +280,11 @@ export class ExtHostTelemetryLogger {
}; };
const cleanedErrorData = cleanData(errorData, []); const cleanedErrorData = cleanData(errorData, []);
// Reconstruct the error object with the cleaned data // Reconstruct the error object with the cleaned data
const cleanedError = new Error(cleanedErrorData.message, { const cleanedError = new Error(typeof cleanedErrorData.message === 'string' ? cleanedErrorData.message : undefined, {
cause: cleanedErrorData.cause cause: cleanedErrorData.cause
}); });
cleanedError.stack = cleanedErrorData.stack; cleanedError.stack = typeof cleanedErrorData.stack === 'string' ? cleanedErrorData.stack : undefined;
cleanedError.name = cleanedErrorData.name; cleanedError.name = typeof cleanedErrorData.name === 'string' ? cleanedErrorData.name : 'unknown';
data = this.mixInCommonPropsAndCleanData(data || {}); data = this.mixInCommonPropsAndCleanData(data || {});
if (!this._inLoggingOnlyMode) { if (!this._inLoggingOnlyMode) {
this._sender.sendErrorData(cleanedError, data); this._sender.sendErrorData(cleanedError, data);

View File

@@ -25,7 +25,7 @@ import { EditorProgressIndicator } from '../../../services/progress/browser/prog
import { localize } from '../../../../nls.js'; import { localize } from '../../../../nls.js';
import { coalesce } from '../../../../base/common/arrays.js'; import { coalesce } from '../../../../base/common/arrays.js';
import { DisposableStore, MutableDisposable, toDisposable } from '../../../../base/common/lifecycle.js'; import { DisposableStore, MutableDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; import { ITelemetryData, ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js';
import { DeferredPromise, Promises, RunOnceWorker } from '../../../../base/common/async.js'; import { DeferredPromise, Promises, RunOnceWorker } from '../../../../base/common/async.js';
import { EventType as TouchEventType, GestureEvent } from '../../../../base/browser/touch.js'; import { EventType as TouchEventType, GestureEvent } from '../../../../base/browser/touch.js';
import { IEditorGroupsView, IEditorGroupView, fillActiveEditorViewState, EditorServiceImpl, IEditorGroupTitleHeight, IInternalEditorOpenOptions, IInternalMoveCopyOptions, IInternalEditorCloseOptions, IInternalEditorTitleControlOptions, IEditorPartsView, IEditorGroupViewOptions } from './editor.js'; import { IEditorGroupsView, IEditorGroupView, fillActiveEditorViewState, EditorServiceImpl, IEditorGroupTitleHeight, IInternalEditorOpenOptions, IInternalMoveCopyOptions, IInternalEditorCloseOptions, IInternalEditorTitleControlOptions, IEditorPartsView, IEditorGroupViewOptions } from './editor.js';
@@ -724,7 +724,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
}; };
} }
private toEditorTelemetryDescriptor(editor: EditorInput): object { private toEditorTelemetryDescriptor(editor: EditorInput): ITelemetryData {
const descriptor = editor.getTelemetryDescriptor(); const descriptor = editor.getTelemetryDescriptor();
const resource = EditorResourceAccessor.getOriginalUri(editor, { supportSideBySide: SideBySideEditor.BOTH }); const resource = EditorResourceAccessor.getOriginalUri(editor, { supportSideBySide: SideBySideEditor.BOTH });

View File

@@ -6,6 +6,7 @@ import assert from 'assert';
import { resolveWorkbenchCommonProperties } from '../../browser/workbenchCommonProperties.js'; import { resolveWorkbenchCommonProperties } from '../../browser/workbenchCommonProperties.js';
import { InMemoryStorageService } from '../../../../../platform/storage/common/storage.js'; import { InMemoryStorageService } from '../../../../../platform/storage/common/storage.js';
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
import { hasKey } from '../../../../../base/common/types.js';
suite('Browser Telemetry - common properties', function () { suite('Browser Telemetry - common properties', function () {
@@ -32,18 +33,19 @@ suite('Browser Telemetry - common properties', function () {
const props = 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(hasKey(props, {
assert.ok('sessionID' in props); commitHash: true,
assert.ok('timestamp' in props); sessionID: true,
assert.ok('common.platform' in props); timestamp: true,
assert.ok('common.timesincesessionstart' in props); 'common.platform': true,
assert.ok('common.sequence' in props); 'common.timesincesessionstart': true,
assert.ok('version' in props); 'common.sequence': true,
assert.ok('common.firstSessionDate' in props, 'firstSessionDate'); version: true,
assert.ok('common.lastSessionDate' in props, 'lastSessionDate'); 'common.firstSessionDate': true,
assert.ok('common.isNewSession' in props, 'isNewSession'); 'common.lastSessionDate': true,
assert.ok('common.machineId' in props, 'machineId'); 'common.isNewSession': true,
'common.machineId': true
}));
assert.strictEqual(props['userId'], '1'); assert.strictEqual(props['userId'], '1');
}); });

View File

@@ -9,6 +9,7 @@ import { resolveWorkbenchCommonProperties } from '../../common/workbenchCommonPr
import { StorageScope, InMemoryStorageService, StorageTarget } from '../../../../../platform/storage/common/storage.js'; import { StorageScope, InMemoryStorageService, StorageTarget } from '../../../../../platform/storage/common/storage.js';
import { timeout } from '../../../../../base/common/async.js'; import { timeout } from '../../../../../base/common/async.js';
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
import { hasKey } from '../../../../../base/common/types.js';
suite('Telemetry - common properties', function () { suite('Telemetry - common properties', function () {
const commit: string = (undefined)!; const commit: string = (undefined)!;
@@ -28,24 +29,25 @@ suite('Telemetry - common properties', function () {
test('default', function () { test('default', function () {
const props = resolveWorkbenchCommonProperties(testStorageService, release(), hostname(), commit, version, 'someMachineId', 'someSqmId', 'somedevDeviceId', false, process, date); const props = resolveWorkbenchCommonProperties(testStorageService, release(), hostname(), commit, version, 'someMachineId', 'someSqmId', 'somedevDeviceId', false, process, date);
assert.ok('commitHash' in props); assert.ok(hasKey(props, {
assert.ok('sessionID' in props); commitHash: true,
assert.ok('timestamp' in props); sessionID: true,
assert.ok('common.platform' in props); timestamp: true,
assert.ok('common.nodePlatform' in props); 'common.platform': true,
assert.ok('common.nodeArch' in props); 'common.nodePlatform': true,
assert.ok('common.timesincesessionstart' in props); 'common.nodeArch': true,
assert.ok('common.sequence' in props); 'common.timesincesessionstart': true,
// assert.ok('common.version.shell' in first.data); // only when running on electron 'common.sequence': true,
// assert.ok('common.version.renderer' in first.data); // 'common.version.shell': true, // only when running on electron
assert.ok('common.platformVersion' in props, 'platformVersion'); // 'common.version.renderer': true,
assert.ok('version' in props); 'common.platformVersion': true,
assert.ok('common.releaseDate' in props); version: true,
assert.ok('common.firstSessionDate' in props, 'firstSessionDate'); 'common.releaseDate': true,
assert.ok('common.lastSessionDate' in props, 'lastSessionDate'); // conditional, see below, 'lastSessionDate'ow 'common.firstSessionDate': true,
assert.ok('common.isNewSession' in props, 'isNewSession'); 'common.lastSessionDate': true,
// machine id et al 'common.isNewSession': true,
assert.ok('common.machineId' in props, 'machineId'); 'common.machineId': true
}));
}); });
test('lastSessionDate when available', function () { test('lastSessionDate when available', function () {
@@ -53,8 +55,8 @@ suite('Telemetry - common properties', function () {
testStorageService.store('telemetry.lastSessionDate', new Date().toUTCString(), StorageScope.APPLICATION, StorageTarget.MACHINE); testStorageService.store('telemetry.lastSessionDate', new Date().toUTCString(), StorageScope.APPLICATION, StorageTarget.MACHINE);
const props = resolveWorkbenchCommonProperties(testStorageService, release(), hostname(), commit, version, 'someMachineId', 'someSqmId', 'somedevDeviceId', false, process, date); const props = resolveWorkbenchCommonProperties(testStorageService, release(), hostname(), commit, version, 'someMachineId', 'someSqmId', 'somedevDeviceId', false, process, date);
assert.ok('common.lastSessionDate' in props); // conditional, see below assert.ok(props['common.lastSessionDate']); // conditional, see below
assert.ok('common.isNewSession' in props); assert.ok(props['common.isNewSession']);
assert.strictEqual(props['common.isNewSession'], '0'); assert.strictEqual(props['common.isNewSession'], '0');
}); });

View File

@@ -11,7 +11,7 @@ import { IUpdateService } from '../../../../platform/update/common/update.js';
import { ILifecycleService, LifecyclePhase } from '../../lifecycle/common/lifecycle.js'; import { ILifecycleService, LifecyclePhase } from '../../lifecycle/common/lifecycle.js';
import { IEditorService } from '../../editor/common/editorService.js'; import { IEditorService } from '../../editor/common/editorService.js';
import { IAccessibilityService } from '../../../../platform/accessibility/common/accessibility.js'; import { IAccessibilityService } from '../../../../platform/accessibility/common/accessibility.js';
import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; import { ITelemetryData, ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js';
import { Barrier, timeout } from '../../../../base/common/async.js'; import { Barrier, timeout } from '../../../../base/common/async.js';
import { IWorkbenchLayoutService } from '../../layout/browser/layoutService.js'; import { IWorkbenchLayoutService } from '../../layout/browser/layoutService.js';
import { IPaneCompositePartService } from '../../panecomposite/browser/panecomposite.js'; import { IPaneCompositePartService } from '../../panecomposite/browser/panecomposite.js';
@@ -644,7 +644,7 @@ export abstract class AbstractTimerService implements ITimerService {
] ]
} }
*/ */
this._telemetryService.publicLog('startupTimeVaried', metrics); this._telemetryService.publicLog('startupTimeVaried', metrics as unknown as ITelemetryData);
} }
protected _shouldReportPerfMarks(): boolean { protected _shouldReportPerfMarks(): boolean {