mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-31 09:35:39 -05:00
Add initial telemetry for schema compare (#5595)
* add initial telemetry to schema compare * addressing comments
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
102
extensions/schema-compare/src/telemetry.ts
Normal file
102
extensions/schema-compare/src/telemetry.ts
Normal 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();
|
||||
34
extensions/schema-compare/src/utils.ts
Normal file
34
extensions/schema-compare/src/utils.ts
Normal 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';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user