telemetry for tde user actions (#22474)

* telemetry for user actions

* remove unused action

* try catch around admin function
This commit is contained in:
junierch
2023-03-27 17:48:47 -04:00
committed by GitHub
parent e80c6f2dcb
commit e741fa0bbd
7 changed files with 71 additions and 20 deletions

View File

@@ -13,6 +13,7 @@ import * as constants from '../constants/strings';
import { logError, TelemetryViews } from '../telemetry';
import { AdsMigrationStatus } from '../dashboard/tabBase';
import { getMigrationMode, getMigrationStatus, getMigrationTargetType, hasRestoreBlockingReason, PipelineStatusCodes } from '../constants/helper';
import * as os from 'os';
export type TargetServerType = azure.SqlVMServer | azureResource.AzureSqlManagedInstance | azure.AzureSqlDatabaseServer;
@@ -923,3 +924,20 @@ export async function promptUserForFolder(): Promise<string> {
return '';
}
export function isWindows(): boolean { return (os.platform() === 'win32') }
export async function isAdmin(): Promise<boolean> {
let isAdmin: boolean = false;
try {
if (isWindows()) {
isAdmin = (await import('native-is-elevated'))();
} else {
isAdmin = process.getuid() === 0;
}
} catch (e) {
//Ignore error and return false;
}
return isAdmin;
}

View File

@@ -6,7 +6,8 @@
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import * as constants from '../../constants/strings';
import { logError, TelemetryErrorName, TelemetryViews } from '../../telemetry';
import * as utils from '../../api/utils';
import { logError, TelemetryAction, TelemetryViews, sendSqlMigrationActionEvent, getTelemetryProps } from '../../telemetry';
import { EOL } from 'os';
import { MigrationStateModel, OperationResult } from '../../models/stateMachine';
import { IconPathHelper } from '../../constants/iconPathHelper';
@@ -317,12 +318,28 @@ export class TdeMigrationDialog {
};
this._model.tdeMigrationConfig.setTdeMigrationResult(this._tdeMigrationResult); // Set value on success.
sendSqlMigrationActionEvent(
TelemetryViews.TdeMigrationDialog,
TelemetryAction.TdeMigrationSuccess,
{
...getTelemetryProps(this._model)
},
{}
);
}
else {
this._dialog!.okButton.enabled = false;
const errorDetails = operationResult.errors.join(EOL);
logError(TelemetryViews.MigrationLocalStorage, TelemetryErrorName.StartMigrationFailed, errorDetails);
sendSqlMigrationActionEvent(
TelemetryViews.TdeMigrationDialog,
TelemetryAction.TdeMigrationFailures,
{
...getTelemetryProps(this._model),
'runningAsAdmin': (await utils.isAdmin()).toString()
},
{}
);
}
this._startMigrationLoader.loading = false;
@@ -339,6 +356,8 @@ export class TdeMigrationDialog {
this._copyButton.enabled = false;
this._dialog!.okButton.enabled = false;
this._progressReportText.value = '';
logError(TelemetryViews.TdeMigrationDialog, TelemetryAction.TdeMigrationClientException, error);
}
this._headingText.value = constants.TDE_MIGRATE_RESULTS_HEADING_COMPLETED;
@@ -433,13 +452,17 @@ export class TdeMigrationDialog {
}
}
private async _updateTableResultRow(dbName: string, succeeded: boolean, message: string): Promise<void> {
private async _updateTableResultRow(dbName: string, succeeded: boolean, message: string, statusCode: string): Promise<void> {
if (!this._dbRowsMap.has(dbName)) {
return; //Table not found
}
this._updateValidationResultRow(dbName, succeeded, message);
if (!succeeded) {
logError(TelemetryViews.TdeMigrationDialog, statusCode, {});
}
// Update the table
await this._updateTableData();
@@ -522,7 +545,4 @@ export class TdeMigrationDialog {
return IconPathHelper.notStartedMigration;
}
}
}

View File

@@ -947,7 +947,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
public async startTdeMigration(
accessToken: string,
reportUpdate: (dbName: string, succeeded: boolean, message: string) => Promise<void>): Promise<OperationResult<TdeMigrationDbResult[]>> {
reportUpdate: (dbName: string, succeeded: boolean, message: string, statusCode: string) => Promise<void>): Promise<OperationResult<TdeMigrationDbResult[]>> {
const tdeEnabledDatabases = this.tdeMigrationConfig.getTdeEnabledDatabases();
const connectionString = await getSourceConnectionString();

View File

@@ -500,7 +500,7 @@ export interface ISqlMigrationService {
targetManagedInstanceName: string,
networkSharePath: string,
accessToken: string,
reportUpdate: (dbName: string, succeeded: boolean, message: string) => void): Promise<TdeMigrationResult | undefined>;
reportUpdate: (dbName: string, succeeded: boolean, message: string, statusCode: string) => void): Promise<TdeMigrationResult | undefined>;
}
export interface TdeMigrationRequest {
@@ -547,4 +547,5 @@ export interface TdeMigrateProgressParams {
name: string;
success: boolean;
message: string;
statusCode: string;
}

View File

@@ -26,7 +26,7 @@ export abstract class MigrationExtensionService extends SqlOpsFeature<undefined>
}
export class SqlMigrationService extends MigrationExtensionService implements contracts.ISqlMigrationService {
private _reportUpdate: ((dbName: string, succeeded: boolean, error: string) => void) | undefined = undefined;
private _reportUpdate: ((dbName: string, succeeded: boolean, error: string, statusCode: string) => void) | undefined = undefined;
override providerId = ApiType.SqlMigrationProvider;
@@ -58,7 +58,7 @@ export class SqlMigrationService extends MigrationExtensionService implements co
if (this._reportUpdate === undefined) {
return;
}
this._reportUpdate(e.name, e.success, e.message);
this._reportUpdate(e.name, e.success, e.message, e.statusCode ?? '');
});
}
@@ -288,7 +288,7 @@ export class SqlMigrationService extends MigrationExtensionService implements co
targetManagedInstanceName: string,
networkSharePath: string,
accessToken: string,
reportUpdate: (dbName: string, succeeded: boolean, message: string) => void): Promise<contracts.TdeMigrationResult | undefined> {
reportUpdate: (dbName: string, succeeded: boolean, message: string, statusCode: string) => void): Promise<contracts.TdeMigrationResult | undefined> {
this._reportUpdate = reportUpdate;
let params: contracts.TdeMigrationParams = {
@@ -306,7 +306,7 @@ export class SqlMigrationService extends MigrationExtensionService implements co
try {
// This call needs to be awaited so, the updates are sent during the execution of the task.
// If the task is not await, the finally block will execute and no update will be sent.
// If the task is not awaited, the finally block will execute and no updates will be sent.
const result = await this._client.sendRequest(contracts.TdeMigrateRequest.type, params);
return result;
}

View File

@@ -44,6 +44,7 @@ export enum TelemetryViews {
LoginMigrationSelectorPage = 'LoginMigrationSelectorPage',
LoginMigrationStatusPage = 'LoginMigrationStatusPage',
TdeConfigurationDialog = 'TdeConfigurationDialog',
TdeMigrationDialog = 'TdeMigrationDialog',
ValidIrDialog = 'validIrDialog',
}
@@ -76,10 +77,11 @@ export enum TelemetryAction {
OpenLoginMigrationWizard = 'OpenLoginMigrationWizard',
LoginMigrationStarted = 'LoginMigrationStarted',
LoginMigrationCompleted = 'LoginMigrationCompleted',
}
export enum TelemetryErrorName {
StartMigrationFailed = 'StartMigrationFailed'
TdeMigrationSuccess = 'TdeMigrationSuccess',
TdeMigrationFailures = 'TdeMigrationFailures',
TdeMigrationClientException = 'TdeMigrationClientException',
TdeConfigurationUseADS = 'TdeConfigurationUseADS',
TdeConfigurationIgnoreADS = 'TdeConfigurationIgnoreADS'
}
export function logError(telemetryView: TelemetryViews, err: string, error: any): void {

View File

@@ -18,10 +18,9 @@ import { IconPath, IconPathHelper } from '../constants/iconPathHelper';
import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController';
import * as styles from '../constants/styles';
import { SkuEditParametersDialog } from '../dialog/skuRecommendationResults/skuEditParametersDialog';
import { logError, TelemetryViews } from '../telemetry';
import { logError, TelemetryViews, TelemetryAction, sendSqlMigrationActionEvent, getTelemetryProps } from '../telemetry';
import { TdeConfigurationDialog } from '../dialog/tdeConfiguration/tdeConfigurationDialog';
import { TdeMigrationModel } from '../models/tdeModels';
import * as os from 'os';
import { getSourceConnectionProfile } from '../api/sqlUtils';
export interface Product {
@@ -817,7 +816,7 @@ export class SKURecommendationPage extends MigrationWizardPage {
if (this._matchWithEncryptedDatabases(encryptedDbFound)) {
this.migrationStateModel.tdeMigrationConfig = this._previousMiTdeMigrationConfig;
} else {
if (os.platform() !== 'win32') //Only available for windows for now.
if (!utils.isWindows()) //Only available for windows for now.
return;
//Set encrypted databases
@@ -843,6 +842,17 @@ export class SKURecommendationPage extends MigrationWizardPage {
const tdeMsg = (this.migrationStateModel.tdeMigrationConfig.isTdeMigrationMethodAdsConfirmed()) ? constants.TDE_WIZARD_MSG_TDE : constants.TDE_WIZARD_MSG_MANUAL;
this._tdedatabaseSelectedHelperText.value = constants.TDE_MSG_DATABASES_SELECTED(this.migrationStateModel.tdeMigrationConfig.getTdeEnabledDatabasesCount(), tdeMsg);
const tdeTelemetryAction = (this.migrationStateModel.tdeMigrationConfig.isTdeMigrationMethodAdsConfirmed()) ? TelemetryAction.TdeConfigurationUseADS : TelemetryAction.TdeConfigurationIgnoreADS;
sendSqlMigrationActionEvent(
TelemetryViews.TdeConfigurationDialog,
tdeTelemetryAction,
{
...getTelemetryProps(this.migrationStateModel)
},
{}
);
return this._tdeEditButton.focus();
}