Extension telemetry feature cleanup (#21779)

* Extension telemetry feature cleanup

* one more
This commit is contained in:
Charles Gagnon
2023-01-30 13:14:38 -08:00
committed by GitHub
parent c33d2cc40a
commit ad69164f09
42 changed files with 145 additions and 619 deletions

View File

@@ -10,7 +10,7 @@ import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import * as path from 'path';
import { getCommonLaunchArgsAndCleanupOldLogFiles } from './utils';
import { Telemetry, LanguageClientErrorHandler } from './telemetry';
import { TelemetryReporter, LanguageClientErrorHandler } from './telemetry';
import { SqlOpsDataClient, ClientOptions } from 'dataprotocol-client';
import { SerializationFeature } from './features/serializationFeature';
import { TelemetryFeature } from './features/telemetryFeature';
@@ -48,7 +48,7 @@ export class AzureMonitorServer {
vscode.commands.registerCommand('azuremonitor.loadCompletionExtension', (params: CompletionExtensionParams) => {
this.client.sendRequest(CompletionExtLoadRequest.type, params);
});
Telemetry.sendTelemetryEvent('startup/LanguageClientStarted', {
TelemetryReporter.sendTelemetryEvent('startup/LanguageClientStarted', {
installationTime: String(installationComplete - installationStart),
processStartupTime: String(processEnd - processStart),
totalTime: String(processEnd - installationStart),
@@ -61,7 +61,7 @@ export class AzureMonitorServer {
await Promise.all([clientReadyPromise]);
return this.client;
} catch (e) {
Telemetry.sendTelemetryEvent('ServiceInitializingFailed');
TelemetryReporter.sendTelemetryEvent('ServiceInitializingFailed');
vscode.window.showErrorMessage(localize('failedToStartServiceErrorMsg', "Failed to start {0}", Constants.serviceName));
throw e;
}

View File

@@ -6,6 +6,7 @@ export const serviceName = 'AzureMonitor Tools Service';
export const providerId = 'LOGANALYTICS';
export const serviceCrashLink = 'https://github.com/Microsoft/azuredatastudio/issues';
export const extensionConfigSectionName = 'azuremonitor';
export const packageName = 'Microsoft.azuremonitor';
// DATA PROTOCOL VALUES ///////////////////////////////////////////////////////////
export const azureMonitorClusterProviderName = 'azureMonitorCluster';
@@ -22,4 +23,4 @@ export const objectExplorerPrefix: string = 'objectexplorer://';
export const ViewType = 'view';
export const azuremonitorClusterNewNotebookTask = 'azuremonitorCluster.task.newNotebook';
export const azuremonitorClusterOpenNotebookTask = 'azuremonitorCluster.task.openNotebook';
export const azuremonitorClusterOpenNotebookTask = 'azuremonitorCluster.task.openNotebook';

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { NotificationType, RequestType } from 'vscode-languageclient';
import { ITelemetryEventProperties, ITelemetryEventMeasures } from '../telemetry';
import * as telemetry from '@microsoft/ads-extension-telemetry';
import * as azdata from 'azdata';
// ------------------------------- < Telemetry Sent Event > ------------------------------------
@@ -22,8 +22,8 @@ export namespace TelemetryNotification {
export class TelemetryParams {
public params!: {
eventName: string;
properties: ITelemetryEventProperties;
measures: ITelemetryEventMeasures;
properties: telemetry.TelemetryEventProperties;
measures: telemetry.TelemetryEventMeasures;
};
}

View File

@@ -5,7 +5,7 @@
import { SqlOpsDataClient } from 'dataprotocol-client';
import { ClientCapabilities, StaticFeature } from 'vscode-languageclient';
import { Telemetry } from '../telemetry';
import { TelemetryReporter } from '../telemetry';
import * as contracts from './contracts';
import * as Utils from '../utils';
@@ -19,7 +19,7 @@ export class TelemetryFeature implements StaticFeature {
initialize(): void {
this._client.onNotification(contracts.TelemetryNotification.type, e => {
Telemetry.sendTelemetryEvent(e.params.eventName, e.params.properties, e.params.measures);
TelemetryReporter.sendTelemetryEvent(e.params.eventName, e.params.properties, e.params.measures);
});
}
}

View File

@@ -19,6 +19,7 @@ import { AzureMonitorIconProvider } from './iconProvider';
import { createAzureMonitorApi } from './azuremonitorApiFactory';
import { AzureMonitorServer } from './azuremonitorServer';
import { promises as fs } from 'fs';
import { TelemetryReporter } from './telemetry';
const localize = nls.loadMessageBundle();
@@ -54,7 +55,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<IExten
const server = new AzureMonitorServer();
context.subscriptions.push(server);
await server.start(appContext);
context.subscriptions.push(TelemetryReporter);
return createAzureMonitorApi(appContext);
}

View File

@@ -4,118 +4,18 @@
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import TelemetryReporter from '@microsoft/ads-extension-telemetry';
import AdsTelemetryReporter from '@microsoft/ads-extension-telemetry';
import { ErrorAction, ErrorHandler, Message, CloseAction } from 'vscode-languageclient';
import * as Utils from './utils';
import * as Constants from './constants';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
const packageJson = require('../package.json');
const viewKnownIssuesAction = localize('viewKnownIssuesText', "View Known Issues");
export interface ITelemetryEventProperties {
[key: string]: string;
}
export interface ITelemetryEventMeasures {
[key: string]: number;
}
/**
* Filters error paths to only include source files. Exported to support testing
*/
export function FilterErrorPath(line: string): string | undefined {
if (line) {
let values: string[] = line.split('/out/');
if (values.length <= 1) {
// Didn't match expected format
return line;
} else {
return values[1];
}
}
return undefined;
}
export class Telemetry {
private static reporter: TelemetryReporter;
private static disabled: boolean;
/**
* Disable telemetry reporting
*/
public static disable(): void {
this.disabled = true;
}
/**
* Initialize the telemetry reporter for use.
*/
public static initialize(): void {
if (typeof this.reporter === 'undefined') {
// Check if the user has opted out of telemetry
if (!vscode.workspace.getConfiguration('telemetry').get<boolean>('enableTelemetry', true)) {
this.disable();
return;
}
let packageInfo = Utils.getPackageInfo(packageJson)!;
this.reporter = new TelemetryReporter(packageInfo.name, packageInfo.version, packageInfo.aiKey);
}
}
/**
* Send a telemetry event for an exception
*/
public static sendTelemetryEventForException(
err: any, methodName: string, _extensionConfigName: string): void {
let stackArray: string[];
let firstLine: string = '';
if (err !== undefined && err.stack !== undefined) {
stackArray = err.stack.split('\n');
if (stackArray !== undefined && stackArray.length >= 2) {
firstLine = stackArray[1]; // The fist line is the error message and we don't want to send that telemetry event
firstLine = FilterErrorPath(firstLine)!;
}
}
// Only adding the method name and the fist line of the stack trace. We don't add the error message because it might have PII
this.sendTelemetryEvent('Exception', { methodName: methodName, errorLine: firstLine });
}
/**
* Send a telemetry event using application insights
*/
public static sendTelemetryEvent(
eventName: string,
properties?: ITelemetryEventProperties,
measures?: ITelemetryEventMeasures): void {
if (typeof this.disabled === 'undefined') {
this.disabled = false;
}
if (this.disabled || typeof (this.reporter) === 'undefined') {
// Don't do anything if telemetry is disabled
return;
}
if (!properties || typeof properties === 'undefined') {
properties = {};
}
try {
this.reporter.sendTelemetryEvent(eventName, properties, measures);
} catch (telemetryErr) {
// If sending telemetry event fails ignore it so it won't break the extension
console.error('Failed to send telemetry event. error: ' + telemetryErr);
}
}
}
const packageInfo = vscode.extensions.getExtension(Constants.packageName)?.packageJSON;
export const TelemetryReporter = new AdsTelemetryReporter<string, string>(packageInfo?.name, packageInfo?.version, packageInfo?.aiKey);
/**
* Handle Language Service client errors
@@ -127,12 +27,12 @@ export class LanguageClientErrorHandler implements ErrorHandler {
* @memberOf LanguageClientErrorHandler
*/
showOnErrorPrompt(): void {
Telemetry.sendTelemetryEvent(Constants.serviceName + 'Crash');
vscode.window.showErrorMessage(
TelemetryReporter.sendTelemetryEvent(Constants.serviceName + 'Crash');
void vscode.window.showErrorMessage(
localize('serviceCrashMessage', "{0} component exited unexpectedly. Please restart Azure Data Studio.", Constants.serviceName),
viewKnownIssuesAction).then(action => {
if (action && action === viewKnownIssuesAction) {
vscode.env.openExternal(vscode.Uri.parse(Constants.serviceCrashLink));
void vscode.env.openExternal(vscode.Uri.parse(Constants.serviceCrashLink));
}
});
}
@@ -163,5 +63,3 @@ export class LanguageClientErrorHandler implements ErrorHandler {
return CloseAction.DoNotRestart;
}
}
Telemetry.initialize();