cleanup dacpac extension telemetry (#18778)

* cleanup dacpac extension telemetry

* Add helper function and missing action
This commit is contained in:
Kim Santiago
2022-03-18 15:53:05 -07:00
committed by GitHub
parent f2d4801634
commit 6263cc2f87
2 changed files with 100 additions and 161 deletions

View File

@@ -14,10 +14,14 @@ let packageInfo = Utils.getPackageInfo(packageJson);
export const TelemetryReporter = new AdsTelemetryReporter(packageInfo.name, packageInfo.version, packageInfo.aiKey); export const TelemetryReporter = new AdsTelemetryReporter(packageInfo.name, packageInfo.version, packageInfo.aiKey);
export enum TelemetryViews { export enum TelemetryViews {
DataTierApplicationWizard = 'DataTierApplicationWizard', DataTierApplicationWizard = 'DataTierApplicationWizard'
DeployDacpac = 'DeployDacpac', }
DeployPlanPage = 'DeployPlanPage',
ExportBacpac = 'ExportBacpac', export enum TelemetryAction {
ExtractDacpac = 'ExtractDacpac', DeployDacpac = 'DeployDacpacOperation',
ImportBacpac = 'ImportBacpac' GenerateScript = 'GenerateDeployScriptOperation',
GenerateDeployPlan = 'GenerateDeployPlan',
ExtractDacpac = 'ExtractDacpacOperation',
ExportBacpac = 'ExportBacpacOperation',
ImportBacpac = 'ImportBacpacOperation'
} }

View File

@@ -17,10 +17,9 @@ import { ExtractConfigPage } from './pages/extractConfigPage';
import { ImportConfigPage } from './pages/importConfigPage'; import { ImportConfigPage } from './pages/importConfigPage';
import { DacFxDataModel } from './api/models'; import { DacFxDataModel } from './api/models';
import { BasePage } from './api/basePage'; import { BasePage } from './api/basePage';
import { TelemetryReporter, TelemetryViews } from '../telemetry'; import { TelemetryAction, TelemetryReporter, TelemetryViews } from '../telemetry';
import { TelemetryEventMeasures, TelemetryEventProperties } from '@microsoft/ads-extension-telemetry'; import { TelemetryEventMeasures, TelemetryEventProperties } from '@microsoft/ads-extension-telemetry';
const msSqlProvider = 'MSSQL';
class Page { class Page {
wizardPage: azdata.window.WizardPage; wizardPage: azdata.window.WizardPage;
dacFxPage: BasePage; dacFxPage: BasePage;
@@ -313,155 +312,123 @@ export class DataTierApplicationWizard {
} }
public async deploy(): Promise<mssql.DacFxResult> { public async deploy(): Promise<mssql.DacFxResult> {
const deployStartTime = new Date().getTime();
let service: mssql.IDacFxService;
let ownerUri: string;
let result: mssql.DacFxResult;
let additionalProps: TelemetryEventProperties = {}; let additionalProps: TelemetryEventProperties = {};
let additionalMeasurements: TelemetryEventMeasures = {}; let additionalMeasurements: TelemetryEventMeasures = {};
try {
service = await this.getService(msSqlProvider);
ownerUri = await azdata.connection.getUriForConnection(this.model.server.connectionId);
result = await service.deployDacpac(this.model.filePath, this.model.database, this.model.upgradeExisting, ownerUri, azdata.TaskExecutionMode.execute);
} catch (e) {
additionalProps.exceptionOccurred = 'true';
}
// If result is null which means exception occured, will be adding additional props to the Telemetry const service = await this.getService();
if (!result) { const ownerUri = await azdata.connection.getUriForConnection(this.model.server.connectionId);
additionalProps = { ...additionalProps, ...this.getDacServiceArgsAsProps(service, this.model.database, this.model.filePath, ownerUri) };
} const deployStartTime = new Date().getTime();
additionalProps.deploymentStatus = result?.success.toString(); const result = await service.deployDacpac(this.model.filePath, this.model.database, this.model.upgradeExisting, ownerUri, azdata.TaskExecutionMode.execute);
additionalMeasurements.totalDurationMs = (new Date().getTime() - deployStartTime);
additionalMeasurements.deployDacpacFileSizeBytes = await utils.tryGetFileSize(this.model.filePath);
additionalProps.upgradeExistingDatabase = this.model.upgradeExisting.toString(); additionalProps.upgradeExistingDatabase = this.model.upgradeExisting.toString();
additionalProps.potentialDataLoss = this.model.potentialDataLoss.toString(); additionalProps.potentialDataLoss = this.model.potentialDataLoss.toString();
additionalMeasurements.deployDacpacFileSizeBytes = await utils.tryGetFileSize(this.model.filePath); this.sendDacFxOperationTelemetryEvent(result, TelemetryAction.DeployDacpac, additionalProps, additionalMeasurements);
additionalMeasurements.totalDurationMs = (new Date().getTime() - deployStartTime);
// Deploy Dacpac: 'Deploy button' clicked in deploy summary page, Reporting the event selection to the telemetry
this.sendDacServiceTelemetryEvent(TelemetryViews.DeployDacpac, 'DeployDacpacOperation', additionalProps, additionalMeasurements);
return result; return result;
} }
private async extract(): Promise<mssql.DacFxResult> { private async extract(): Promise<mssql.DacFxResult> {
const extractStartTime = new Date().getTime();
let service: mssql.IDacFxService;
let ownerUri: string;
let result: mssql.DacFxResult;
let additionalProps: TelemetryEventProperties = {};
let additionalMeasurements: TelemetryEventMeasures = {}; let additionalMeasurements: TelemetryEventMeasures = {};
try {
service = await this.getService(msSqlProvider);
ownerUri = await azdata.connection.getUriForConnection(this.model.server.connectionId);
result = await service.extractDacpac(this.model.database, this.model.filePath, this.model.database, this.model.version, ownerUri, azdata.TaskExecutionMode.execute);
} catch (e) {
additionalProps.exceptionOccurred = 'true';
}
// If result is null which means exception occured, will be adding additional props to the Telemetry const service = await this.getService();
if (!result) { const ownerUri = await azdata.connection.getUriForConnection(this.model.server.connectionId);
additionalProps = { ...additionalProps, ...this.getDacServiceArgsAsProps(service, this.model.database, this.model.filePath, ownerUri) };
} const extractStartTime = new Date().getTime();
additionalProps.extractStatus = result?.success.toString(); const result = await service.extractDacpac(this.model.database, this.model.filePath, this.model.database, this.model.version, ownerUri, azdata.TaskExecutionMode.execute);
additionalMeasurements.extractedDacpacFileSizeBytes = await utils.tryGetFileSize(this.model.filePath);
additionalMeasurements.totalDurationMs = (new Date().getTime() - extractStartTime); additionalMeasurements.totalDurationMs = (new Date().getTime() - extractStartTime);
// Extract Dacpac: 'Extract button' clicked in extract summary page, Reporting the event selection to the telemetry additionalMeasurements.extractedDacpacFileSizeBytes = await utils.tryGetFileSize(this.model.filePath);
this.sendDacServiceTelemetryEvent(TelemetryViews.ExtractDacpac, 'ExtractDacpacOperation', additionalProps, additionalMeasurements);
this.sendDacFxOperationTelemetryEvent(result, TelemetryAction.ExtractDacpac, undefined, additionalMeasurements);
return result; return result;
} }
private async export(): Promise<mssql.DacFxResult> { private async export(): Promise<mssql.DacFxResult> {
const exportStartTime = new Date().getTime();
let service: mssql.IDacFxService;
let ownerUri: string;
let result: mssql.DacFxResult;
let additionalProps: TelemetryEventProperties = {};
let additionalMeasurements: TelemetryEventMeasures = {}; let additionalMeasurements: TelemetryEventMeasures = {};
try {
service = await this.getService(msSqlProvider);
ownerUri = await azdata.connection.getUriForConnection(this.model.server.connectionId);
result = await service.exportBacpac(this.model.database, this.model.filePath, ownerUri, azdata.TaskExecutionMode.execute);
} catch (e) {
additionalProps.exceptionOccurred = 'true';
}
// If result is null which means exception occured, will be adding additional props to the Telemetry const service = await this.getService();
if (!result) { const ownerUri = await azdata.connection.getUriForConnection(this.model.server.connectionId);
additionalProps = { ...additionalProps, ...this.getDacServiceArgsAsProps(service, this.model.database, this.model.filePath, ownerUri) };
} const exportStartTime = new Date().getTime();
additionalProps.exportStatus = result?.success.toString(); const result = await service.exportBacpac(this.model.database, this.model.filePath, ownerUri, azdata.TaskExecutionMode.execute);
additionalMeasurements.exportedBacpacFileSizeBytes = await utils.tryGetFileSize(this.model.filePath);
additionalMeasurements.totalDurationMs = (new Date().getTime() - exportStartTime); additionalMeasurements.totalDurationMs = (new Date().getTime() - exportStartTime);
// Export Bacpac: 'Export button' clicked in Export summary page, Reporting the event selection to the telemetry additionalMeasurements.exportedBacpacFileSizeBytes = await utils.tryGetFileSize(this.model.filePath);
this.sendDacServiceTelemetryEvent(TelemetryViews.ExportBacpac, 'ExportBacpacOperation', additionalProps, additionalMeasurements);
this.sendDacFxOperationTelemetryEvent(result, TelemetryAction.ExportBacpac, undefined, additionalMeasurements);
return result; return result;
} }
private async import(): Promise<mssql.DacFxResult> { private async import(): Promise<mssql.DacFxResult> {
const importStartTime = new Date().getTime();
let service: mssql.IDacFxService;
let ownerUri: string;
let result: mssql.DacFxResult;
let additionalProps: TelemetryEventProperties = {};
let additionalMeasurements: TelemetryEventMeasures = {}; let additionalMeasurements: TelemetryEventMeasures = {};
try {
service = await this.getService(msSqlProvider);
ownerUri = await azdata.connection.getUriForConnection(this.model.server.connectionId);
result = await service.importBacpac(this.model.filePath, this.model.database, ownerUri, azdata.TaskExecutionMode.execute);
} catch (e) {
additionalProps.exceptionOccurred = 'true';
}
// If result is null which means exception occured, will be adding additional props to the Telemetry const service = await this.getService();
if (!result) { const ownerUri = await azdata.connection.getUriForConnection(this.model.server.connectionId);
additionalProps = { ...additionalProps, ...this.getDacServiceArgsAsProps(service, this.model.database, this.model.filePath, ownerUri) };
} const importStartTime = new Date().getTime();
additionalProps.importStatus = result?.success.toString(); const result = await service.importBacpac(this.model.filePath, this.model.database, ownerUri, azdata.TaskExecutionMode.execute);
additionalMeasurements.importedBacpacFileSizeBytes = await utils.tryGetFileSize(this.model.filePath);
additionalMeasurements.totalDurationMs = (new Date().getTime() - importStartTime); additionalMeasurements.totalDurationMs = (new Date().getTime() - importStartTime);
// Import Bacpac: 'Import button' clicked in Import summary page, Reporting the event selection to the telemetry additionalMeasurements.importedBacpacFileSizeBytes = await utils.tryGetFileSize(this.model.filePath);
this.sendDacServiceTelemetryEvent(TelemetryViews.ImportBacpac, 'ImportBacpacOperation', additionalProps, additionalMeasurements);
this.sendDacFxOperationTelemetryEvent(result, TelemetryAction.ImportBacpac, undefined, additionalMeasurements);
return result; return result;
} }
public async generateDeployScript(): Promise<mssql.DacFxResult> { public async generateDeployScript(): Promise<mssql.DacFxResult> {
const genScriptStartTime = new Date().getTime();
let service: mssql.IDacFxService;
let ownerUri: string;
let result: mssql.DacFxResult;
let additionalProps: TelemetryEventProperties = {}; let additionalProps: TelemetryEventProperties = {};
let additionalMeasurements: TelemetryEventMeasures = {}; let additionalMeasurements: TelemetryEventMeasures = {};
try { this.wizard.message = {
this.wizard.message = { text: loc.generatingScriptMessage,
text: loc.generatingScriptMessage, level: azdata.window.MessageLevel.Information
level: azdata.window.MessageLevel.Information, };
description: ''
};
service = await this.getService(msSqlProvider); const service = await this.getService();
ownerUri = await azdata.connection.getUriForConnection(this.model.server.connectionId); const ownerUri = await azdata.connection.getUriForConnection(this.model.server.connectionId);
result = await service.generateDeployScript(this.model.filePath, this.model.database, ownerUri, azdata.TaskExecutionMode.script);
} catch (e) {
additionalProps.exceptionOccurred = 'true';
}
if (!result || !result.success) { const genScriptStartTime = new Date().getTime();
vscode.window.showErrorMessage(loc.generateDeployErrorMessage(result?.errorMessage)); const result = await service.generateDeployScript(this.model.filePath, this.model.database, ownerUri, azdata.TaskExecutionMode.script);
}
// If result is null which means exception occured, will be adding additional props to the Telemetry
if (!result) {
additionalProps = { ...additionalProps, ...this.getDacServiceArgsAsProps(service, this.model.database, this.model.filePath, ownerUri) };
}
additionalProps.isScriptGenerated = result?.success.toString();
additionalProps.potentialDataLoss = this.model.potentialDataLoss.toString();
additionalMeasurements.deployDacpacFileSizeBytes = await utils.tryGetFileSize(this.model.filePath);
additionalMeasurements.totalDurationMs = (new Date().getTime() - genScriptStartTime); additionalMeasurements.totalDurationMs = (new Date().getTime() - genScriptStartTime);
// Deploy Dacpac 'generate script' button clicked in DeployPlanPage, Reporting the event selection to the telemetry with fail/sucess status additionalMeasurements.deployDacpacFileSizeBytes = await utils.tryGetFileSize(this.model.filePath);
this.sendDacServiceTelemetryEvent(TelemetryViews.DeployDacpac, 'GenerateDeployScriptOperation', additionalProps, additionalMeasurements); additionalProps.potentialDataLoss = this.model.potentialDataLoss.toString();
this.sendDacFxOperationTelemetryEvent(result, TelemetryAction.GenerateScript, undefined, additionalMeasurements);
if (!result?.success && result.errorMessage) {
vscode.window.showErrorMessage(loc.generateDeployErrorMessage(result.errorMessage));
}
return result; return result;
} }
public async generateDeployPlan(): Promise<string> {
let additionalMeasurements: TelemetryEventMeasures = {};
const service = await this.getService();
const ownerUri = await azdata.connection.getUriForConnection(this.model.server.connectionId);
const deployPlanStartTime = new Date().getTime();
const result = await service.generateDeployPlan(this.model.filePath, this.model.database, ownerUri, azdata.TaskExecutionMode.execute);
additionalMeasurements.totalDurationMs = (new Date().getTime() - deployPlanStartTime);
this.sendDacFxOperationTelemetryEvent(result, TelemetryAction.GenerateDeployPlan, undefined, additionalMeasurements);
if (!result?.success && result.errorMessage) {
vscode.window.showErrorMessage(loc.deployPlanErrorMessage(result.errorMessage));
}
return result.report;
}
public getPage(idx: number): Page { public getPage(idx: number): Page {
let page: Page; let page: Page;
@@ -501,56 +468,24 @@ export class DataTierApplicationWizard {
|| (this.selectedOperation === Operation.deploy) && idx === DeployOperationPath.summary; || (this.selectedOperation === Operation.deploy) && idx === DeployOperationPath.summary;
} }
public async generateDeployPlan(): Promise<string> { private async getService(): Promise<mssql.IDacFxService> {
const deployPlanStartTime = new Date().getTime();
let service: mssql.IDacFxService;
let ownerUri: string;
let result: mssql.GenerateDeployPlanResult;
let additionalProps: TelemetryEventProperties = {};
let additionalMeasurements: TelemetryEventMeasures = {};
try {
service = await this.getService(msSqlProvider);
ownerUri = await azdata.connection.getUriForConnection(this.model.server.connectionId);
result = await service.generateDeployPlan(this.model.filePath, this.model.database, ownerUri, azdata.TaskExecutionMode.execute);
} catch (e) {
additionalProps.exceptionOccurred = 'true';
}
if (!result || !result.success) {
vscode.window.showErrorMessage(loc.deployPlanErrorMessage(result?.errorMessage));
}
// If result is null which means exception occured, will be adding additional props to the Telemetry
if (!result) {
additionalProps = { ...additionalProps, ...this.getDacServiceArgsAsProps(service, this.model.database, this.model.filePath, ownerUri) };
}
additionalProps.isPlanGenerated = result?.success.toString();
additionalMeasurements.totalDurationMs = (new Date().getTime() - deployPlanStartTime);
// send Generate deploy plan error/succes telemetry event
this.sendDacServiceTelemetryEvent(TelemetryViews.DeployPlanPage, 'GenerateDeployPlanOperation', additionalProps, additionalMeasurements);
return result.report;
}
private async getService(providerName: string): Promise<mssql.IDacFxService> {
if (!this.dacfxService) { if (!this.dacfxService) {
this.dacfxService = (vscode.extensions.getExtension(mssql.extension.name).exports as mssql.IExtension).dacFx; this.dacfxService = (vscode.extensions.getExtension(mssql.extension.name).exports as mssql.IExtension).dacFx;
} }
return this.dacfxService; return this.dacfxService;
} }
public getDacServiceArgsAsProps(service: mssql.IDacFxService, database: string, filePath: string, ownerUri: string): { [k: string]: string } { private sendDacFxOperationTelemetryEvent(result: azdata.ResultStatus, telemetryAction: string, additionalProps: TelemetryEventProperties, additionalMeasurements: TelemetryEventMeasures): void {
return { if (result?.success) {
isServiceExist: (!!service).toString(), TelemetryReporter.createActionEvent(TelemetryViews.DataTierApplicationWizard, telemetryAction)
isDatabaseExists: (!!database).toString(), .withAdditionalProperties(additionalProps)
isFilePathExist: (!!filePath).toString(), .withAdditionalMeasurements(additionalMeasurements)
isOwnerUriExist: (!!ownerUri).toString() .send();
}; } else {
} TelemetryReporter.createErrorEvent(TelemetryViews.DataTierApplicationWizard, telemetryAction)
.withAdditionalProperties(additionalProps)
private sendDacServiceTelemetryEvent(telemetryView: string, telemetryAction: string, additionalProps: TelemetryEventProperties, additionalMeasurements: TelemetryEventMeasures): void { .withAdditionalMeasurements(additionalMeasurements)
TelemetryReporter.createActionEvent(telemetryView, telemetryAction) .send();
.withAdditionalProperties(additionalProps) }
.withAdditionalMeasurements(additionalMeasurements)
.send();
} }
} }