mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
telemetry for tde user actions (#22474)
* telemetry for user actions * remove unused action * try catch around admin function
This commit is contained in:
@@ -13,6 +13,7 @@ import * as constants from '../constants/strings';
|
|||||||
import { logError, TelemetryViews } from '../telemetry';
|
import { logError, TelemetryViews } from '../telemetry';
|
||||||
import { AdsMigrationStatus } from '../dashboard/tabBase';
|
import { AdsMigrationStatus } from '../dashboard/tabBase';
|
||||||
import { getMigrationMode, getMigrationStatus, getMigrationTargetType, hasRestoreBlockingReason, PipelineStatusCodes } from '../constants/helper';
|
import { getMigrationMode, getMigrationStatus, getMigrationTargetType, hasRestoreBlockingReason, PipelineStatusCodes } from '../constants/helper';
|
||||||
|
import * as os from 'os';
|
||||||
|
|
||||||
export type TargetServerType = azure.SqlVMServer | azureResource.AzureSqlManagedInstance | azure.AzureSqlDatabaseServer;
|
export type TargetServerType = azure.SqlVMServer | azureResource.AzureSqlManagedInstance | azure.AzureSqlDatabaseServer;
|
||||||
|
|
||||||
@@ -923,3 +924,20 @@ export async function promptUserForFolder(): Promise<string> {
|
|||||||
|
|
||||||
return '';
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as constants from '../../constants/strings';
|
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 { EOL } from 'os';
|
||||||
import { MigrationStateModel, OperationResult } from '../../models/stateMachine';
|
import { MigrationStateModel, OperationResult } from '../../models/stateMachine';
|
||||||
import { IconPathHelper } from '../../constants/iconPathHelper';
|
import { IconPathHelper } from '../../constants/iconPathHelper';
|
||||||
@@ -317,12 +318,28 @@ export class TdeMigrationDialog {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this._model.tdeMigrationConfig.setTdeMigrationResult(this._tdeMigrationResult); // Set value on success.
|
this._model.tdeMigrationConfig.setTdeMigrationResult(this._tdeMigrationResult); // Set value on success.
|
||||||
|
|
||||||
|
sendSqlMigrationActionEvent(
|
||||||
|
TelemetryViews.TdeMigrationDialog,
|
||||||
|
TelemetryAction.TdeMigrationSuccess,
|
||||||
|
{
|
||||||
|
...getTelemetryProps(this._model)
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this._dialog!.okButton.enabled = false;
|
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;
|
this._startMigrationLoader.loading = false;
|
||||||
@@ -339,6 +356,8 @@ export class TdeMigrationDialog {
|
|||||||
this._copyButton.enabled = false;
|
this._copyButton.enabled = false;
|
||||||
this._dialog!.okButton.enabled = false;
|
this._dialog!.okButton.enabled = false;
|
||||||
this._progressReportText.value = '';
|
this._progressReportText.value = '';
|
||||||
|
|
||||||
|
logError(TelemetryViews.TdeMigrationDialog, TelemetryAction.TdeMigrationClientException, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._headingText.value = constants.TDE_MIGRATE_RESULTS_HEADING_COMPLETED;
|
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)) {
|
if (!this._dbRowsMap.has(dbName)) {
|
||||||
return; //Table not found
|
return; //Table not found
|
||||||
}
|
}
|
||||||
|
|
||||||
this._updateValidationResultRow(dbName, succeeded, message);
|
this._updateValidationResultRow(dbName, succeeded, message);
|
||||||
|
|
||||||
|
if (!succeeded) {
|
||||||
|
logError(TelemetryViews.TdeMigrationDialog, statusCode, {});
|
||||||
|
}
|
||||||
|
|
||||||
// Update the table
|
// Update the table
|
||||||
await this._updateTableData();
|
await this._updateTableData();
|
||||||
|
|
||||||
@@ -522,7 +545,4 @@ export class TdeMigrationDialog {
|
|||||||
return IconPathHelper.notStartedMigration;
|
return IconPathHelper.notStartedMigration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -947,7 +947,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
|||||||
|
|
||||||
public async startTdeMigration(
|
public async startTdeMigration(
|
||||||
accessToken: string,
|
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 tdeEnabledDatabases = this.tdeMigrationConfig.getTdeEnabledDatabases();
|
||||||
const connectionString = await getSourceConnectionString();
|
const connectionString = await getSourceConnectionString();
|
||||||
|
|||||||
@@ -500,7 +500,7 @@ export interface ISqlMigrationService {
|
|||||||
targetManagedInstanceName: string,
|
targetManagedInstanceName: string,
|
||||||
networkSharePath: string,
|
networkSharePath: string,
|
||||||
accessToken: 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 {
|
export interface TdeMigrationRequest {
|
||||||
@@ -547,4 +547,5 @@ export interface TdeMigrateProgressParams {
|
|||||||
name: string;
|
name: string;
|
||||||
success: boolean;
|
success: boolean;
|
||||||
message: string;
|
message: string;
|
||||||
|
statusCode: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export abstract class MigrationExtensionService extends SqlOpsFeature<undefined>
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class SqlMigrationService extends MigrationExtensionService implements contracts.ISqlMigrationService {
|
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;
|
override providerId = ApiType.SqlMigrationProvider;
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ export class SqlMigrationService extends MigrationExtensionService implements co
|
|||||||
if (this._reportUpdate === undefined) {
|
if (this._reportUpdate === undefined) {
|
||||||
return;
|
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,
|
targetManagedInstanceName: string,
|
||||||
networkSharePath: string,
|
networkSharePath: string,
|
||||||
accessToken: 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;
|
this._reportUpdate = reportUpdate;
|
||||||
let params: contracts.TdeMigrationParams = {
|
let params: contracts.TdeMigrationParams = {
|
||||||
@@ -306,7 +306,7 @@ export class SqlMigrationService extends MigrationExtensionService implements co
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// This call needs to be awaited so, the updates are sent during the execution of the task.
|
// 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);
|
const result = await this._client.sendRequest(contracts.TdeMigrateRequest.type, params);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ export enum TelemetryViews {
|
|||||||
LoginMigrationSelectorPage = 'LoginMigrationSelectorPage',
|
LoginMigrationSelectorPage = 'LoginMigrationSelectorPage',
|
||||||
LoginMigrationStatusPage = 'LoginMigrationStatusPage',
|
LoginMigrationStatusPage = 'LoginMigrationStatusPage',
|
||||||
TdeConfigurationDialog = 'TdeConfigurationDialog',
|
TdeConfigurationDialog = 'TdeConfigurationDialog',
|
||||||
|
TdeMigrationDialog = 'TdeMigrationDialog',
|
||||||
ValidIrDialog = 'validIrDialog',
|
ValidIrDialog = 'validIrDialog',
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,10 +77,11 @@ export enum TelemetryAction {
|
|||||||
OpenLoginMigrationWizard = 'OpenLoginMigrationWizard',
|
OpenLoginMigrationWizard = 'OpenLoginMigrationWizard',
|
||||||
LoginMigrationStarted = 'LoginMigrationStarted',
|
LoginMigrationStarted = 'LoginMigrationStarted',
|
||||||
LoginMigrationCompleted = 'LoginMigrationCompleted',
|
LoginMigrationCompleted = 'LoginMigrationCompleted',
|
||||||
}
|
TdeMigrationSuccess = 'TdeMigrationSuccess',
|
||||||
|
TdeMigrationFailures = 'TdeMigrationFailures',
|
||||||
export enum TelemetryErrorName {
|
TdeMigrationClientException = 'TdeMigrationClientException',
|
||||||
StartMigrationFailed = 'StartMigrationFailed'
|
TdeConfigurationUseADS = 'TdeConfigurationUseADS',
|
||||||
|
TdeConfigurationIgnoreADS = 'TdeConfigurationIgnoreADS'
|
||||||
}
|
}
|
||||||
|
|
||||||
export function logError(telemetryView: TelemetryViews, err: string, error: any): void {
|
export function logError(telemetryView: TelemetryViews, err: string, error: any): void {
|
||||||
|
|||||||
@@ -18,10 +18,9 @@ import { IconPath, IconPathHelper } from '../constants/iconPathHelper';
|
|||||||
import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController';
|
import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController';
|
||||||
import * as styles from '../constants/styles';
|
import * as styles from '../constants/styles';
|
||||||
import { SkuEditParametersDialog } from '../dialog/skuRecommendationResults/skuEditParametersDialog';
|
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 { TdeConfigurationDialog } from '../dialog/tdeConfiguration/tdeConfigurationDialog';
|
||||||
import { TdeMigrationModel } from '../models/tdeModels';
|
import { TdeMigrationModel } from '../models/tdeModels';
|
||||||
import * as os from 'os';
|
|
||||||
import { getSourceConnectionProfile } from '../api/sqlUtils';
|
import { getSourceConnectionProfile } from '../api/sqlUtils';
|
||||||
|
|
||||||
export interface Product {
|
export interface Product {
|
||||||
@@ -817,7 +816,7 @@ export class SKURecommendationPage extends MigrationWizardPage {
|
|||||||
if (this._matchWithEncryptedDatabases(encryptedDbFound)) {
|
if (this._matchWithEncryptedDatabases(encryptedDbFound)) {
|
||||||
this.migrationStateModel.tdeMigrationConfig = this._previousMiTdeMigrationConfig;
|
this.migrationStateModel.tdeMigrationConfig = this._previousMiTdeMigrationConfig;
|
||||||
} else {
|
} else {
|
||||||
if (os.platform() !== 'win32') //Only available for windows for now.
|
if (!utils.isWindows()) //Only available for windows for now.
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//Set encrypted databases
|
//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;
|
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);
|
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();
|
return this._tdeEditButton.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user