diff --git a/extensions/schema-compare/package.json b/extensions/schema-compare/package.json index 34660240aa..381c01c35e 100644 --- a/extensions/schema-compare/package.json +++ b/extensions/schema-compare/package.json @@ -59,7 +59,7 @@ } }, "dependencies": { - "vscode-extension-telemetry": "0.0.18", + "ads-extension-telemetry": "github:Charles-Gagnon/ads-extension-telemetry#0.1.0", "vscode-nls": "^4.0.0" }, "devDependencies": { diff --git a/extensions/schema-compare/src/dialogs/schemaCompareDialog.ts b/extensions/schema-compare/src/dialogs/schemaCompareDialog.ts index ef009a2d78..4fcf33c3d1 100644 --- a/extensions/schema-compare/src/dialogs/schemaCompareDialog.ts +++ b/extensions/schema-compare/src/dialogs/schemaCompareDialog.ts @@ -8,7 +8,7 @@ import * as azdata from 'azdata'; import * as vscode from 'vscode'; import { SchemaCompareMainWindow } from '../schemaCompareMainWindow'; import { promises as fs } from 'fs'; -import { Telemetry } from '../telemetry'; +import { TelemetryReporter, TelemetryViews } from '../telemetry'; import { getEndpointName, getRootPath } from '../utils'; import * as mssql from '../../../mssql'; @@ -152,10 +152,11 @@ export class SchemaCompareDialog { }; } - Telemetry.sendTelemetryEvent('SchemaCompareStart', { - 'sourceIsDacpac': this.sourceIsDacpac.toString(), - 'targetIsDacpac': this.targetIsDacpac.toString() - }); + TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareDialog, 'SchemaCompareStart') + .withAdditionalProperties({ + sourceIsDacpac: this.sourceIsDacpac.toString(), + targetIsDacpac: this.targetIsDacpac.toString() + }).send(); // update source and target values that are displayed this.schemaCompareResult.updateSourceAndTarget(); diff --git a/extensions/schema-compare/src/schemaCompareMainWindow.ts b/extensions/schema-compare/src/schemaCompareMainWindow.ts index ffb8d976bb..9301a12b63 100644 --- a/extensions/schema-compare/src/schemaCompareMainWindow.ts +++ b/extensions/schema-compare/src/schemaCompareMainWindow.ts @@ -10,7 +10,7 @@ import * as os from 'os'; import * as path from 'path'; import * as mssql from '../../mssql'; import { SchemaCompareOptionsDialog } from './dialogs/schemaCompareOptionsDialog'; -import { Telemetry } from './telemetry'; +import { TelemetryReporter, TelemetryViews } from './telemetry'; import { getTelemetryErrorType, getEndpointName, verifyConnectionAndGetOwnerUri, getRootPath } from './utils'; import { SchemaCompareDialog } from './dialogs/schemaCompareDialog'; import { isNullOrUndefined } from 'util'; @@ -281,7 +281,7 @@ export class SchemaCompareMainWindow { } public async execute(): Promise { - Telemetry.sendTelemetryEvent('SchemaComparisonStarted'); + TelemetryReporter.sendActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaComparisonStarted'); const service = await this.getService(); if (!this.operationId) { // create once per page @@ -289,17 +289,18 @@ export class SchemaCompareMainWindow { } this.comparisonResult = await service.schemaCompare(this.operationId, this.sourceEndpointInfo, this.targetEndpointInfo, azdata.TaskExecutionMode.execute, this.deploymentOptions); if (!this.comparisonResult || !this.comparisonResult.success) { - Telemetry.sendTelemetryEventForError('SchemaComparisonFailed', { - 'errorType': getTelemetryErrorType(this.comparisonResult.errorMessage), - 'operationId': this.comparisonResult.operationId - }); + TelemetryReporter.createErrorEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaComparisonFailed', undefined, getTelemetryErrorType(this.comparisonResult.errorMessage)) + .withAdditionalProperties({ + operationId: this.comparisonResult.operationId + }).send(); vscode.window.showErrorMessage(localize('schemaCompare.compareErrorMessage', "Schema Compare failed: {0}", this.comparisonResult.errorMessage ? this.comparisonResult.errorMessage : 'Unknown')); return; } - Telemetry.sendTelemetryEvent('SchemaComparisonFinished', { - 'endTime': Date.now().toString(), - 'operationId': this.comparisonResult.operationId - }); + TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaComparisonFinished') + .withAdditionalProperties({ + 'endTime': Date.now().toString(), + 'operationId': this.comparisonResult.operationId + }).send(); let data = this.getAllDifferences(this.comparisonResult.differences); @@ -642,10 +643,11 @@ export class SchemaCompareMainWindow { private async cancelCompare() { - Telemetry.sendTelemetryEvent('SchemaCompareCancelStarted', { - 'startTime:': Date.now().toString(), - 'operationId': this.operationId - }); + TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareCancelStarted') + .withAdditionalProperties({ + 'startTime': Date.now().toString(), + 'operationId': this.operationId + }).send(); // clean the pane this.flexModel.removeItem(this.loader); @@ -659,17 +661,18 @@ export class SchemaCompareMainWindow { const result = await service.schemaCompareCancel(this.operationId); if (!result || !result.success) { - Telemetry.sendTelemetryEvent('SchemaCompareCancelFailed', { - 'errorType': getTelemetryErrorType(result.errorMessage), - 'operationId': this.operationId - }); + TelemetryReporter.createErrorEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareCancelFailed', undefined, getTelemetryErrorType(result.errorMessage)) + .withAdditionalProperties({ + 'operationId': this.operationId + }).send(); vscode.window.showErrorMessage( localize('schemaCompare.cancelErrorMessage', "Cancel schema compare failed: '{0}'", (result && result.errorMessage) ? result.errorMessage : 'Unknown')); } - Telemetry.sendTelemetryEvent('SchemaCompareCancelEnded', { - 'endTime:': Date.now().toString(), - 'operationId': this.operationId - }); + TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareCancelEnded') + .withAdditionalProperties({ + 'endTime': Date.now().toString(), + 'operationId': this.operationId + }).send(); } } @@ -683,24 +686,26 @@ export class SchemaCompareMainWindow { }).component(); this.generateScriptButton.onDidClick(async (click) => { - Telemetry.sendTelemetryEvent('SchemaCompareGenerateScriptStarted', { - 'startTime:': Date.now().toString(), - 'operationId': this.comparisonResult.operationId - }); + TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareGenerateScriptStarted') + .withAdditionalProperties({ + 'startTime': Date.now().toString(), + 'operationId': this.comparisonResult.operationId + }).send(); const service = await this.getService(); const result = await service.schemaCompareGenerateScript(this.comparisonResult.operationId, this.targetEndpointInfo.serverName, this.targetEndpointInfo.databaseName, azdata.TaskExecutionMode.script); if (!result || !result.success) { - Telemetry.sendTelemetryEvent('SchemaCompareGenerateScriptFailed', { - 'errorType': getTelemetryErrorType(result.errorMessage), - 'operationId': this.comparisonResult.operationId - }); + TelemetryReporter.createErrorEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareGenerateScriptFailed', undefined, getTelemetryErrorType(result.errorMessage)) + .withAdditionalProperties({ + 'operationId': this.comparisonResult.operationId + }).send(); vscode.window.showErrorMessage( localize('schemaCompare.generateScriptErrorMessage', "Generate script failed: '{0}'", (result && result.errorMessage) ? result.errorMessage : 'Unknown')); } - Telemetry.sendTelemetryEvent('SchemaCompareGenerateScriptEnded', { - 'endTime:': Date.now().toString(), - 'operationId': this.comparisonResult.operationId - }); + TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareGenerateScriptEnded') + .withAdditionalProperties({ + 'endTime': Date.now().toString(), + 'operationId': this.comparisonResult.operationId + }).send(); }); } @@ -715,8 +720,7 @@ export class SchemaCompareMainWindow { }).component(); this.optionsButton.onDidClick(async (click) => { - Telemetry.sendTelemetryEvent('SchemaCompareOptionsOpened'); - + TelemetryReporter.sendActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareOptionsOpened'); // create fresh every time this.schemaCompareOptionDialog = new SchemaCompareOptionsDialog(this.deploymentOptions, this); await this.schemaCompareOptionDialog.openDialog(); @@ -739,10 +743,11 @@ export class SchemaCompareMainWindow { vscode.window.showWarningMessage(applyConfirmation, { modal: true }, yesString).then(async (result) => { if (result === yesString) { - Telemetry.sendTelemetryEvent('SchemaCompareApplyStarted', { - 'startTime': Date.now().toString(), - 'operationId': this.comparisonResult.operationId - }); + TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareApplyStarted') + .withAdditionalProperties({ + 'startTime': Date.now().toString(), + 'operationId': this.comparisonResult.operationId + }).send(); // disable apply and generate script buttons because the results are no longer valid after applying the changes this.setButtonsForRecompare(); @@ -750,10 +755,10 @@ export class SchemaCompareMainWindow { const service = await this.getService(); const result = await service.schemaComparePublishChanges(this.comparisonResult.operationId, this.targetEndpointInfo.serverName, this.targetEndpointInfo.databaseName, azdata.TaskExecutionMode.execute); if (!result || !result.success) { - Telemetry.sendTelemetryEvent('SchemaCompareApplyFailed', { - 'errorType': getTelemetryErrorType(result.errorMessage), - 'operationId': this.comparisonResult.operationId - }); + TelemetryReporter.createErrorEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareApplyFailed', undefined, getTelemetryErrorType(result.errorMessage)) + .withAdditionalProperties({ + 'operationId': this.comparisonResult.operationId + }).send(); vscode.window.showErrorMessage( localize('schemaCompare.updateErrorMessage', "Schema Compare Apply failed '{0}'", result.errorMessage ? result.errorMessage : 'Unknown')); @@ -763,10 +768,11 @@ export class SchemaCompareMainWindow { this.applyButton.enabled = true; this.applyButton.title = applyEnabledMessage; } - Telemetry.sendTelemetryEvent('SchemaCompareApplyEnded', { - 'endTime': Date.now().toString(), - 'operationId': this.comparisonResult.operationId - }); + TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareApplyEnded') + .withAdditionalProperties({ + 'endTime': Date.now().toString(), + 'operationId': this.comparisonResult.operationId + }).send(); } }); }); @@ -841,8 +847,7 @@ export class SchemaCompareMainWindow { }).component(); this.switchButton.onDidClick(async (click) => { - Telemetry.sendTelemetryEvent('SchemaCompareSwitch'); - + TelemetryReporter.sendActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareSwitch'); // switch source and target [this.sourceEndpointInfo, this.targetEndpointInfo] = [this.targetEndpointInfo, this.sourceEndpointInfo]; [this.sourceName, this.targetName] = [this.targetName, this.sourceName]; @@ -885,7 +890,7 @@ export class SchemaCompareMainWindow { }).component(); this.selectSourceButton.onDidClick(() => { - Telemetry.sendTelemetryEvent('SchemaCompareSelectSource'); + TelemetryReporter.sendActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareSelectSource'); let dialog = new SchemaCompareDialog(this); dialog.openDialog(); }); @@ -897,7 +902,7 @@ export class SchemaCompareMainWindow { }).component(); this.selectTargetButton.onDidClick(() => { - Telemetry.sendTelemetryEvent('SchemaCompareSelectTarget'); + TelemetryReporter.sendActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareSelectTarget'); let dialog = new SchemaCompareDialog(this); dialog.openDialog(); }); @@ -914,7 +919,7 @@ export class SchemaCompareMainWindow { }).component(); this.openScmpButton.onDidClick(async (click) => { - Telemetry.sendTelemetryEvent('SchemaCompareOpenScmpStarted'); + TelemetryReporter.sendActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareOpenScmpStarted'); const rootPath = getRootPath(); let fileUris = await vscode.window.showOpenDialog( { @@ -938,9 +943,7 @@ export class SchemaCompareMainWindow { let startTime = Date.now(); const result = await service.schemaCompareOpenScmp(fileUri.fsPath); if (!result || !result.success) { - Telemetry.sendTelemetryEvent('SchemaCompareOpenScmpFailed', { - 'errorType': getTelemetryErrorType(result.errorMessage) - }); + TelemetryReporter.sendErrorEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareOpenScmpFailed', undefined, getTelemetryErrorType(result.errorMessage)); vscode.window.showErrorMessage( localize('schemaCompare.openScmpErrorMessage', "Open scmp failed: '{0}'", (result && result.errorMessage) ? result.errorMessage : 'Unknown')); return; @@ -958,9 +961,10 @@ export class SchemaCompareMainWindow { // clear out any old results this.resetForNewCompare(); - Telemetry.sendTelemetryEvent('SchemaCompareOpenScmpEnded', { - 'elapsedTime:': (Date.now() - startTime).toString() - }); + TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareOpenScmpEnded') + .withAdditionalProperties({ + elapsedTime: (Date.now() - startTime).toString() + }).send(); }); } @@ -1021,22 +1025,22 @@ export class SchemaCompareMainWindow { let targetExcludes: mssql.SchemaCompareObjectId[] = this.convertExcludesToObjectIds(this.originalTargetExcludes); let startTime = Date.now(); - Telemetry.sendTelemetryEvent('SchemaCompareSaveScmp'); + TelemetryReporter.sendActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareSaveScmp'); const service = await this.getService(); const result = await service.schemaCompareSaveScmp(this.sourceEndpointInfo, this.targetEndpointInfo, azdata.TaskExecutionMode.execute, this.deploymentOptions, filePath.fsPath, sourceExcludes, targetExcludes); if (!result || !result.success) { - Telemetry.sendTelemetryEvent('SchemaCompareSaveScmpFailed', { - 'errorType': getTelemetryErrorType(result.errorMessage), - 'operationId': this.comparisonResult.operationId - }); + TelemetryReporter.createErrorEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareSaveScmpFailed', undefined, getTelemetryErrorType(result.errorMessage)) + .withAdditionalProperties({ + operationId: this.comparisonResult.operationId + }).send(); vscode.window.showErrorMessage( localize('schemaCompare.saveScmpErrorMessage', "Save scmp failed: '{0}'", (result && result.errorMessage) ? result.errorMessage : 'Unknown')); } - - Telemetry.sendTelemetryEvent('SchemaCompareSaveScmpEnded', { - 'elapsedTime:': (Date.now() - startTime).toString(), - 'operationId': this.comparisonResult.operationId - }); + TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareSaveScmpEnded') + .withAdditionalProperties({ + elapsedTime: (Date.now() - startTime).toString(), + operationId: this.comparisonResult.operationId + }); }); } diff --git a/extensions/schema-compare/src/telemetry.ts b/extensions/schema-compare/src/telemetry.ts index 90583140c7..af2943fdc9 100644 --- a/extensions/schema-compare/src/telemetry.ts +++ b/extensions/schema-compare/src/telemetry.ts @@ -3,99 +3,17 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as vscode from 'vscode'; -import TelemetryReporter from 'vscode-extension-telemetry'; +import AdsTelemetryReporter from 'ads-extension-telemetry'; import * as Utils from './utils'; const packageJson = require('../package.json'); -export interface ITelemetryEventProperties { - [key: string]: string; +let packageInfo = Utils.getPackageInfo(packageJson); + +export const TelemetryReporter = new AdsTelemetryReporter(packageInfo.name, packageInfo.version, packageInfo.aiKey); + +export enum TelemetryViews { + SchemaCompareMainWindow = 'SchemaCompareMainWindow', + SchemaCompareDialog = 'SchemaCompareDialog' } - -export interface ITelemetryEventMeasures { - [key: string]: number; -} - -/** - * Filters error paths to only include source files. Exported to support testing - */ -export function filterErrorPath(line: string): string { - if (line) { - let values: string[] = line.split('/out/'); - if (values.length <= 1) { - // Didn't match expected format - return line; - } else { - return values[1]; - } - } -} - -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('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 a general error - * @param err The error to log - */ - public static sendTelemetryEventForError(err: string, properties?: ITelemetryEventProperties): void { - this.sendTelemetryEvent('Error', { error: err, ...properties }); - } - - /** - * 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); - } - } -} - -Telemetry.initialize(); diff --git a/extensions/schema-compare/yarn.lock b/extensions/schema-compare/yarn.lock index f624163030..dc9cd0c94d 100644 --- a/extensions/schema-compare/yarn.lock +++ b/extensions/schema-compare/yarn.lock @@ -12,6 +12,12 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.7.tgz#01e4ea724d9e3bd50d90c11fd5980ba317d8fa11" integrity sha512-E6Zn0rffhgd130zbCbAr/JdXfXkoOUFAKNs/rF8qnafSJ8KYaA/j3oz7dcwal+lYjLA7xvdd5J4wdYpCTlP8+w== +"ads-extension-telemetry@github:Charles-Gagnon/ads-extension-telemetry#0.1.0": + version "0.1.0" + resolved "https://codeload.github.com/Charles-Gagnon/ads-extension-telemetry/tar.gz/70c2fea10e9ff6e329c4c5ec0b77017ada514b6d" + dependencies: + vscode-extension-telemetry "0.1.1" + ajv@^6.5.5: version "6.10.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1" @@ -53,10 +59,10 @@ append-buffer@^1.0.2: dependencies: buffer-equal "^1.0.0" -applicationinsights@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.0.1.tgz#53446b830fe8d5d619eee2a278b31d3d25030927" - integrity sha1-U0Rrgw/o1dYZ7uKieLMdPSUDCSc= +applicationinsights@1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.0.8.tgz#db6e3d983cf9f9405fe1ee5ba30ac6e1914537b5" + integrity sha512-KzOOGdphOS/lXWMFZe5440LUdFbrLpMvh2SaRxn7BmiI550KAoSb2gIhiq6kJZ9Ir3AxRRztjhzif+e5P5IXIg== dependencies: diagnostic-channel "0.2.0" diagnostic-channel-publishers "0.2.1" @@ -1597,12 +1603,12 @@ vinyl@^2.0.0, vinyl@^2.0.1, vinyl@^2.0.2: remove-trailing-separator "^1.0.1" replace-ext "^1.0.0" -vscode-extension-telemetry@0.0.18: - version "0.0.18" - resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.18.tgz#602ba20d8c71453aa34533a291e7638f6e5c0327" - integrity sha512-Vw3Sr+dZwl+c6PlsUwrTtCOJkgrmvS3OUVDQGcmpXWAgq9xGq6as0K4pUx+aGqTjzLAESmWSrs6HlJm6J6Khcg== +vscode-extension-telemetry@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.1.1.tgz#91387e06b33400c57abd48979b0e790415ae110b" + integrity sha512-TkKKG/B/J94DP5qf6xWB4YaqlhWDg6zbbqVx7Bz//stLQNnfE9XS1xm3f6fl24c5+bnEK0/wHgMgZYKIKxPeUA== dependencies: - applicationinsights "1.0.1" + applicationinsights "1.0.8" vscode-nls@^4.0.0: version "4.1.1"