Add initial telemetry for schema compare (#5595)

* add initial telemetry to schema compare

* addressing comments
This commit is contained in:
kisantia
2019-05-24 15:32:23 -07:00
committed by GitHub
parent 85b2c4de4a
commit 3d494dcd73
4 changed files with 182 additions and 3 deletions

View File

@@ -11,6 +11,7 @@ import * as os from 'os';
import { SchemaCompareResult } from '../schemaCompareResult';
import { isNullOrUndefined } from 'util';
import { existsSync } from 'fs';
import { Telemetry } from '../telemetry';
const localize = nls.loadMessageBundle();
const OkButtonText: string = localize('schemaCompareDialog.ok', 'Ok');
@@ -137,6 +138,10 @@ export class SchemaCompareDialog {
};
}
Telemetry.sendTelemetryEvent('SchemaCompareStart', {
'sourceIsDacpac': this.sourceIsDacpac.toString(),
'targetIsDacpac': this.targetIsDacpac.toString()
});
let schemaCompareResult = new SchemaCompareResult(sourceName, targetName, sourceEndpointInfo, targetEndpointInfo);
schemaCompareResult.start();
}

View File

@@ -7,9 +7,10 @@ import * as nls from 'vscode-nls';
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import * as os from 'os';
import { SchemaCompareOptionsDialog } from './dialogs/schemaCompareOptionsDialog';
import * as path from 'path';
import { SchemaCompareOptionsDialog } from './dialogs/schemaCompareOptionsDialog';
import { Telemetry } from './telemetry';
import { getTelemetryErrorType } from './utils';
const localize = nls.loadMessageBundle();
const diffEditorTitle = localize('schemaCompare.ObjectDefinitionsTitle', 'Object Definitions');
@@ -180,13 +181,21 @@ export class SchemaCompareResult {
// take updates if any
this.deploymentOptions = this.schemaCompareOptionDialog.deploymentOptions;
}
Telemetry.sendTelemetryEvent('SchemaComparisonStarted');
let service = await SchemaCompareResult.getService('MSSQL');
this.comparisonResult = await service.schemaCompare(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
});
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
});
let data = this.getAllDifferences(this.comparisonResult.differences);
@@ -418,12 +427,24 @@ export class SchemaCompareResult {
}).component();
this.generateScriptButton.onDidClick(async (click) => {
Telemetry.sendTelemetryEvent('SchemaCompareGenerateScriptStarted', {
'startTime:': Date.now().toString(),
'operationId': this.comparisonResult.operationId
});
let service = await SchemaCompareResult.getService('MSSQL');
let 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
});
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
});
});
}
@@ -438,6 +459,9 @@ export class SchemaCompareResult {
}).component();
this.optionsButton.onDidClick(async (click) => {
Telemetry.sendTelemetryEvent('SchemaCompareOptionsOpened', {
'operationId': this.comparisonResult.operationId
});
//restore options from last time
if (this.schemaCompareOptionDialog && this.schemaCompareOptionDialog.deploymentOptions) {
this.deploymentOptions = this.schemaCompareOptionDialog.deploymentOptions;
@@ -459,12 +483,24 @@ export class SchemaCompareResult {
}).component();
this.applyButton.onDidClick(async (click) => {
Telemetry.sendTelemetryEvent('SchemaCompareApplyStarted', {
'startTime': Date.now().toString(),
'operationId': this.comparisonResult.operationId
});
let service = await SchemaCompareResult.getService('MSSQL');
let 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
});
vscode.window.showErrorMessage(
localize('schemaCompare.updateErrorMessage', "Schema Compare Apply failed '{0}'", result.errorMessage ? result.errorMessage : 'Unknown'));
}
Telemetry.sendTelemetryEvent('SchemaCompareApplyEnded', {
'endTime': Date.now().toString(),
'operationId': this.comparisonResult.operationId
});
});
}
@@ -496,6 +532,8 @@ export class SchemaCompareResult {
}).component();
this.switchButton.onDidClick(async (click) => {
Telemetry.sendTelemetryEvent('SchemaCompareSwitch');
// switch source and target
[this.sourceEndpointInfo, this.targetEndpointInfo] = [this.targetEndpointInfo, this.sourceEndpointInfo];
[this.sourceName, this.targetName] = [this.targetName, this.sourceName];

View File

@@ -0,0 +1,102 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as vscode from 'vscode';
import TelemetryReporter from 'vscode-extension-telemetry';
import * as Utils from './utils';
const packageJson = require('../package.json');
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 {
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<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 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();

View File

@@ -0,0 +1,34 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
export interface IPackageInfo {
name: string;
version: string;
aiKey: string;
}
export function getPackageInfo(packageJson: any): IPackageInfo {
if (packageJson) {
return {
name: packageJson.name,
version: packageJson.version,
aiKey: packageJson.aiKey
};
}
}
/**
* Map an error message into a short name for the type of error.
* @param msg The error message to map
*/
export function getTelemetryErrorType(msg: string): string {
if (msg.indexOf('Object reference not set to an instance of an object') !== -1) {
return 'ObjectReferenceNotSet';
}
else {
return 'Other';
}
}