Add telemetry to troubleshoot customer issues (#17748)

* Add telemetry to troubleshoot customer issues

* Updating logerror method calls with custom errors

* Add performance telemetry
This commit is contained in:
goyal-anjali
2021-12-06 11:39:41 +05:30
committed by GitHub
parent 8d8b3983a9
commit 80541ce6f0
9 changed files with 51 additions and 21 deletions

View File

@@ -6,6 +6,7 @@
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { MigrationContext, MigrationLocalStorage } from '../models/migrationLocalStorage'; import { MigrationContext, MigrationLocalStorage } from '../models/migrationLocalStorage';
import { logError, TelemetryViews } from '../telemtery';
import * as loc from '../constants/strings'; import * as loc from '../constants/strings';
import { IconPath, IconPathHelper } from '../constants/iconPathHelper'; import { IconPath, IconPathHelper } from '../constants/iconPathHelper';
import { MigrationStatusDialog } from '../dialog/migrationStatus/migrationStatusDialog'; import { MigrationStatusDialog } from '../dialog/migrationStatus/migrationStatusDialog';
@@ -298,7 +299,8 @@ export class DashboardWidget {
} }
} catch (error) { } catch (error) {
console.log(error); logError(TelemetryViews.SqlServerDashboard, 'RefreshgMigrationFailed', error);
} finally { } finally {
this.isRefreshing = false; this.isRefreshing = false;
this._migrationStatusCardLoadingContainer.loading = false; this._migrationStatusCardLoadingContainer.loading = false;

View File

@@ -7,6 +7,7 @@ import * as azdata from 'azdata';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { createSqlMigrationService, getSqlMigrationService, getSqlMigrationServiceAuthKeys, getSqlMigrationServiceMonitoringData, SqlMigrationService } from '../../api/azure'; import { createSqlMigrationService, getSqlMigrationService, getSqlMigrationServiceAuthKeys, getSqlMigrationServiceMonitoringData, SqlMigrationService } from '../../api/azure';
import { MigrationStateModel, NetworkContainerType } from '../../models/stateMachine'; import { MigrationStateModel, NetworkContainerType } from '../../models/stateMachine';
import { logError, TelemetryViews } from '../../telemtery';
import * as constants from '../../constants/strings'; import * as constants from '../../constants/strings';
import * as os from 'os'; import * as os from 'os';
import { azureResource } from 'azureResource'; import { azureResource } from 'azureResource';
@@ -497,7 +498,7 @@ export class CreateSqlMigrationServiceDialog {
description: e.message, description: e.message,
level: azdata.window.MessageLevel.Error level: azdata.window.MessageLevel.Error
}; };
console.log(e); logError(TelemetryViews.CreateDataMigrationServiceDialog, 'FetchSqlMigrationServiceFailed', e);
} }
await new Promise(r => setTimeout(r, 5000)); await new Promise(r => setTimeout(r, 5000));
} }

View File

@@ -12,6 +12,7 @@ import * as loc from '../../constants/strings';
import { convertByteSizeToReadableUnit, convertIsoTimeToLocalTime, getSqlServerName, getMigrationStatusImage, SupportedAutoRefreshIntervals, clearDialogMessage, displayDialogErrorMessage } from '../../api/utils'; import { convertByteSizeToReadableUnit, convertIsoTimeToLocalTime, getSqlServerName, getMigrationStatusImage, SupportedAutoRefreshIntervals, clearDialogMessage, displayDialogErrorMessage } from '../../api/utils';
import { EOL } from 'os'; import { EOL } from 'os';
import { ConfirmCutoverDialog } from './confirmCutoverDialog'; import { ConfirmCutoverDialog } from './confirmCutoverDialog';
import { logError, TelemetryViews } from '../../telemtery';
import { RetryMigrationDialog } from '../retryMigration/retryMigrationDialog'; import { RetryMigrationDialog } from '../retryMigration/retryMigrationDialog';
import * as styles from '../../constants/styles'; import * as styles from '../../constants/styles';
import { canRetryMigration } from '../../constants/helper'; import { canRetryMigration } from '../../constants/helper';
@@ -233,7 +234,7 @@ export class MigrationCutoverDialog {
await this.refreshStatus(); await this.refreshStatus();
}); });
} catch (e) { } catch (e) {
console.log(e); logError(TelemetryViews.MigrationCutoverDialog, 'IntializingFailed', e);
} }
}); });
this._dialogObject.content = [tab]; this._dialogObject.content = [tab];

View File

@@ -5,7 +5,7 @@
import { getMigrationStatus, DatabaseMigration, startMigrationCutover, stopMigration, getMigrationAsyncOperationDetails, AzureAsyncOperationResource, BackupFileInfo, getResourceGroupFromId } from '../../api/azure'; import { getMigrationStatus, DatabaseMigration, startMigrationCutover, stopMigration, getMigrationAsyncOperationDetails, AzureAsyncOperationResource, BackupFileInfo, getResourceGroupFromId } from '../../api/azure';
import { BackupFileInfoStatus, MigrationContext } from '../../models/migrationLocalStorage'; import { BackupFileInfoStatus, MigrationContext } from '../../models/migrationLocalStorage';
import { sendSqlMigrationActionEvent, TelemetryAction, TelemetryViews } from '../../telemtery'; import { logError, sendSqlMigrationActionEvent, TelemetryAction, TelemetryViews } from '../../telemtery';
import * as constants from '../../constants/strings'; import * as constants from '../../constants/strings';
import { EOL } from 'os'; import { EOL } from 'os';
import { getMigrationTargetType, getMigrationMode } from '../../constants/helper'; import { getMigrationTargetType, getMigrationMode } from '../../constants/helper';
@@ -71,7 +71,7 @@ export class MigrationCutoverDialogModel {
} }
} catch (error) { } catch (error) {
this.CutoverError = error; this.CutoverError = error;
console.log(error); logError(TelemetryViews.MigrationCutoverDialog, 'StartCutoverError', error);
} }
return undefined!; return undefined!;
} }
@@ -111,7 +111,7 @@ export class MigrationCutoverDialogModel {
} }
} catch (error) { } catch (error) {
this.CancelMigrationError = error; this.CancelMigrationError = error;
console.log(error); logError(TelemetryViews.MigrationCutoverDialog, 'CancelMigrationError', error);
} }
return undefined!; return undefined!;
} }

View File

@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { azureResource } from 'azureResource'; import { azureResource } from 'azureResource';
import { logError, sendSqlMigrationActionEvent, TelemetryAction, TelemetryViews } from '../telemtery';
import { DatabaseMigration, SqlMigrationService, SqlManagedInstance, getMigrationStatus, AzureAsyncOperationResource, getMigrationAsyncOperationDetails, SqlVMServer, getSubscriptions } from '../api/azure'; import { DatabaseMigration, SqlMigrationService, SqlManagedInstance, getMigrationStatus, AzureAsyncOperationResource, getMigrationAsyncOperationDetails, SqlVMServer, getSubscriptions } from '../api/azure';
import * as azdata from 'azdata'; import * as azdata from 'azdata';
@@ -19,7 +20,7 @@ export class MigrationLocalStorage {
const undefinedSessionId = '{undefined}'; const undefinedSessionId = '{undefined}';
const result: MigrationContext[] = []; const result: MigrationContext[] = [];
const validMigrations: MigrationContext[] = []; const validMigrations: MigrationContext[] = [];
const startTime = new Date().toString();
// fetch saved migrations // fetch saved migrations
const migrationMementos: MigrationContext[] = this.context.globalState.get(this.mementoToken) || []; const migrationMementos: MigrationContext[] = this.context.globalState.get(this.mementoToken) || [];
for (let i = 0; i < migrationMementos.length; i++) { for (let i = 0; i < migrationMementos.length; i++) {
@@ -53,7 +54,7 @@ export class MigrationLocalStorage {
case 'NullMigrationId': case 'NullMigrationId':
continue; continue;
default: default:
console.log(e); logError(TelemetryViews.MigrationLocalStorage, 'MigrationBySourceConnectionError', e);
} }
} }
} }
@@ -62,6 +63,20 @@ export class MigrationLocalStorage {
validMigrations.push(migration); validMigrations.push(migration);
} }
await this.context.globalState.update(this.mementoToken, validMigrations);
sendSqlMigrationActionEvent(
TelemetryViews.MigrationLocalStorage,
TelemetryAction.Done,
{
'startTime': startTime,
'endTime': new Date().toString()
},
{
'migrationCount': migrationMementos.length
}
);
// only save updated migration context // only save updated migration context
if (refreshStatus) { if (refreshStatus) {
const migrations: MigrationContext[] = this.context.globalState.get(this.mementoToken) || []; const migrations: MigrationContext[] = this.context.globalState.get(this.mementoToken) || [];
@@ -79,7 +94,6 @@ export class MigrationLocalStorage {
await this.context.globalState.update(this.mementoToken, migrations); await this.context.globalState.update(this.mementoToken, migrations);
} }
} }
return result; return result;
} }
@@ -121,7 +135,7 @@ export class MigrationLocalStorage {
}); });
await this.context.globalState.update(this.mementoToken, migrationMementos); await this.context.globalState.update(this.mementoToken, migrationMementos);
} catch (e) { } catch (e) {
console.log(e); logError(TelemetryViews.MigrationLocalStorage, 'CantSaveMigration', e);
} }
} }

View File

@@ -14,13 +14,18 @@ export enum TelemetryViews {
SqlServerDashboard = 'SqlServerDashboard', SqlServerDashboard = 'SqlServerDashboard',
CreateDataMigrationServiceDialog = 'CreateDataMigrationServiceDialog', CreateDataMigrationServiceDialog = 'CreateDataMigrationServiceDialog',
AssessmentsDialog = 'AssessmentsDialog', AssessmentsDialog = 'AssessmentsDialog',
DatabaseBackupPage = 'DatabaseBackupPage',
IntegrationRuntimePage = 'IntegrationRuntimePage',
MigrationCutoverDialog = 'MigrationCutoverDialog', MigrationCutoverDialog = 'MigrationCutoverDialog',
MigrationStatusDialog = 'MigrationStatusDialog', MigrationStatusDialog = 'MigrationStatusDialog',
MigrationWizardAccountSelectionPage = 'MigrationWizardAccountSelectionPage', MigrationWizardAccountSelectionPage = 'MigrationWizardAccountSelectionPage',
MigrationWizardTargetSelectionPage = 'MigrationWizardTargetSelectionPage', MigrationWizardTargetSelectionPage = 'MigrationWizardTargetSelectionPage',
MigrationWizardIntegrationRuntimePage = 'MigrationWizardIntegrationRuntimePage',
MigrationWizardSummaryPage = 'MigrationWizardSummaryPage', MigrationWizardSummaryPage = 'MigrationWizardSummaryPage',
MigrationWizardController = 'MigrationWizardController',
StartMigrationService = 'StartMigrationSerivce', StartMigrationService = 'StartMigrationSerivce',
SqlMigrationWizard = 'SqlMigrationWizard' SqlMigrationWizard = 'SqlMigrationWizard',
MigrationLocalStorage = 'MigrationLocalStorage'
} }
export enum TelemetryAction { export enum TelemetryAction {
@@ -41,6 +46,11 @@ export enum TelemetryAction {
Cancel = 'cancel', Cancel = 'cancel',
} }
export function logError(telemetryView: TelemetryViews, err: string, error: any): void {
console.log(error);
TelemetryReporter.sendErrorEvent(telemetryView, err);
}
export function sendSqlMigrationActionEvent(telemetryView: TelemetryViews, telemetryAction: TelemetryAction, additionalProps: TelemetryEventProperties, additionalMeasurements: TelemetryEventMeasures): void { export function sendSqlMigrationActionEvent(telemetryView: TelemetryViews, telemetryAction: TelemetryAction, additionalProps: TelemetryEventProperties, additionalMeasurements: TelemetryEventMeasures): void {
TelemetryReporter.createActionEvent(telemetryView, telemetryAction) TelemetryReporter.createActionEvent(telemetryView, telemetryAction)
.withAdditionalProperties(additionalProps) .withAdditionalProperties(additionalProps)

View File

@@ -13,6 +13,7 @@ import * as constants from '../constants/strings';
import { IconPathHelper } from '../constants/iconPathHelper'; import { IconPathHelper } from '../constants/iconPathHelper';
import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController'; import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController';
import { findDropDownItemIndex, selectDropDownIndex } from '../api/utils'; import { findDropDownItemIndex, selectDropDownIndex } from '../api/utils';
import { logError, TelemetryViews } from '../telemtery';
import { azureResource } from 'azureResource'; import { azureResource } from 'azureResource';
import * as styles from '../constants/styles'; import * as styles from '../constants/styles';
@@ -1233,7 +1234,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
selectDropDownIndex(this._networkShareStorageAccountResourceGroupDropdown, 0); selectDropDownIndex(this._networkShareStorageAccountResourceGroupDropdown, 0);
} }
} catch (error) { } catch (error) {
console.log(error); logError(TelemetryViews.DatabaseBackupPage, 'ErrorLoadingNetworkStorageResourceGroup', error);
} finally { } finally {
this._networkShareStorageAccountResourceGroupDropdown.loading = false; this._networkShareStorageAccountResourceGroupDropdown.loading = false;
await this.loadNetworkShareStorageDropdown(); await this.loadNetworkShareStorageDropdown();
@@ -1246,7 +1247,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
this._networkShareContainerStorageAccountDropdown.values = await this.migrationStateModel.getStorageAccountValues(this.migrationStateModel._databaseBackup.subscription, this.migrationStateModel._databaseBackup.networkShares[0].resourceGroup); this._networkShareContainerStorageAccountDropdown.values = await this.migrationStateModel.getStorageAccountValues(this.migrationStateModel._databaseBackup.subscription, this.migrationStateModel._databaseBackup.networkShares[0].resourceGroup);
selectDropDownIndex(this._networkShareContainerStorageAccountDropdown, 0); selectDropDownIndex(this._networkShareContainerStorageAccountDropdown, 0);
} catch (error) { } catch (error) {
console.log(error); logError(TelemetryViews.DatabaseBackupPage, 'ErrorLoadingNetworkShareStorageDropdown', error);
} finally { } finally {
this._networkShareContainerStorageAccountDropdown.loading = false; this._networkShareContainerStorageAccountDropdown.loading = false;
} }
@@ -1269,7 +1270,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
} }
}); });
} catch (error) { } catch (error) {
console.log(error); logError(TelemetryViews.DatabaseBackupPage, 'ErrorLoadingBlobResourceGroup', error);
} finally { } finally {
this._blobContainerResourceGroupDropdowns.forEach(v => v.loading = false); this._blobContainerResourceGroupDropdowns.forEach(v => v.loading = false);
} }
@@ -1289,7 +1290,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
selectDropDownIndex(this._blobContainerStorageAccountDropdowns[index], 0); selectDropDownIndex(this._blobContainerStorageAccountDropdowns[index], 0);
} }
} catch (error) { } catch (error) {
console.log(error); logError(TelemetryViews.DatabaseBackupPage, 'ErrorLoadingBlobStorageDropdown', error);
} finally { } finally {
this._blobContainerStorageAccountDropdowns[index].loading = false; this._blobContainerStorageAccountDropdowns[index].loading = false;
} }
@@ -1310,7 +1311,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
selectDropDownIndex(this._blobContainerDropdowns[index], 0); selectDropDownIndex(this._blobContainerDropdowns[index], 0);
} }
} catch (error) { } catch (error) {
console.log(error); logError(TelemetryViews.DatabaseBackupPage, 'ErrorLoadingBlobContainers', error);
} finally { } finally {
this._blobContainerDropdowns[index].loading = false; this._blobContainerDropdowns[index].loading = false;
} }
@@ -1331,7 +1332,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
selectDropDownIndex(this._blobContainerLastBackupFileDropdowns[index], 0); selectDropDownIndex(this._blobContainerLastBackupFileDropdowns[index], 0);
} }
} catch (error) { } catch (error) {
console.log(error); logError(TelemetryViews.DatabaseBackupPage, 'ErrorLoadingBlobLastBackupFiles', error);
} finally { } finally {
this._blobContainerLastBackupFileDropdowns[index].loading = false; this._blobContainerLastBackupFileDropdowns[index].loading = false;
} }

View File

@@ -13,6 +13,7 @@ import * as constants from '../constants/strings';
import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController'; import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController';
import { getFullResourceGroupFromId, getLocationDisplayName, getSqlMigrationService, getSqlMigrationServiceAuthKeys, getSqlMigrationServiceMonitoringData, SqlManagedInstance, SqlVMServer } from '../api/azure'; import { getFullResourceGroupFromId, getLocationDisplayName, getSqlMigrationService, getSqlMigrationServiceAuthKeys, getSqlMigrationServiceMonitoringData, SqlManagedInstance, SqlVMServer } from '../api/azure';
import { IconPathHelper } from '../constants/iconPathHelper'; import { IconPathHelper } from '../constants/iconPathHelper';
import { logError, TelemetryViews } from '../telemtery';
import { findDropDownItemIndex, selectDropDownIndex } from '../api/utils'; import { findDropDownItemIndex, selectDropDownIndex } from '../api/utils';
import * as styles from '../constants/styles'; import * as styles from '../constants/styles';
@@ -428,7 +429,7 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
try { try {
await this.loadStatus(); await this.loadStatus();
} catch (error) { } catch (error) {
console.log(error); logError(TelemetryViews.MigrationWizardIntegrationRuntimePage, 'ErrorLoadingMigrationServiceStatus', error);
} finally { } finally {
this._statusLoadingComponent.loading = false; this._statusLoadingComponent.loading = false;
} }
@@ -507,7 +508,7 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
await this._authKeyTable.setDataValues(data); await this._authKeyTable.setDataValues(data);
} }
} catch (e) { } catch (e) {
console.log(e); logError(TelemetryViews.IntegrationRuntimePage, 'ErrorLoadingStatus', e);
} }
} }
} }

View File

@@ -15,7 +15,7 @@ import { IntergrationRuntimePage } from './integrationRuntimePage';
import { SummaryPage } from './summaryPage'; import { SummaryPage } from './summaryPage';
import { MigrationModePage } from './migrationModePage'; import { MigrationModePage } from './migrationModePage';
import { DatabaseSelectorPage } from './databaseSelectorPage'; import { DatabaseSelectorPage } from './databaseSelectorPage';
import { sendSqlMigrationActionEvent, TelemetryAction, TelemetryViews } from '../telemtery'; import { sendSqlMigrationActionEvent, TelemetryAction, TelemetryViews, logError } from '../telemtery';
import * as styles from '../constants/styles'; import * as styles from '../constants/styles';
export const WIZARD_INPUT_COMPONENT_WIDTH = '600px'; export const WIZARD_INPUT_COMPONENT_WIDTH = '600px';
@@ -80,7 +80,7 @@ export class WizardController {
this._model.extensionContext.subscriptions.push(this._wizardObject.onPageChanged(async (pageChangeInfo: azdata.window.WizardPageChangeInfo) => { this._model.extensionContext.subscriptions.push(this._wizardObject.onPageChanged(async (pageChangeInfo: azdata.window.WizardPageChangeInfo) => {
const newPage = pageChangeInfo.newPage; const newPage = pageChangeInfo.newPage;
const lastPage = pageChangeInfo.lastPage; const lastPage = pageChangeInfo.lastPage;
this.sendPageButtonClickEvent(pageChangeInfo).catch(e => console.log(e)); this.sendPageButtonClickEvent(pageChangeInfo).catch(e => logError(TelemetryViews.MigrationWizardController, 'ErrorSendingPageButtonClick', e));
await pages[lastPage]?.onPageLeave(pageChangeInfo); await pages[lastPage]?.onPageLeave(pageChangeInfo);
await pages[newPage]?.onPageEnter(pageChangeInfo); await pages[newPage]?.onPageEnter(pageChangeInfo);
})); }));