diff --git a/src/test/testHooks.ts b/src/test/testHooks.ts index 20e7a601ba06..5fbccc556e5f 100644 --- a/src/test/testHooks.ts +++ b/src/test/testHooks.ts @@ -2,11 +2,10 @@ import { Context } from 'mocha'; import { AppinsightsKey, JVSC_EXTENSION_ID, Telemetry } from '../platform/common/constants'; import { IS_CI_SERVER } from './ciConstants.node'; import { extensions } from 'vscode'; -import TelemetryReporter from './utils/ciTelemetry/node/telemetryReporter.node'; import { sleep } from './core'; +import { CiTelemetryReporter } from './utils/ciTelemetry/ciTelemetryReporter.node'; - -let telemetryReporter: TelemetryReporter | undefined; +let telemetryReporter: CiTelemetryReporter | undefined; export const rootHooks = { beforeAll() { @@ -15,7 +14,7 @@ export const rootHooks = { } const extensionVersion = extensions.getExtension(JVSC_EXTENSION_ID)?.packageJSON.version; - telemetryReporter = new TelemetryReporter(JVSC_EXTENSION_ID, extensionVersion, AppinsightsKey, true); + telemetryReporter = new CiTelemetryReporter(JVSC_EXTENSION_ID, extensionVersion, AppinsightsKey, true); }, afterEach(this: Context) { if (!IS_CI_SERVER) { @@ -36,7 +35,7 @@ export const rootHooks = { if (!IS_CI_SERVER) { return; } - + await telemetryReporter?.dispose(); await sleep(2000); } diff --git a/src/test/utils/ciTelemetry/common/baseTelemetryAppender.ts b/src/test/utils/ciTelemetry/TelemetryAppender.ts similarity index 94% rename from src/test/utils/ciTelemetry/common/baseTelemetryAppender.ts rename to src/test/utils/ciTelemetry/TelemetryAppender.ts index c5aa5ab5e01c..644822b00c32 100644 --- a/src/test/utils/ciTelemetry/common/baseTelemetryAppender.ts +++ b/src/test/utils/ciTelemetry/TelemetryAppender.ts @@ -2,7 +2,7 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ -import { AppenderData, ITelemetryAppender } from './baseTelemetryReporter'; +import { AppenderData, ITelemetryAppender } from './baseCiTelemetryReporter'; export interface BaseTelemetryClient { logEvent(eventName: string, data?: AppenderData): void; @@ -10,7 +10,7 @@ export interface BaseTelemetryClient { flush(): void | Promise; } -export class BaseTelemetryAppender implements ITelemetryAppender { +export class TelemetryAppender implements ITelemetryAppender { private _telemetryClient: BaseTelemetryClient | undefined; private _clientInitialization: Promise | undefined; @@ -36,8 +36,7 @@ export class BaseTelemetryAppender implements ITelemetryAppender { logEvent(eventName: string, data?: AppenderData): void { if (this._telemetryClient) { this._telemetryClient.logEvent(eventName, data); - } - else{ + } else { this._eventQueue.push({ eventName, data }); } } @@ -50,8 +49,7 @@ export class BaseTelemetryAppender implements ITelemetryAppender { logException(exception: Error, data?: AppenderData): void { if (this._telemetryClient) { this._telemetryClient.logException(exception, data); - } - else{ + } else { this._exceptionQueue.push({ exception, data }); } } diff --git a/src/test/utils/ciTelemetry/node/telemetryReporter.node.ts b/src/test/utils/ciTelemetry/appInsightsClientFactory.node.ts similarity index 74% rename from src/test/utils/ciTelemetry/node/telemetryReporter.node.ts rename to src/test/utils/ciTelemetry/appInsightsClientFactory.node.ts index eb952317f59d..008489a0ed49 100644 --- a/src/test/utils/ciTelemetry/node/telemetryReporter.node.ts +++ b/src/test/utils/ciTelemetry/appInsightsClientFactory.node.ts @@ -1,12 +1,7 @@ -/*--------------------------------------------------------- - * Copyright (C) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------*/ - -import * as os from "os"; +import { TelemetryClient } from 'applicationinsights'; +import { BaseTelemetryClient } from './TelemetryAppender'; +import { AppenderData } from './baseCiTelemetryReporter'; import * as vscode from "vscode"; -import type { TelemetryClient } from "applicationinsights"; -import { AppenderData, BaseTelemetryReporter } from "../common/baseTelemetryReporter"; -import { BaseTelemetryAppender, BaseTelemetryClient } from "../common/baseTelemetryAppender"; /** * A factory function which creates a telemetry client to be used by an appender to send telemetry in a node application. @@ -17,7 +12,7 @@ import { BaseTelemetryAppender, BaseTelemetryClient } from "../common/baseTeleme * * @returns A promise which resolves to the telemetry client or rejects upon error */ -const appInsightsClientFactory = async (key: string): Promise => { +export async function appInsightsClientFactory (key: string): Promise { let appInsightsClient: TelemetryClient | undefined; try { process.env["APPLICATION_INSIGHTS_NO_DIAGNOSTIC_CHANNEL"] = "1"; @@ -88,17 +83,3 @@ const appInsightsClientFactory = async (key: string): Promise appInsightsClientFactory(key)); - if (key && key.indexOf("AIF-") === 0) { - firstParty = true; - } - super(extensionId, extensionVersion, appender, { - release: os.release(), - platform: os.platform(), - architecture: os.arch(), - }, firstParty); - } -} diff --git a/src/test/utils/ciTelemetry/common/baseTelemetryReporter.ts b/src/test/utils/ciTelemetry/baseCiTelemetryReporter.ts similarity index 97% rename from src/test/utils/ciTelemetry/common/baseTelemetryReporter.ts rename to src/test/utils/ciTelemetry/baseCiTelemetryReporter.ts index da9fbca56268..d45b86d17ba9 100644 --- a/src/test/utils/ciTelemetry/common/baseTelemetryReporter.ts +++ b/src/test/utils/ciTelemetry/baseCiTelemetryReporter.ts @@ -3,7 +3,6 @@ *--------------------------------------------------------*/ import * as vscode from "vscode"; -import { RawTelemetryEventProperties, TelemetryEventMeasurements, TelemetryEventProperties } from '../telemetryReporter'; export interface AppenderData { @@ -17,6 +16,19 @@ export interface ITelemetryAppender { instantiateAppender(): void; } +export interface TelemetryEventProperties { + readonly [key: string]: string; +} + +export interface RawTelemetryEventProperties { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + readonly [key: string]: any; +} + +export interface TelemetryEventMeasurements { + readonly [key: string]: number; +} + export class BaseTelemetryReporter { private userOptIn = true; diff --git a/src/test/utils/ciTelemetry/ciTelemetryReporter.node.ts b/src/test/utils/ciTelemetry/ciTelemetryReporter.node.ts new file mode 100644 index 000000000000..bdd0994fa955 --- /dev/null +++ b/src/test/utils/ciTelemetry/ciTelemetryReporter.node.ts @@ -0,0 +1,32 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + +import * as os from 'os'; +import { BaseTelemetryReporter } from './baseCiTelemetryReporter'; +import { TelemetryAppender } from './TelemetryAppender'; +import { appInsightsClientFactory } from './appInsightsClientFactory.node'; + +/** + * An isolated wrapper for an Application Insights client that is specifically for sending telemetry during CI jobs. + * This won't run on a users machine, so there is no need to check for opt-in status. + */ +export class CiTelemetryReporter extends BaseTelemetryReporter { + constructor(extensionId: string, extensionVersion: string, key: string, firstParty: boolean) { + const appender = new TelemetryAppender(key, (key) => appInsightsClientFactory(key)); + if (key && key.indexOf('AIF-') === 0) { + firstParty = true; + } + super( + extensionId, + extensionVersion, + appender, + { + release: os.release(), + platform: os.platform(), + architecture: os.arch() + }, + firstParty + ); + } +} diff --git a/src/test/utils/ciTelemetry/telemetryReporter.d.ts b/src/test/utils/ciTelemetry/telemetryReporter.d.ts deleted file mode 100644 index ffda688e7675..000000000000 --- a/src/test/utils/ciTelemetry/telemetryReporter.d.ts +++ /dev/null @@ -1,88 +0,0 @@ -/*--------------------------------------------------------- - * Copyright (C) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------*/ - -export interface TelemetryEventProperties { - readonly [key: string]: string; -} - -export interface RawTelemetryEventProperties { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - readonly [key: string]: any; -} - -export interface TelemetryEventMeasurements { - readonly [key: string]: number; -} - -/** - * A replacement option for the app insights client. This allows the appender to filter out any sensitive or unnecessary information from the telemetry server. - */ - export interface ReplacementOption { - - /** - * A regular expression matching any property to be removed or replaced from the telemetry server. - */ - lookup: RegExp; - - /** - * The replacement value for the property. If not present or undefined, the property will be removed. - */ - replacementString?: string; -} - -export default class TelemetryReporter { - /** - * @param extensionId The id of your extension - * @param extensionVersion The version of your extension - * @param key The app insights key - * @param firstParty Whether or not the telemetry is first party (i.e from Microsoft / GitHub) - * @param replacementOptions A list of replacement options for the app insights client. This allows the appender to filter out any sensitive or unnecessary information from the telemetry server. - */ - constructor(extensionId: string, extensionVersion: string, key: string, firstParty?: boolean, replacementOptions?: ReplacementOption[]); - - /** - * A string representation of the current level of telemetry being collected - */ - telemetryLevel: 'all' | 'error' | 'crash' | 'off'; - - /** - * Sends a telemetry event with the given properties and measurements - * Properties are sanitized on best-effort basis to remove sensitive data prior to sending. - * @param eventName The name of the event - * @param properties The set of properties to add to the event in the form of a string key value pair - * @param measurements The set of measurements to add to the event in the form of a string key number value pair - */ - sendTelemetryEvent(eventName: string, properties?: TelemetryEventProperties, measurements?: TelemetryEventMeasurements): void; - - /** - * Sends a raw (unsanitized) telemetry event with the given properties and measurements - * @param eventName The name of the event - * @param properties The set of properties to add to the event in the form of a string key value pair - * @param measurements The set of measurements to add to the event in the form of a string key number value pair - */ - sendRawTelemetryEvent(eventName: string, properties?: RawTelemetryEventProperties, measurements?: TelemetryEventMeasurements): void; - - /** - * Sends a telemetry error event with the given properties, measurements, and errorProps - * @param eventName The name of the event - * @param properties The set of properties to add to the event in the form of a string key value pair - * @param measurements The set of measurements to add to the event in the form of a string key number value pair - * @param errorProps A list of case sensitive properties to drop, if excluded we drop all properties but still send the event - */ - sendTelemetryErrorEvent(eventName: string, properties?: TelemetryEventProperties, measurements?: TelemetryEventMeasurements, errorProps?: string[]): void; - - /** - * Sends an exception which includes the error stack, properties, and measurements - * @param error The error to send - * @param properties The set of properties to add to the event in the form of a string key value pair - * @param measurements The set of measurements to add to the event in the form of a string key number value pair - */ - sendTelemetryException(error: Error, properties?: TelemetryEventProperties, measurements?: TelemetryEventMeasurements): void; - - /** - * Disposes of the telemetry reporter. This flushes the remaining events and disposes of the telemetry client. - */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - dispose(): Promise; -}