1DS appender for the web (#152489)

* 1ds web appender

* Start testing web
This commit is contained in:
Logan Ramos 2022-06-17 15:10:04 -04:00 committed by GitHub
parent dea813ff7c
commit 0edb88f3b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 144 additions and 6 deletions

View file

@ -227,8 +227,6 @@
"@vscode/ripgrep",
"@vscode/iconv-lite-umd",
"applicationinsights",
"@microsoft/1ds-core-js",
"@microsoft/1ds-post-js",
"assert",
"child_process",
"console",
@ -332,7 +330,9 @@
"vs/base/~",
"vs/base/parts/*/~",
"vs/platform/*/~",
"tas-client-umd" // node module allowed even in /common/
"tas-client-umd", // node module allowed even in /common/
"@microsoft/1ds-core-js",// node module allowed even in /common/
"@microsoft/1ds-post-js" // node module allowed even in /common/
]
},
{

View file

@ -0,0 +1,128 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import type { AppInsightsCore, IExtendedConfiguration } from '@microsoft/1ds-core-js';
import type { PostChannel } from '@microsoft/1ds-post-js';
import { onUnexpectedError } from 'vs/base/common/errors';
import { mixin } from 'vs/base/common/objects';
import { ITelemetryAppender, validateTelemetryData } from 'vs/platform/telemetry/common/telemetryUtils';
const endpointUrl = 'https://mobile.events.data.microsoft.com/OneCollector/1.0';
async function getClient(instrumentationKey: string): Promise<AppInsightsCore> {
const oneDs = await import('@microsoft/1ds-core-js');
const postPlugin = await import('@microsoft/1ds-post-js');
const appInsightsCore = new oneDs.AppInsightsCore();
const collectorChannelPlugin: PostChannel = new postPlugin.PostChannel();
// Configure the app insights core to send to collector++ and disable logging of debug info
const coreConfig: IExtendedConfiguration = {
instrumentationKey,
endpointUrl,
loggingLevelTelemetry: 0,
loggingLevelConsole: 0,
disableCookiesUsage: true,
disableDbgExt: true,
disableInstrumentationKeyValidation: true,
channels: [[
collectorChannelPlugin
]]
};
appInsightsCore.initialize(coreConfig, []);
appInsightsCore.addTelemetryInitializer((envelope) => {
if (envelope.tags) {
// Sets it to be internal only based on Windows UTC flagging
envelope.tags['utc.flags'] = 0x0000811ECD;
}
});
return appInsightsCore;
}
// TODO @lramos15 maybe make more in line with src/vs/platform/telemetry/browser/appInsightsAppender.ts with caching support
export class OneDataSystemWebAppender implements ITelemetryAppender {
private _aiCoreOrKey: AppInsightsCore | string | undefined;
private _asyncAiCore: Promise<AppInsightsCore> | null;
constructor(
private _eventPrefix: string,
private _defaultData: { [key: string]: any } | null,
iKeyOrClientFactory: string | (() => AppInsightsCore), // allow factory function for testing
) {
if (!this._defaultData) {
this._defaultData = Object.create(null);
}
if (typeof iKeyOrClientFactory === 'function') {
this._aiCoreOrKey = iKeyOrClientFactory();
} else {
this._aiCoreOrKey = iKeyOrClientFactory;
}
this._asyncAiCore = null;
// If we cannot fetch the endpoint it means it is down and we should not send any telemetry.
// This is most likely due to ad blockers
fetch(endpointUrl, { method: 'POST' }).catch(err => {
this._aiCoreOrKey = undefined;
});
}
private _withAIClient(callback: (aiCore: AppInsightsCore) => void): void {
if (!this._aiCoreOrKey) {
return;
}
if (typeof this._aiCoreOrKey !== 'string') {
callback(this._aiCoreOrKey);
return;
}
if (!this._asyncAiCore) {
this._asyncAiCore = getClient(this._aiCoreOrKey);
}
this._asyncAiCore.then(
(aiClient) => {
callback(aiClient);
},
(err) => {
onUnexpectedError(err);
console.error(err);
}
);
}
log(eventName: string, data?: any): void {
if (!this._aiCoreOrKey) {
return;
}
data = mixin(data, this._defaultData);
data = validateTelemetryData(data);
try {
this._withAIClient((aiClient) => aiClient.track({
name: this._eventPrefix + '/' + eventName,
data: { ...data.properties, ...data.measurements },
}));
} catch { }
}
flush(): Promise<any> {
if (this._aiCoreOrKey) {
return new Promise(resolve => {
this._withAIClient((aiClient) => {
aiClient.unload(true, () => {
this._aiCoreOrKey = undefined;
resolve(undefined);
});
});
});
}
return Promise.resolve(undefined);
}
}

View file

@ -10,6 +10,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ILoggerService } from 'vs/platform/log/common/log';
import { IProductService } from 'vs/platform/product/common/productService';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { OneDataSystemWebAppender } from 'vs/platform/telemetry/browser/1dsAppender';
import { WebAppInsightsAppender } from 'vs/platform/telemetry/browser/appInsightsAppender';
import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings';
import { ITelemetryData, ITelemetryInfo, ITelemetryService, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry';
@ -37,11 +38,20 @@ export class TelemetryService extends Disposable implements ITelemetryService {
) {
super();
if (supportsTelemetry(productService, environmentService) && productService.aiConfig?.asimovKey) {
if (supportsTelemetry(productService, environmentService) && productService.aiConfig?.asimovKey && productService.aiConfig?.ariaKey) {
// If remote server is present send telemetry through that, else use the client side appender
const telemetryProvider: ITelemetryAppender = remoteAgentService.getConnection() !== null ? { log: remoteAgentService.logTelemetry.bind(remoteAgentService), flush: remoteAgentService.flushTelemetry.bind(remoteAgentService) } : new WebAppInsightsAppender('monacoworkbench', productService.aiConfig?.asimovKey);
const internalTesting = configurationService.getValue<boolean>('telemetry.internalTesting');
const appenders = [];
if (internalTesting) {
const telemetryProvider: ITelemetryAppender = remoteAgentService.getConnection() !== null ? { log: remoteAgentService.logTelemetry.bind(remoteAgentService), flush: remoteAgentService.flushTelemetry.bind(remoteAgentService) } : new OneDataSystemWebAppender('monacoworkbench', null, productService.aiConfig?.ariaKey);
appenders.push(telemetryProvider);
} else {
const telemetryProvider: ITelemetryAppender = remoteAgentService.getConnection() !== null ? { log: remoteAgentService.logTelemetry.bind(remoteAgentService), flush: remoteAgentService.flushTelemetry.bind(remoteAgentService) } : new WebAppInsightsAppender('monacoworkbench', productService.aiConfig?.asimovKey);
appenders.push(telemetryProvider);
}
appenders.push(new TelemetryLogAppender(loggerService, environmentService));
const config: ITelemetryServiceConfig = {
appenders: [telemetryProvider, new TelemetryLogAppender(loggerService, environmentService)],
appenders,
commonProperties: resolveWorkbenchCommonProperties(storageService, productService.commit, productService.version, environmentService.remoteAuthority, productService.embedderIdentifier, productService.removeTelemetryMachineId, environmentService.options && environmentService.options.resolveCommonTelemetryProperties),
sendErrorTelemetry: this.sendErrorTelemetry,
};