From a8a88ccbebdc545441f28b54587a09a231faa782 Mon Sep 17 00:00:00 2001 From: AkshayMata Date: Wed, 3 May 2023 10:35:44 -0700 Subject: [PATCH] [SQL-Migration] Improve log migrations telemetry (#22927) - Bucketized errors to track top errors - Created separate login migration specific error to improve monitoring --------- Co-authored-by: Akshay Mata --- extensions/sql-migration/config.json | 2 +- .../src/models/loginMigrationModel.ts | 23 ++++++++++++++-- extensions/sql-migration/src/telemetry.ts | 1 + .../src/wizard/loginMigrationStatusPage.ts | 18 ++++++++++--- .../loginMigrationTargetSelectionPage.ts | 12 ++++++++- .../src/wizard/loginSelectorPage.ts | 27 ++++++++++++++++--- 6 files changed, 73 insertions(+), 10 deletions(-) diff --git a/extensions/sql-migration/config.json b/extensions/sql-migration/config.json index 57ab29e29f..bb365ff892 100644 --- a/extensions/sql-migration/config.json +++ b/extensions/sql-migration/config.json @@ -1,7 +1,7 @@ { "downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/{#version#}/microsoft.sqltools.migration-{#fileName#}", "useDefaultLinuxRuntime": true, - "version": "4.7.0.3", + "version": "4.7.0.13", "downloadFileNames": { "Windows_86": "win-x86-net7.0.zip", "Windows": "win-x64-net7.0.zip", diff --git a/extensions/sql-migration/src/models/loginMigrationModel.ts b/extensions/sql-migration/src/models/loginMigrationModel.ts index 3f645787c4..653bb67c89 100644 --- a/extensions/sql-migration/src/models/loginMigrationModel.ts +++ b/extensions/sql-migration/src/models/loginMigrationModel.ts @@ -26,6 +26,12 @@ export enum LoginMigrationStep { MigrationCompleted = 3, } +export const CollectingSourceLoginsFailed = 'Collecting source logins failed'; +export const CollectingTargetLoginsFailed = 'Collecting target logins failed'; +export const ConnectingToTargetFailed = 'Connecting to target failed'; +export const InternalServerError = 'Login Migrations Internal Server Error'; + + export function GetLoginMigrationStepString(step: LoginMigrationStep): string { switch (step) { case LoginMigrationStep.NotStarted: @@ -159,8 +165,21 @@ export class LoginMigrationModel { } private setErrorCountMapPerStep(step: LoginMigrationStep, result: contracts.StartLoginMigrationResult) { - const errorCount = result.exceptionMap ? Object.keys(result.exceptionMap).length : 0; - this.errorCountMap.set(LoginMigrationStep[step], errorCount); + const errorBuckets: Map = new Map(); + + if (!result.exceptionMap) { + return; + } + + for (const exceptions of Object.values(result.exceptionMap)) { + for (const exception of exceptions) { + // Get the value for the key, or the default value of t0 if he key is not in the map + const errorCount = errorBuckets.get(exception.ErrorCodeString) ?? 0; + errorBuckets.set(exception.ErrorCodeString, errorCount + 1) + } + } + + this.errorCountMap.set(LoginMigrationStep[step], errorBuckets); } private setDurationPerStep(step: LoginMigrationStep, result: contracts.StartLoginMigrationResult) { diff --git a/extensions/sql-migration/src/telemetry.ts b/extensions/sql-migration/src/telemetry.ts index 49960192c4..aa5c7d529e 100644 --- a/extensions/sql-migration/src/telemetry.ts +++ b/extensions/sql-migration/src/telemetry.ts @@ -77,6 +77,7 @@ export enum TelemetryAction { OpenLoginMigrationWizard = 'OpenLoginMigrationWizard', LoginMigrationStarted = 'LoginMigrationStarted', LoginMigrationCompleted = 'LoginMigrationCompleted', + LoginMigrationError = 'LoginMigrationError', TdeMigrationSuccess = 'TdeMigrationSuccess', TdeMigrationFailures = 'TdeMigrationFailures', TdeMigrationClientException = 'TdeMigrationClientException', diff --git a/extensions/sql-migration/src/wizard/loginMigrationStatusPage.ts b/extensions/sql-migration/src/wizard/loginMigrationStatusPage.ts index 6bea50f6dc..ce6b50f84e 100644 --- a/extensions/sql-migration/src/wizard/loginMigrationStatusPage.ts +++ b/extensions/sql-migration/src/wizard/loginMigrationStatusPage.ts @@ -14,6 +14,7 @@ import { IconPathHelper } from '../constants/iconPathHelper'; import { LoginMigrationStatusCodes } from '../constants/helper'; import { MultiStepStatusDialog } from '../dialog/generic/multiStepStatusDialog'; import { getTelemetryProps, logError, sendSqlMigrationActionEvent, TelemetryAction, TelemetryViews } from '../telemetry'; +import { InternalServerError } from '../models/loginMigrationModel'; export class LoginMigrationStatusPage extends MigrationWizardPage { private _view!: azdata.ModelView; @@ -93,7 +94,17 @@ export class LoginMigrationStatusPage extends MigrationWizardPage { }; this._progressLoader.loading = false; - logError(TelemetryViews.LoginMigrationWizard, 'LoginMigrationFailed', 'Login Migrations Internal Server Error'); + logError(TelemetryViews.LoginMigrationWizard, 'LoginMigrationFailed', InternalServerError); + + sendSqlMigrationActionEvent( + TelemetryViews.LoginMigrationStatusPage, + TelemetryAction.LoginMigrationError, + { + ...getTelemetryProps(this.migrationStateModel), + 'errorMessage': InternalServerError, + }, + {} + ); } this._logMigrationResult(); @@ -450,9 +461,10 @@ export class LoginMigrationStatusPage extends MigrationWizardPage { 'numberLoginsFailingPerStep': JSON.stringify(Array.from(this.migrationStateModel._loginMigrationModel.errorCountMap)), 'durationPerStepTimestamp': JSON.stringify(Array.from(this.migrationStateModel._loginMigrationModel.durationPerStep)), 'hasSystemError': JSON.stringify(this.migrationStateModel._loginMigrationModel.hasSystemError), - // AKMA TODO: add error code string count map }, - {} + { + 'numberLogins': this.migrationStateModel._loginMigrationModel.loginsForMigration.length, + } ); } } diff --git a/extensions/sql-migration/src/wizard/loginMigrationTargetSelectionPage.ts b/extensions/sql-migration/src/wizard/loginMigrationTargetSelectionPage.ts index f733b49584..42a044bdf7 100644 --- a/extensions/sql-migration/src/wizard/loginMigrationTargetSelectionPage.ts +++ b/extensions/sql-migration/src/wizard/loginMigrationTargetSelectionPage.ts @@ -18,6 +18,7 @@ import { AzureSqlDatabaseServer, getVMInstanceView, SqlVMServer } from '../api/a import { collectSourceLogins, collectTargetLogins, getSourceConnectionId, getSourceConnectionProfile, isSourceConnectionSysAdmin, LoginTableInfo } from '../api/sqlUtils'; import { NetworkInterfaceModel } from '../api/dataModels/azure/networkInterfaceModel'; import { getTelemetryProps, logError, sendSqlMigrationActionEvent, TelemetryAction, TelemetryViews } from '../telemetry'; +import { ConnectingToTargetFailed, } from '../models/loginMigrationModel'; export class LoginMigrationTargetSelectionPage extends MigrationWizardPage { private _view!: azdata.ModelView; @@ -636,7 +637,16 @@ export class LoginMigrationTargetSelectionPage extends MigrationWizardPage { loginsOnTarget, constants.AZURE_SQL_TARGET_CONNECTION_ERROR_TITLE); - logError(TelemetryViews.LoginMigrationTargetSelectionPage, 'ConnectingToTargetFailed', error); + logError(TelemetryViews.LoginMigrationTargetSelectionPage, ConnectingToTargetFailed, error); + sendSqlMigrationActionEvent( + TelemetryViews.LoginMigrationTargetSelectionPage, + TelemetryAction.LoginMigrationError, + { + ...getTelemetryProps(this.migrationStateModel), + 'errorMessage': ConnectingToTargetFailed, + }, + {} + ); connectionSuccessful = false; } finally { diff --git a/extensions/sql-migration/src/wizard/loginSelectorPage.ts b/extensions/sql-migration/src/wizard/loginSelectorPage.ts index 292754f134..466ad011e7 100644 --- a/extensions/sql-migration/src/wizard/loginSelectorPage.ts +++ b/extensions/sql-migration/src/wizard/loginSelectorPage.ts @@ -13,7 +13,8 @@ import * as styles from '../constants/styles'; import { collectSourceLogins, collectTargetLogins, getSourceConnectionId, LoginTableInfo } from '../api/sqlUtils'; import { IconPathHelper } from '../constants/iconPathHelper'; import * as utils from '../api/utils'; -import { logError, TelemetryViews } from '../telemetry'; +import { getTelemetryProps, logError, sendSqlMigrationActionEvent, TelemetryAction, TelemetryViews } from '../telemetry'; +import { CollectingSourceLoginsFailed, CollectingTargetLoginsFailed } from '../models/loginMigrationModel'; export class LoginSelectorPage extends MigrationWizardPage { @@ -367,7 +368,17 @@ export class LoginSelectorPage extends MigrationWizardPage { description: constants.LOGIN_MIGRATIONS_GET_LOGINS_ERROR(error.message), }; - logError(TelemetryViews.LoginMigrationWizard, 'CollectingSourceLoginsFailed', error); + logError(TelemetryViews.LoginMigrationWizard, CollectingSourceLoginsFailed, error); + + sendSqlMigrationActionEvent( + TelemetryViews.LoginMigrationSelectorPage, + TelemetryAction.LoginMigrationError, + { + ...getTelemetryProps(this.migrationStateModel), + 'errorMessage': CollectingSourceLoginsFailed, + }, + {} + ); } } @@ -400,7 +411,17 @@ export class LoginSelectorPage extends MigrationWizardPage { description: constants.LOGIN_MIGRATIONS_GET_LOGINS_ERROR(error.message), }; - logError(TelemetryViews.LoginMigrationWizard, 'CollectingTargetLoginsFailed', error); + logError(TelemetryViews.LoginMigrationWizard, CollectingTargetLoginsFailed, error); + + sendSqlMigrationActionEvent( + TelemetryViews.LoginMigrationSelectorPage, + TelemetryAction.LoginMigrationError, + { + ...getTelemetryProps(this.migrationStateModel), + 'errorMessage': CollectingTargetLoginsFailed, + }, + {} + ); } }