mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Clean up extension telemetry (#5596)
This commit is contained in:
@@ -8,7 +8,7 @@ import * as path from 'path';
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import { Telemetry } from './telemetry';
|
||||
import { doubleEscapeSingleQuotes, backEscapeDoubleQuotes } from './utils';
|
||||
import { doubleEscapeSingleQuotes, backEscapeDoubleQuotes, getTelemetryErrorType } from './utils';
|
||||
import { ChildProcess, exec } from 'child_process';
|
||||
const localize = nls.loadMessageBundle();
|
||||
const ssmsMinVer = JSON.parse(JSON.stringify(require('./config.json'))).version;
|
||||
@@ -66,7 +66,6 @@ export interface LaunchSsmsDialogParams {
|
||||
export async function activate(context: vscode.ExtensionContext): Promise<void> {
|
||||
// This is for Windows-specific support so do nothing on other platforms
|
||||
if (process.platform === 'win32') {
|
||||
Telemetry.sendTelemetryEvent('startup/ExtensionActivated');
|
||||
exePath = path.join(context.extensionPath, 'ssmsmin', 'Windows', ssmsMinVer, 'ssmsmin.exe');
|
||||
registerCommands(context);
|
||||
}
|
||||
@@ -76,7 +75,7 @@ export async function deactivate(): Promise<void> {
|
||||
// If the extension is being deactivated we want to kill all processes that are still currently
|
||||
// running otherwise they will continue to run as orphan processes. We use taskkill here in case
|
||||
// they started off child processes of their own
|
||||
runningProcesses.forEach(p => exec('taskkill /pid ' + p.pid + ' /T /F'));
|
||||
runningProcesses.forEach(p => exec(`taskkill /pid ${p.pid} /T /F`));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,6 +95,7 @@ function registerCommands(context: vscode.ExtensionContext): void {
|
||||
*/
|
||||
async function handleLaunchSsmsMinPropertiesDialogCommand(connectionContext?: azdata.ObjectExplorerContext): Promise<void> {
|
||||
if (!connectionContext) {
|
||||
Telemetry.sendTelemetryEventForError('NoConnectionContext', { action: 'Properties' });
|
||||
vscode.window.showErrorMessage(localize('adminToolExtWin.noConnectionContextForProp', 'No ConnectionContext provided for handleLaunchSsmsMinPropertiesDialogCommand'));
|
||||
return;
|
||||
}
|
||||
@@ -106,9 +106,9 @@ async function handleLaunchSsmsMinPropertiesDialogCommand(connectionContext?: az
|
||||
}
|
||||
else if (connectionContext.nodeInfo) {
|
||||
nodeType = connectionContext.nodeInfo.nodeType;
|
||||
}
|
||||
else {
|
||||
vscode.window.showErrorMessage(localize('adminToolExtWin.noOeNode', 'Could not determine NodeType for handleLaunchSsmsMinPropertiesDialogCommand with context {0}', JSON.stringify(connectionContext)));
|
||||
} else {
|
||||
Telemetry.sendTelemetryEventForError('NoOENode', { action: 'Properties' });
|
||||
vscode.window.showErrorMessage(localize('adminToolExtWin.noOENode', 'Could not determine Object Explorer node from connectionContext : {0}', JSON.stringify(connectionContext)));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -122,12 +122,14 @@ async function handleLaunchSsmsMinPropertiesDialogCommand(connectionContext?: az
|
||||
* @param connectionId The connection context from the command
|
||||
*/
|
||||
async function handleLaunchSsmsMinGswDialogCommand(connectionContext?: azdata.ObjectExplorerContext): Promise<void> {
|
||||
const action = 'GenerateScripts';
|
||||
if (!connectionContext) {
|
||||
Telemetry.sendTelemetryEventForError('NoConnectionContext', { action: action });
|
||||
vscode.window.showErrorMessage(localize('adminToolExtWin.noConnectionContextForGsw', 'No ConnectionContext provided for handleLaunchSsmsMinPropertiesDialogCommand'));
|
||||
}
|
||||
|
||||
launchSsmsDialog(
|
||||
'GenerateScripts',
|
||||
action,
|
||||
connectionContext);
|
||||
}
|
||||
|
||||
@@ -139,6 +141,7 @@ async function handleLaunchSsmsMinGswDialogCommand(connectionContext?: azdata.Ob
|
||||
*/
|
||||
async function launchSsmsDialog(action: string, connectionContext: azdata.ObjectExplorerContext): Promise<void> {
|
||||
if (!connectionContext.connectionProfile) {
|
||||
Telemetry.sendTelemetryEventForError('NoConnectionProfile', { action: action });
|
||||
vscode.window.showErrorMessage(localize('adminToolExtWin.noConnectionProfile', 'No connectionProfile provided from connectionContext : {0}', JSON.stringify(connectionContext)));
|
||||
return;
|
||||
}
|
||||
@@ -152,6 +155,7 @@ async function launchSsmsDialog(action: string, connectionContext: azdata.Object
|
||||
oeNode = await azdata.objectexplorer.getNode(connectionContext.connectionProfile.id, connectionContext.nodeInfo.nodePath);
|
||||
}
|
||||
else {
|
||||
Telemetry.sendTelemetryEventForError('NoOENode', { action: action });
|
||||
vscode.window.showErrorMessage(localize('adminToolExtWin.noOENode', 'Could not determine Object Explorer node from connectionContext : {0}', JSON.stringify(connectionContext)));
|
||||
return;
|
||||
}
|
||||
@@ -175,7 +179,12 @@ async function launchSsmsDialog(action: string, connectionContext: azdata.Object
|
||||
|
||||
const args = buildSsmsMinCommandArgs(params);
|
||||
|
||||
Telemetry.sendTelemetryEvent('LaunchSsmsDialog', { 'action': action });
|
||||
Telemetry.sendTelemetryEvent('LaunchSsmsDialog',
|
||||
{
|
||||
action: action,
|
||||
nodeType: oeNode ? oeNode.nodeType : 'Server',
|
||||
authType: connectionContext.connectionProfile.authenticationType
|
||||
});
|
||||
|
||||
vscode.window.setStatusBarMessage(localize('adminToolExtWin.launchingDialogStatus', 'Launching dialog...'), 3000);
|
||||
|
||||
@@ -186,11 +195,12 @@ async function launchSsmsDialog(action: string, connectionContext: azdata.Object
|
||||
(execException, stdout, stderr) => {
|
||||
// Process has exited so remove from map of running processes
|
||||
runningProcesses.delete(proc.pid);
|
||||
const err = stderr.toString();
|
||||
Telemetry.sendTelemetryEvent('LaunchSsmsDialogResult', {
|
||||
'action': params.action,
|
||||
'returnCode': execException && execException.code ? execException.code.toString() : '0'
|
||||
action: params.action,
|
||||
returnCode: execException && execException.code ? execException.code.toString() : '0',
|
||||
errorType: getTelemetryErrorType(err)
|
||||
});
|
||||
let err = stderr.toString();
|
||||
if (err !== '') {
|
||||
vscode.window.showErrorMessage(localize(
|
||||
'adminToolExtWin.ssmsMinError',
|
||||
|
||||
@@ -62,27 +62,11 @@ export class Telemetry {
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a telemetry event for an exception
|
||||
* Send a telemetry event for a general error
|
||||
* @param err The error to log
|
||||
*/
|
||||
public static sendTelemetryEventForException(
|
||||
err: any, methodName: string, extensionConfigName: string): void {
|
||||
try {
|
||||
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 first 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 });
|
||||
} 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, extensionConfigName);
|
||||
}
|
||||
public static sendTelemetryEventForError(err: string, properties?: ITelemetryEventProperties): void {
|
||||
this.sendTelemetryEvent('Error', { error: err, ...properties });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,7 +90,12 @@ export class Telemetry {
|
||||
properties = {};
|
||||
}
|
||||
|
||||
this.reporter.sendTelemetryEvent(eventName, properties, measures);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,4 +36,26 @@ export function doubleEscapeSingleQuotes(value: string): string {
|
||||
*/
|
||||
export function backEscapeDoubleQuotes(value: string): string {
|
||||
return value.replace(/"/g, '\\"');
|
||||
}
|
||||
|
||||
/**
|
||||
* Map an error message into a GDPR-Compliant short name for the type of error.
|
||||
* @param msg The error message to map
|
||||
*/
|
||||
export function getTelemetryErrorType(msg: string): string {
|
||||
if (msg.indexOf('is not recognized as an internal or external command') !== -1) {
|
||||
return 'ExeNotFound';
|
||||
}
|
||||
else if (msg.indexOf('Unknown Action') !== -1) {
|
||||
return 'UnknownAction';
|
||||
}
|
||||
else if (msg.indexOf('No Action Provided') !== -1) {
|
||||
return 'NoActionProvided';
|
||||
}
|
||||
else if (msg.indexOf('Run exception') !== -1) {
|
||||
return 'RunException';
|
||||
}
|
||||
else {
|
||||
return 'Other';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user