Skip to content

Commit

Permalink
created isolated app insights client for tests
Browse files Browse the repository at this point in the history
  • Loading branch information
amunger committed Apr 19, 2022
1 parent 261afd9 commit d4dbf27
Show file tree
Hide file tree
Showing 8 changed files with 1,265 additions and 9 deletions.
628 changes: 624 additions & 4 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2299,6 +2299,7 @@
"@vscode/test-electron": "^1.6.1",
"@vscode/test-web": "^0.0.24",
"acorn": "^6.4.1",
"applicationinsights": "^2.3.1",
"babel-polyfill": "^6.26.0",
"bufferutil": "^4.0.6",
"chai": "^4.3.0",
Expand Down
2 changes: 1 addition & 1 deletion src/telemetry/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export function sendTelemetryEvent<P extends IEventNamePropertyMapping, E extend
ex?: Error,
sendOriginalEventWithErrors?: boolean
) {
if (!isTelemetrySupported() || (isTestExecution() && eventName !== Telemetry.RunTest)) {
if (!isTelemetrySupported() || isTestExecution()) {
return;
}
// If stuff is already queued, then queue the rest.
Expand Down
31 changes: 27 additions & 4 deletions src/test/testHooks.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,43 @@
import { Context } from 'mocha';
import { Telemetry } from '../platform/common/constants';
import { sendTelemetryEvent } from '../telemetry';
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';


let telemetryReporter: TelemetryReporter | undefined;

export const rootHooks = {
beforeAll() {
if (!IS_CI_SERVER) {
return;
}

const extensionVersion = extensions.getExtension(JVSC_EXTENSION_ID)?.packageJSON.version;
telemetryReporter = new TelemetryReporter(JVSC_EXTENSION_ID, extensionVersion, AppinsightsKey, true);
},
afterEach(this: Context) {
if (!IS_CI_SERVER) {
return;
}

let result = this.currentTest?.isFailed() ? 'failed' : this.currentTest?.isPassed() ? 'passed' : 'skipped';
if (this.currentTest?.title) {
sendTelemetryEvent(Telemetry.RunTest, this.currentTest?.duration, {
const duration = this.currentTest?.duration;
const measures = typeof duration === 'number' ? { duration: duration } : duration ? duration : undefined;
telemetryReporter?.sendRawTelemetryEvent(Telemetry.RunTest, {
testName: this.currentTest?.title,
testResult: result
});
}, measures);
}
},
afterAll: async function () {
if (!IS_CI_SERVER) {
return;
}

await telemetryReporter?.dispose();
await sleep(2000);
}
};
100 changes: 100 additions & 0 deletions src/test/utils/ciTelemetry/common/baseTelemetryAppender.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/

import { AppenderData, ITelemetryAppender } from './baseTelemetryReporter';

export interface BaseTelemetryClient {
logEvent(eventName: string, data?: AppenderData): void;
logException(exception: Error, data?: AppenderData): void;
flush(): void | Promise<void>;
}

export class BaseTelemetryAppender implements ITelemetryAppender {
private _telemetryClient: BaseTelemetryClient | undefined;
private _clientInitialization: Promise<void> | undefined;

// Queues used to store events until the appender is ready
private _eventQueue: Array<{ eventName: string; data: AppenderData | undefined }> = [];
private _exceptionQueue: Array<{ exception: Error; data: AppenderData | undefined }> = [];

// Necessary information to create a telemetry client
private _clientFactory: (key: string) => Promise<BaseTelemetryClient>;
private _key: string;

constructor(key: string, clientFactory: (key: string) => Promise<BaseTelemetryClient>) {
this._clientFactory = clientFactory;
this._key = key;
this.instantiateAppender();
}

/**
* Sends the event to the passed in telemetry client
* @param eventName The named of the event to log
* @param data The data contanied in the event
*/
logEvent(eventName: string, data?: AppenderData): void {
if (this._telemetryClient) {
this._telemetryClient.logEvent(eventName, data);
}
else{
this._eventQueue.push({ eventName, data });
}
}

/**
* Sends an exception to the passed in telemetry client
* @param exception The exception to collect
* @param data Data associated with the exception
*/
logException(exception: Error, data?: AppenderData): void {
if (this._telemetryClient) {
this._telemetryClient.logException(exception, data);
}
else{
this._exceptionQueue.push({ exception, data });
}
}

/**
* Flushes the buffered telemetry data
*/
async flush(): Promise<void> {
if (this._clientInitialization) {
await this._clientInitialization;
if (this._telemetryClient) {
await this._telemetryClient.flush();
this._telemetryClient = undefined;
}
}
return;
}

/**
* Flushes the queued events that existed before the client was instantiated
*/
private _flushQueues(): void {
this._eventQueue.forEach(({ eventName, data }) => this.logEvent(eventName, data));
this._eventQueue = [];
this._exceptionQueue.forEach(({ exception, data }) => this.logException(exception, data));
this._exceptionQueue = [];
}

/**
* Instantiates the telemetry client to make the appender "active"
*/
instantiateAppender(): void {
if (this._clientInitialization) {
return;
}
// Call the client factory to get the client and then let it know it's instatntiated
this._clientInitialization = this._clientFactory(this._key)
.then((client) => {
this._telemetryClient = client;
this._flushQueues();
})
.catch((err) => {
console.error(err);
});
}
}
Loading

0 comments on commit d4dbf27

Please sign in to comment.