提交 9a543b59 编写于 作者: J Joao Moreno

isolate telemetry in vs/platform/telemetry

上级 19c1af1b
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {TPromise} from 'vs/base/common/winjs.base';
import {IServer} from 'vs/base/parts/ipc/common/ipc';
import {AppInsightsAppender} from 'vs/platform/telemetry/node/aiAdapter';
import {IAIChannel} from './ai.ipc';
const adapter: { [handle: number]: AppInsightsAppender } = Object.create(null);
let idPool = 0;
export function registerAIChannel(server: IServer) {
server.registerChannel('ai', <IAIChannel>{
call(command: string, arg: any): TPromise<any> {
switch (command) {
case 'create': {
let handle = idPool++;
let {key, eventPrefix, data} = arg;
adapter[handle] = new AppInsightsAppender(eventPrefix, data, key);
return TPromise.as(handle);
}
case 'log': {
let {handle, eventName, data} = arg;
adapter[handle].log(eventName, data);
return TPromise.as(undefined);
}
case 'dispose': {
let {handle} = arg;
adapter[handle].dispose();
delete adapter[handle];
return TPromise.as(undefined);
}
}
}
});
}
// It is important to dispose the AI adapter properly because
// only then they flush remaining data.
process.on('SIGTERM', function () {
let promises: TPromise<any>[] = [];
for (let handle in adapter) {
let ai = adapter[handle];
promises.push(ai.dispose());
}
TPromise.join(promises).then(_ => process.exit(0));
});
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {TPromise} from 'vs/base/common/winjs.base';
import {IChannel} from 'vs/base/parts/ipc/common/ipc';
export interface IAIChannel extends IChannel {
call(command: 'create', data: { key: string; eventPrefix: string; data: { [k: string]: any }; }): TPromise<number>;
call(command: 'log', data: { handle: number; eventName: string; data: { [k: string]: any }; }): TPromise<any>;
call(command: 'dispose', data: { handle: number; }): TPromise<any>;
call(command: string, arg: any): TPromise<any>;
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {IAIChannel} from './ai.ipc';
import {TPromise} from 'vs/base/common/winjs.base';
import {connect} from 'vs/base/parts/ipc/node/ipc.net';
export interface IAIAdapter {
log(eventName: string, data?: any): void;
dispose(): void;
}
export function createAIAdapter(key: string, eventPrefix: string, data: { [key: string]: any }): IAIAdapter {
let beforeReadyMessages: { type: string; args: any }[] = [];
let handle: number = undefined;
let channel: IAIChannel = {
call(type: string, args: any): TPromise<any> {
beforeReadyMessages.push({ type, args });
return TPromise.as(void 0);
}
};
connect(process.env['VSCODE_SHARED_IPC_HOOK']).then(client => client.getChannel<IAIChannel>('ai')).then(actualChannel => {
return actualChannel.call('create', { key, eventPrefix, data }).then(actualHandle => {
// channel has been created, store handle etc,
// and flush all early messages
handle = actualHandle;
channel = actualChannel;
for (let m of beforeReadyMessages) {
let {type, args} = m;
args.handle = handle;
channel.call(type, args);
}
beforeReadyMessages.length = 0;
});
});
return <IAIAdapter>{
log(eventName: string, data?: any) {
channel.call('log', { handle, eventName, data });
},
dispose() {
channel.call('dispose', { handle });
}
};
}
......@@ -7,7 +7,6 @@ import * as fs from 'fs';
import * as platform from 'vs/base/common/platform';
import { serve, Server, connect } from 'vs/base/parts/ipc/node/ipc.net';
import { TPromise } from 'vs/base/common/winjs.base';
import { registerAIChannel } from 'vs/base/parts/ai/node/ai.app';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
......@@ -22,9 +21,10 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { NodeConfigurationService } from 'vs/platform/configuration/node/nodeConfigurationService';
import product from 'vs/platform/product';
import { ITelemetryAppender, combinedAppender, ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { ITelemetryAppender, ITelemetryService, combinedAppender } from 'vs/platform/telemetry/common/telemetry';
import { TelemetryAppenderChannel } from 'vs/platform/telemetry/common/telemetryIpc';
import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService';
import { AppInsightsAppender } from 'vs/platform/telemetry/node/aiAdapter';
import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender';
function quit(err?: Error) {
if (err) {
......@@ -49,21 +49,6 @@ function setupPlanB(parentPid: number): void {
const eventPrefix = 'monacoworkbench';
function createAppender(): ITelemetryAppender {
const result: ITelemetryAppender[] = [];
const { key, asimovKey } = product.aiConfig || { key: null, asimovKey: null };
if (key) {
result.push(new AppInsightsAppender(eventPrefix, null, key));
}
if (asimovKey) {
result.push(new AppInsightsAppender(eventPrefix, null, asimovKey));
}
return combinedAppender(...result);
}
function main(server: Server): void {
const services = new ServiceCollection();
......@@ -75,12 +60,30 @@ function main(server: Server): void {
const instantiationService = new InstantiationService(services);
instantiationService.invokeFunction(accessor => {
const { appRoot, extensionsPath } = accessor.get(IEnvironmentService);
const aiAppenders: AppInsightsAppender[] = [];
const appender = createAppender();
if (product.aiConfig && product.aiConfig.key) {
aiAppenders.push(new AppInsightsAppender(eventPrefix, null, product.aiConfig.key));
}
if (product.aiConfig && product.aiConfig.asimovKey) {
aiAppenders.push(new AppInsightsAppender(eventPrefix, null, product.aiConfig.asimovKey));
}
const appenders: ITelemetryAppender[] = aiAppenders.slice();
appenders.push({ log: (e,d) => console.log(`Telemetry event: ${ e }\n${ JSON.stringify(d) }`) });
// It is important to dispose the AI adapter properly because
// only then they flush remaining data.
process.once('exit', () => aiAppenders.forEach(a => a.dispose()));
const appender = combinedAppender(...appenders);
server.registerChannel('telemetryAppender', new TelemetryAppenderChannel(appender));
const { appRoot, extensionsPath } = accessor.get(IEnvironmentService);
const config: ITelemetryServiceConfig = {
appender,
commonProperties: TPromise.as({}), //resolveCommonProperties(storageService, contextService),
commonProperties: TPromise.as({}),
piiPaths: [appRoot, extensionsPath]
};
......@@ -89,13 +92,11 @@ function main(server: Server): void {
const instantiationService2 = instantiationService.createChild(services);
instantiationService2.invokeFunction(accessor => {
const telemetryService = accessor.get(ITelemetryService);
console.log(telemetryService);
// const telemetryService = accessor.get(ITelemetryService);
const extensionManagementService = accessor.get(IExtensionManagementService);
const channel = new ExtensionManagementChannel(extensionManagementService);
server.registerChannel('extensions', channel);
registerAIChannel(server);
// eventually clean up old extensions
setTimeout(() => (extensionManagementService as ExtensionManagementService).removeDeprecatedExtensions(), 5000);
......
......@@ -5,7 +5,6 @@
'use strict';
import {TPromise} from 'vs/base/common/winjs.base';
import {IDisposable} from 'vs/base/common/lifecycle';
import {ITimerEvent, nullEvent} from 'vs/base/common/timer';
import {createDecorator, ServiceIdentifier} from 'vs/platform/instantiation/common/instantiation';
......@@ -51,17 +50,15 @@ export const NullTelemetryService: ITelemetryService = {
}
};
export interface ITelemetryAppender extends IDisposable {
log(eventName: string, data?: any): any;
export interface ITelemetryAppender {
log(eventName: string, data: any): void;
}
export function combinedAppender(...appenders: ITelemetryAppender[]): ITelemetryAppender {
const log = (e, d) => appenders.forEach(a => a.log(e, d));
const dispose = () => appenders.forEach(a => a.dispose());
return { log, dispose };
return { log: (e, d) => appenders.forEach(a => a.log(e,d)) };
}
export const NullAppender = combinedAppender();
export const NullAppender: ITelemetryAppender = { log: () => null };
// --- util
......
......@@ -24,7 +24,8 @@ export class TelemetryAppenderChannel implements ITelemetryAppenderChannel {
constructor(private appender: ITelemetryAppender) { }
call(command: string, { eventName, data }: ITelemetryLog): TPromise<any> {
return this.appender.log(eventName, data);
this.appender.log(eventName, data);
return TPromise.as(null);
}
}
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as appInsights from 'applicationinsights';
import {isObject} from 'vs/base/common/types';
import {safeStringify, mixin} from 'vs/base/common/objects';
import {TPromise} from 'vs/base/common/winjs.base';
import {ITelemetryAppender} from '../common/telemetry';
let _initialized = false;
function ensureAIEngineIsInitialized(): void {
if (_initialized === false) {
// we need to pass some fake key, otherwise AI throws an exception
appInsights.setup('2588e01f-f6c9-4cd6-a348-143741f8d702')
.setAutoCollectConsole(false)
.setAutoCollectExceptions(false)
.setAutoCollectPerformance(false)
.setAutoCollectRequests(false);
_initialized = true;
}
}
function getClient(aiKey: string): typeof appInsights.client {
ensureAIEngineIsInitialized();
const client = appInsights.getClient(aiKey);
client.channel.setOfflineMode(true);
client.context.tags[client.context.keys.deviceMachineName] = ''; //prevent App Insights from reporting machine name
if (aiKey.indexOf('AIF-') === 0) {
client.config.endpointUrl = 'https://vortex.data.microsoft.com/collect/v1';
}
return client;
}
interface Properties {
[key: string]: string;
}
interface Measurements {
[key: string]: number;
}
export class AppInsightsAppender implements ITelemetryAppender {
private _aiClient: typeof appInsights.client;
constructor(
private _eventPrefix: string,
private _defaultData: { [key: string]: any },
aiKeyOrClientFactory: string | (() => typeof appInsights.client) // allow factory function for testing
) {
if (!this._defaultData) {
this._defaultData = Object.create(null);
}
if (typeof aiKeyOrClientFactory === 'string') {
this._aiClient = getClient(aiKeyOrClientFactory);
} else if (typeof aiKeyOrClientFactory === 'function') {
this._aiClient = aiKeyOrClientFactory();
}
}
private static _getData(data?: any): { properties: Properties, measurements: Measurements } {
const properties: Properties = Object.create(null);
const measurements: Measurements = Object.create(null);
const flat = Object.create(null);
AppInsightsAppender._flaten(data, flat);
for (let prop in flat) {
// enforce property names less than 150 char, take the last 150 char
prop = prop.length > 150 ? prop.substr(prop.length - 149) : prop;
var value = flat[prop];
if (typeof value === 'number') {
measurements[prop] = value;
} else if (typeof value === 'boolean') {
measurements[prop] = value ? 1 : 0;
} else if (typeof value === 'string') {
//enforce property value to be less than 1024 char, take the first 1024 char
properties[prop] = value.substring(0, 1023);
} else if (typeof value !== 'undefined' && value !== null) {
properties[prop] = value;
}
}
return {
properties,
measurements
};
}
private static _flaten(obj: any, result: {[key: string]: any }, order: number = 0, prefix?: string): void {
if (!obj) {
return;
}
for(var item of Object.getOwnPropertyNames(obj)){
const value = obj[item];
const index = prefix ? prefix + item : item;
if (Array.isArray(value)) {
result[index] = safeStringify(value);
} else if (value instanceof Date) {
// TODO unsure why this is here and not in _getData
result[index] = value.toISOString();
} else if (isObject(value)) {
if (order < 2) {
AppInsightsAppender._flaten(value, result, order + 1, index + '.');
} else {
result[index] = safeStringify(value);
}
} else {
result[index] = value;
}
}
}
public log(eventName: string, data?: any): void {
if (!this._aiClient) {
return;
}
data = mixin(data, this._defaultData);
let {properties, measurements} = AppInsightsAppender._getData(data);
this._aiClient.trackEvent(this._eventPrefix + '/' + eventName, properties, measurements);
}
public dispose(): TPromise<any> {
if (this._aiClient) {
return new TPromise(resolve => {
this._aiClient.sendPendingData(() => {
// all data flushed
this._aiClient = undefined;
resolve(void 0);
});
});
}
}
}
\ No newline at end of file
......@@ -4,23 +4,148 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import {IEnvironment} from 'vs/platform/workspace/common/workspace';
import {ITelemetryAppender, combinedAppender} from 'vs/platform/telemetry/common/telemetry';
import {createAIAdapter} from 'vs/base/parts/ai/node/ai';
import * as appInsights from 'applicationinsights';
import {isObject} from 'vs/base/common/types';
import {safeStringify, mixin} from 'vs/base/common/objects';
import {TPromise} from 'vs/base/common/winjs.base';
import {ITelemetryAppender} from '../common/telemetry';
const eventPrefix = 'monacoworkbench';
let _initialized = false;
export function createAppender(env: IEnvironment): ITelemetryAppender {
const result: ITelemetryAppender[] = [];
const { key, asimovKey } = env.aiConfig;
function ensureAIEngineIsInitialized(): void {
if (_initialized === false) {
// we need to pass some fake key, otherwise AI throws an exception
appInsights.setup('2588e01f-f6c9-4cd6-a348-143741f8d702')
.setAutoCollectConsole(false)
.setAutoCollectExceptions(false)
.setAutoCollectPerformance(false)
.setAutoCollectRequests(false);
if (key) {
result.push(createAIAdapter(key, eventPrefix, undefined));
_initialized = true;
}
}
function getClient(aiKey: string): typeof appInsights.client {
if (asimovKey) {
result.push(createAIAdapter(asimovKey, eventPrefix, undefined));
ensureAIEngineIsInitialized();
const client = appInsights.getClient(aiKey);
client.channel.setOfflineMode(true);
client.context.tags[client.context.keys.deviceMachineName] = ''; //prevent App Insights from reporting machine name
if (aiKey.indexOf('AIF-') === 0) {
client.config.endpointUrl = 'https://vortex.data.microsoft.com/collect/v1';
}
return client;
}
return combinedAppender(...result);
interface Properties {
[key: string]: string;
}
interface Measurements {
[key: string]: number;
}
export class AppInsightsAppender implements ITelemetryAppender {
private _aiClient: typeof appInsights.client;
constructor(
private _eventPrefix: string,
private _defaultData: { [key: string]: any },
aiKeyOrClientFactory: string | (() => typeof appInsights.client) // allow factory function for testing
) {
if (!this._defaultData) {
this._defaultData = Object.create(null);
}
if (typeof aiKeyOrClientFactory === 'string') {
this._aiClient = getClient(aiKeyOrClientFactory);
} else if (typeof aiKeyOrClientFactory === 'function') {
this._aiClient = aiKeyOrClientFactory();
}
}
private static _getData(data?: any): { properties: Properties, measurements: Measurements } {
const properties: Properties = Object.create(null);
const measurements: Measurements = Object.create(null);
const flat = Object.create(null);
AppInsightsAppender._flaten(data, flat);
for (let prop in flat) {
// enforce property names less than 150 char, take the last 150 char
prop = prop.length > 150 ? prop.substr(prop.length - 149) : prop;
var value = flat[prop];
if (typeof value === 'number') {
measurements[prop] = value;
} else if (typeof value === 'boolean') {
measurements[prop] = value ? 1 : 0;
} else if (typeof value === 'string') {
//enforce property value to be less than 1024 char, take the first 1024 char
properties[prop] = value.substring(0, 1023);
} else if (typeof value !== 'undefined' && value !== null) {
properties[prop] = value;
}
}
return {
properties,
measurements
};
}
private static _flaten(obj: any, result: {[key: string]: any }, order: number = 0, prefix?: string): void {
if (!obj) {
return;
}
for(var item of Object.getOwnPropertyNames(obj)){
const value = obj[item];
const index = prefix ? prefix + item : item;
if (Array.isArray(value)) {
result[index] = safeStringify(value);
} else if (value instanceof Date) {
// TODO unsure why this is here and not in _getData
result[index] = value.toISOString();
} else if (isObject(value)) {
if (order < 2) {
AppInsightsAppender._flaten(value, result, order + 1, index + '.');
} else {
result[index] = safeStringify(value);
}
} else {
result[index] = value;
}
}
}
log(eventName: string, data?: any): void {
if (!this._aiClient) {
return;
}
data = mixin(data, this._defaultData);
let {properties, measurements} = AppInsightsAppender._getData(data);
this._aiClient.trackEvent(this._eventPrefix + '/' + eventName, properties, measurements);
}
dispose(): TPromise<any> {
if (this._aiClient) {
return new TPromise(resolve => {
this._aiClient.sendPendingData(() => {
// all data flushed
this._aiClient = undefined;
resolve(void 0);
});
});
}
}
}
\ No newline at end of file
......@@ -5,7 +5,7 @@
'use strict';
import * as assert from 'assert';
import {AppInsightsAppender} from 'vs/platform/telemetry/node/aiAdapter';
import {AppInsightsAppender} from 'vs/platform/telemetry/node/appInsightsAppender';
interface IAppInsightsEvent {
eventName: string;
......
......@@ -20,10 +20,10 @@ import timer = require('vs/base/common/timer');
import {Workbench} from 'vs/workbench/browser/workbench';
import {Storage, inMemoryLocalStorageInstance} from 'vs/workbench/common/storage';
import {ITelemetryService, NullTelemetryService} from 'vs/platform/telemetry/common/telemetry';
import {ITelemetryAppenderChannel,TelemetryAppenderClient} from 'vs/platform/telemetry/common/telemetryIpc';
import {TelemetryService, ITelemetryServiceConfig} from 'vs/platform/telemetry/common/telemetryService';
import {IdleMonitor, UserStatus} from 'vs/platform/telemetry/browser/idleMonitor';
import ErrorTelemetry from 'vs/platform/telemetry/browser/errorTelemetry';
import {createAppender} from 'vs/platform/telemetry/node/appInsightsAppender';
import {resolveCommonProperties} from 'vs/platform/telemetry/node/commonProperties';
import {ElectronIntegration} from 'vs/workbench/electron-browser/integration';
import {Update} from 'vs/workbench/electron-browser/update';
......@@ -48,7 +48,6 @@ import {IOptions} from 'vs/workbench/common/options';
import {IStorageService} from 'vs/platform/storage/common/storage';
import {ServiceCollection} from 'vs/platform/instantiation/common/serviceCollection';
import {InstantiationService} from 'vs/platform/instantiation/common/instantiationService';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
import {IContextViewService} from 'vs/platform/contextview/browser/contextView';
import {IEventService} from 'vs/platform/event/common/event';
import {IFileService} from 'vs/platform/files/common/files';
......@@ -197,6 +196,16 @@ export class WorkbenchShell {
}
private initServiceCollection(): [InstantiationService, ServiceCollection] {
const sharedProcess = connect(process.env['VSCODE_SHARED_IPC_HOOK']);
sharedProcess.done(service => {
service.onClose(() => {
this.messageService.show(Severity.Error, {
message: nls.localize('sharedProcessCrashed', "The shared process terminated unexpectedly. Please reload the window to recover."),
actions: [instantiationService.createInstance(ReloadWindowAction, ReloadWindowAction.ID, ReloadWindowAction.LABEL)]
});
});
}, errors.onUnexpectedError);
const serviceCollection = new ServiceCollection();
serviceCollection.set(IEventService, this.eventService);
serviceCollection.set(IWorkspaceContextService, this.contextService);
......@@ -215,9 +224,9 @@ export class WorkbenchShell {
// Telemetry
if (this.configuration.env.isBuilt && !this.configuration.env.extensionDevelopmentPath && !!this.configuration.env.enableTelemetry) {
const appender = createAppender(this.configuration.env);
const channel = getDelayedChannel<ITelemetryAppenderChannel>(sharedProcess.then(c => c.getChannel('telemetryAppender')));
const config: ITelemetryServiceConfig = {
appender,
appender: new TelemetryAppenderClient(channel),
commonProperties: resolveCommonProperties(this.storageService, this.contextService),
piiPaths: [this.configuration.env.appRoot, this.configuration.env.userExtensionsHome]
};
......@@ -234,7 +243,7 @@ export class WorkbenchShell {
: TelemetryService.IDLE_START_EVENT_NAME
));
disposables.add(telemetryService, errorTelemetry, listener, idleMonitor, appender);
disposables.add(telemetryService, errorTelemetry, listener, idleMonitor);
} else {
this.telemetryService = NullTelemetryService;
}
......@@ -287,30 +296,13 @@ export class WorkbenchShell {
let codeEditorService = instantiationService.createInstance(CodeEditorServiceImpl);
serviceCollection.set(ICodeEditorService, codeEditorService);
let extensionManagementChannelClient = instantiationService.createInstance(ExtensionManagementChannelClient, this.initSharedProcessChannel(instantiationService, this.messageService));
const extensionManagementChannel = getDelayedChannel<IExtensionManagementChannel>(sharedProcess.then(c => c.getChannel('extensions')));
const extensionManagementChannelClient = instantiationService.createInstance(ExtensionManagementChannelClient, extensionManagementChannel);
serviceCollection.set(IExtensionManagementService, extensionManagementChannelClient);
return [instantiationService, serviceCollection];
}
private initSharedProcessChannel(instantiationService: IInstantiationService, messageService: IMessageService): IExtensionManagementChannel {
const sharedProcessClientPromise = connect(process.env['VSCODE_SHARED_IPC_HOOK']);
sharedProcessClientPromise.done(service => {
service.onClose(() => {
messageService.show(Severity.Error, {
message: nls.localize('sharedProcessCrashed', "The shared process terminated unexpectedly. Please reload the window to recover."),
actions: [instantiationService.createInstance(ReloadWindowAction, ReloadWindowAction.ID, ReloadWindowAction.LABEL)]
});
});
}, errors.onUnexpectedError);
const extensionManagementChannelPromise = sharedProcessClientPromise
.then(client => client.getChannel<IExtensionManagementChannel>('extensions'));
return getDelayedChannel<IExtensionManagementChannel>(extensionManagementChannelPromise);
}
public open(): void {
// Listen on unexpected errors
......
......@@ -17,7 +17,6 @@ import errors = require('vs/base/common/errors');
import severity from 'vs/base/common/severity';
import { TPromise } from 'vs/base/common/winjs.base';
import aria = require('vs/base/browser/ui/aria/aria');
import { IAIAdapter, createAIAdapter } from 'vs/base/parts/ai/node/ai';
import editorbrowser = require('vs/editor/browser/editorBrowser');
import { IKeybindingService, IKeybindingContextKey } from 'vs/platform/keybinding/common/keybindingService';
import {IMarkerService} from 'vs/platform/markers/common/markers';
......@@ -28,6 +27,8 @@ import { IFileService, FileChangesEvent, FileChangeType, EventType } from 'vs/pl
import { IEventService } from 'vs/platform/event/common/event';
import { IMessageService, CloseAction } from 'vs/platform/message/common/message';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
import wbeditorcommon = require('vs/workbench/common/editor');
......@@ -68,7 +69,7 @@ export class DebugService implements debug.IDebugService {
private model: model.Model;
private viewModel: viewmodel.ViewModel;
private configurationManager: ConfigurationManager;
private telemetryAdapter: IAIAdapter;
private customTelemetryService: ITelemetryService;
private lastTaskEvent: TaskEvent;
private toDispose: lifecycle.IDisposable[];
private toDisposeOnSessionEnd: lifecycle.IDisposable[];
......@@ -292,8 +293,8 @@ export class DebugService implements debug.IDebugService {
if (event.body && event.body.category === 'telemetry') {
// only log telemetry events from debug adapter if the adapter provided the telemetry key
// and the user opted in telemetry
if (this.telemetryAdapter && this.telemetryService.isOptedIn) {
this.telemetryAdapter.log(event.body.output, event.body.data);
if (this.customTelemetryService && this.telemetryService.isOptedIn) {
this.customTelemetryService.publicLog(event.body.output, event.body.data);
}
} else if (event.body && typeof event.body.output === 'string' && event.body.output.length > 0) {
this.onOutput(event);
......@@ -561,11 +562,12 @@ export class DebugService implements debug.IDebugService {
telemetryInfo['common.vscodesessionid'] = info.sessionId;
return telemetryInfo;
}).then(data => {
let {aiKey, type} = this.configurationManager.adapter;
this.telemetryAdapter = createAIAdapter(aiKey, type, data);
const { aiKey, type } = this.configurationManager.adapter;
const appender = new AppInsightsAppender(type, data, aiKey);
this.customTelemetryService = new TelemetryService({ appender }, this.configurationService);
});
this.session = this.instantiationService.createInstance(session.RawDebugSession, configuration.debugServer, this.configurationManager.adapter, this.telemetryAdapter);
this.session = this.instantiationService.createInstance(session.RawDebugSession, configuration.debugServer, this.configurationManager.adapter, this.customTelemetryService);
this.registerSessionListeners();
return this.session.initialize({
......@@ -740,10 +742,6 @@ export class DebugService implements debug.IDebugService {
});
this.model.updateBreakpoints(data);
if (this.telemetryAdapter) {
this.telemetryAdapter.dispose();
this.telemetryAdapter = null;
}
this.inDebugMode.reset();
}
......
......@@ -13,7 +13,6 @@ import { Action } from 'vs/base/common/actions';
import errors = require('vs/base/common/errors');
import { TPromise } from 'vs/base/common/winjs.base';
import severity from 'vs/base/common/severity';
import { IAIAdapter } from 'vs/base/parts/ai/node/ai';
import stdfork = require('vs/base/node/stdFork');
import { IMessageService, CloseAction } from 'vs/platform/message/common/message';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
......@@ -66,7 +65,7 @@ export class RawDebugSession extends v8.V8Protocol implements debug.IRawDebugSes
constructor(
private debugServerPort: number,
private adapter: Adapter,
private telemtryAdapter: IAIAdapter,
private customTelemetryService: ITelemetryService,
@IMessageService private messageService: IMessageService,
@ITelemetryService private telemetryService: ITelemetryService,
@IOutputService private outputService: IOutputService
......@@ -146,7 +145,7 @@ export class RawDebugSession extends v8.V8Protocol implements debug.IRawDebugSes
const message = error ? debug.formatPII(error.format, false, error.variables) : errorResponse.message;
if (error && error.sendTelemetry) {
this.telemetryService.publicLog('debugProtocolErrorResponse', { error: message });
this.telemtryAdapter.log('debugProtocolErrorResponse', { error: message });
this.customTelemetryService.publicLog('debugProtocolErrorResponse', { error: message });
}
if (error && error.showUser === false) {
return TPromise.as(null);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册