[SKU Recommendation] Adding telemetry for errors happening during data collection/ get recommendation and telemetry (#18345)

* Adding telemetry for errors happening during data collection/ telemetry for sku recommendation

* log and error happended during get sku recommendation

* Resolving comments from PR https://github.com/microsoft/azuredatastudio/pull/18252. 1) Adding click and close events to dispoable collection to avoid leaks. 2) Adding readable constant for number representing minutes.

* Changes - 1) updating migration workflow strings, 2) adding more onclick events to disposable collection.

* Remove PaaS, IaaS terms from string

* Changes -
1) Renamed 'Saved assessment result' to 'saved session'.
2) Removed Title from 'saved session' page.
3) Added stop data collection on migration start.
This commit is contained in:
Neetu Singh
2022-02-16 14:44:28 -08:00
committed by GitHub
parent 7ff42eeb08
commit 80c8b06ec8
6 changed files with 38 additions and 38 deletions

View File

@@ -19,8 +19,8 @@ export function WIZARD_TITLE(instanceName: string): string {
// Resume Migration Dialog
export const RESUME_TITLE = localize('sql.migration.resume.title', "Run migration workflow again");
export const START_MIGRATION = localize('sql.migration.resume.start', "Start with migration assessment again (recommended)");
export const CONTINUE_MIGRATION = localize('sql.migration.resume.continue', "Continue last migration attempt...");
export const START_MIGRATION = localize('sql.migration.resume.start', "Start a new session");
export const CONTINUE_MIGRATION = localize('sql.migration.resume.continue', "Resume previously saved session");
// Databases for assessment
export const DATABASE_FOR_ASSESSMENT_PAGE_TITLE = localize('sql.migration.database.assessment.title', "Databases for assessment");
@@ -63,13 +63,13 @@ export const REFRESH_ASSESSMENT_BUTTON_LABEL = localize('sql.migration.refresh.a
export const SKU_RECOMMENDATION_CHOOSE_A_TARGET = localize('sql.migration.wizard.sku.choose_a_target', "Choose your Azure SQL target");
export const SKU_RECOMMENDATION_MI_CARD_TEXT = localize('sql.migration.sku.mi.card.title', "Azure SQL Managed Instance (PaaS)");
export const SKU_RECOMMENDATION_DB_CARD_TEXT = localize('sql.migration.sku.db.card.title', "Azure SQL Database (PaaS)");
export const SKU_RECOMMENDATION_VM_CARD_TEXT = localize('sql.migration.sku.vm.card.title', "SQL Server on Azure Virtual Machine (IaaS)");
export const SKU_RECOMMENDATION_MI_CARD_TEXT = localize('sql.migration.sku.mi.card.title', "Azure SQL Managed Instance");
export const SKU_RECOMMENDATION_DB_CARD_TEXT = localize('sql.migration.sku.db.card.title', "Azure SQL Database");
export const SKU_RECOMMENDATION_VM_CARD_TEXT = localize('sql.migration.sku.vm.card.title', "SQL Server on Azure Virtual Machine");
export const SELECT_AZURE_MI = localize('sql.migration.select.azure.mi', "Select your target Azure subscription and your target Azure SQL Managed Instance.");
export const SELECT_AZURE_VM = localize('sql.migration.select.azure.vm', "Select your target Azure Subscription and your target SQL Server on Azure Virtual Machine for your target.");
export const SKU_RECOMMENDATION_VIEW_ASSESSMENT_MI = localize('sql.migration.sku.recommendation.view.assessment.mi', "To migrate to Azure SQL Managed Instance (PaaS), view assessment results and select one or more databases.");
export const SKU_RECOMMENDATION_VIEW_ASSESSMENT_VM = localize('sql.migration.sku.recommendation.view.assessment.vm', "To migrate to SQL Server on Azure Virtual Machine (IaaS), view assessment results and select one or more databases.");
export const SKU_RECOMMENDATION_VIEW_ASSESSMENT_MI = localize('sql.migration.sku.recommendation.view.assessment.mi', "To migrate to Azure SQL Managed Instance, view assessment results and select one or more databases.");
export const SKU_RECOMMENDATION_VIEW_ASSESSMENT_VM = localize('sql.migration.sku.recommendation.view.assessment.vm', "To migrate to SQL Server on Azure Virtual Machine, view assessment results and select one or more databases.");
export const VIEW_SELECT_BUTTON_LABEL = localize('sql.migration.view.select.button.label', "View/Select");
export function TOTAL_DATABASES_SELECTED(selectedDbCount: number, totalDbCount: number): string {
return localize('total.databases.selected', "{0} of {1} databases selected", selectedDbCount, totalDbCount);
@@ -232,6 +232,9 @@ export const EMPTY_TIME = localize('sql.migration.sku.recommendations.empty.time
export function LAST_REFRESHED_TIME(d: string = EMPTY_TIME): string {
return localize('sql.migration.sku.recommendations.lastRefreshed', "Last refreshed: {0}", d);
}
export function TIME_IN_MINUTES(val: number): number {
return val * 60000;
}
// Azure SQL Target
export const AZURE_SQL_TARGET_PAGE_TITLE = localize('sql.migration.wizard.target.title', "Azure SQL target");
@@ -721,7 +724,7 @@ export const REFRESH_BUTTON_LABEL = localize('sql.migration.status.refresh.label
// Saved Assessment Dialog
export const NEXT_LABEL = localize('sql.migration.saved.assessment.next', "Next");
export const CANCEL_LABEL = localize('sql.migration.saved.assessment.cancel', "Cancel");
export const SAVED_ASSESSMENT_RESULT = localize('sql.migration.saved.assessment.result', "Saved assessment result");
export const SAVED_ASSESSMENT_RESULT = localize('sql.migration.saved.assessment.result', "Saved session");
// Retry Migration
export const MIGRATION_CANNOT_RETRY = localize('sql.migration.cannot.retry', 'Migration cannot be retried.');

View File

@@ -89,14 +89,6 @@ export class SavedAssessmentDialog {
public initializePageContent(view: azdata.ModelView): azdata.FlexContainer {
const buttonGroup = 'resumeMigration';
const pageTitle = view.modelBuilder.text().withProps({
CSSStyles: {
...styles.PAGE_TITLE_CSS,
'margin-bottom': '12px'
},
value: constants.RESUME_TITLE
}).component();
const radioStart = view.modelBuilder.radioButton().withProps({
label: constants.START_MIGRATION,
name: buttonGroup,
@@ -137,7 +129,6 @@ export class SavedAssessmentDialog {
'margin': '20px 15px',
}
}).component();
flex.addItem(pageTitle, { flex: '0 0 auto' });
flex.addItem(radioStart, { flex: '0 0 auto' });
flex.addItem(radioContinue, { flex: '0 0 auto' });

View File

@@ -308,7 +308,7 @@ export class GetAzureRecommendationDialog {
this.dialog.okButton.label = GetAzureRecommendationDialog.StartButtonText;
this._disposables.push(this.dialog.okButton.onClick(async () => await this.execute()));
this.dialog.cancelButton.onClick(() => this._isOpen = false);
this._disposables.push(this.dialog.cancelButton.onClick(() => this._isOpen = false));
const dialogSetupPromises: Thenable<void>[] = [];
dialogSetupPromises.push(this.initializeDialog(this.dialog));

View File

@@ -207,7 +207,7 @@ export class SkuEditParametersDialog {
this.dialog.okButton.label = SkuEditParametersDialog.UpdateButtonText;
this._disposables.push(this.dialog.okButton.onClick(async () => await this.execute()));
this.dialog.cancelButton.onClick(() => this._isOpen = false);
this._disposables.push(this.dialog.cancelButton.onClick(() => this._isOpen = false));
const dialogSetupPromises: Thenable<void>[] = [];
dialogSetupPromises.push(this.initializeDialog(this.dialog));

View File

@@ -13,7 +13,7 @@ import * as constants from '../constants/strings';
import { MigrationLocalStorage } from './migrationLocalStorage';
import * as nls from 'vscode-nls';
import { v4 as uuidv4 } from 'uuid';
import { sendSqlMigrationActionEvent, TelemetryAction, TelemetryViews } from '../telemtery';
import { sendSqlMigrationActionEvent, TelemetryAction, TelemetryViews, logError } from '../telemtery';
import { hashString, deepClone } from '../api/utils';
import { SKURecommendationPage } from '../wizard/skuRecommendationPage';
const localize = nls.loadMessageBundle();
@@ -218,7 +218,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
public refreshPerfDataCollectionFrequency = this._performanceDataQueryIntervalInSeconds * 1000;
private _autoRefreshPerfDataCollectionHandle!: NodeJS.Timeout;
public refreshGetSkuRecommendationFrequency = 600000; // 10 minutes
public refreshGetSkuRecommendationFrequency = constants.TIME_IN_MINUTES(10);
private _autoRefreshGetSkuRecommendationHandle!: NodeJS.Timeout;
public _skuScalingFactor!: number;
@@ -370,9 +370,6 @@ export class MigrationStateModel implements Model, vscode.Disposable {
// clone list of databases currently being assessed and store them, so that if the user ever changes the list we can refresh new recommendations
this._skuRecommendationRecommendedDatabaseList = this._databaseAssessment.slice();
console.log('sqlinstancerequirements: ');
console.log(this._skuRecommendationApiResponse.instanceRequirements);
if (response?.sqlDbRecommendationResults || response?.sqlMiRecommendationResults || response?.sqlVmRecommendationResults) {
this._skuRecommendationResults = {
recommendations: {
@@ -394,7 +391,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
}
} catch (error) {
console.log(error);
logError(TelemetryViews.SkuRecommendationWizard, 'GetSkuRecommendationFailed', error);
this._skuRecommendationResults = {
recommendations: {
@@ -490,7 +487,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
);
} catch (e) {
console.log(e);
logError(TelemetryViews.SkuRecommendationWizard, 'GetSkuRecommendationTelemetryFailed', e);
}
}
@@ -537,7 +534,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
);
} catch (e) {
console.log(e);
logError(TelemetryViews.DataCollectionWizard, 'StartDataCollectionTelemetryFailed', e);
}
}
@@ -581,7 +578,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
clearInterval(this._autoRefreshGetSkuRecommendationHandle);
}
catch (error) {
console.log(error);
logError(TelemetryViews.DataCollectionWizard, 'StopDataCollectionFailed', error);
}
// Generate telemetry for stop data collection request
@@ -602,7 +599,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
);
} catch (e) {
console.log(e);
logError(TelemetryViews.DataCollectionWizard, 'StopDataCollectionTelemetryFailed', e);
}
}
@@ -620,15 +617,15 @@ export class MigrationStateModel implements Model, vscode.Disposable {
}
}
catch (error) {
console.log(error);
logError(TelemetryViews.DataCollectionWizard, 'RefreshDataCollectionFailed', error);
}
return true;
}
public async isWaitingForFirstTimeRefresh(): Promise<boolean> {
const elapsedTimeInMins = Math.abs(new Date().getTime() - new Date(this._perfDataCollectionStartDate!).getTime()) / 60000;
const skuRecAutoRefreshTimeInMins = this.refreshGetSkuRecommendationFrequency / 60000;
const elapsedTimeInMins = Math.abs(new Date().getTime() - new Date(this._perfDataCollectionStartDate!).getTime()) / constants.TIME_IN_MINUTES(1);
const skuRecAutoRefreshTimeInMins = this.refreshGetSkuRecommendationFrequency / constants.TIME_IN_MINUTES(1);
return elapsedTimeInMins < skuRecAutoRefreshTimeInMins;
}
@@ -1392,6 +1389,14 @@ export class MigrationStateModel implements Model, vscode.Disposable {
localize('sql.migration.starting.migration.error', "An error occurred while starting the migration: '{0}'", e.message));
console.log(e);
}
finally {
// kill existing data collection if user start migration
await this.refreshPerfDataCollection();
if ((!this.resumeAssessment || this.retryMigration) && this._perfDataCollectionIsCollecting) {
void this.stopPerfDataCollection();
void vscode.window.showInformationMessage(constants.AZURE_RECOMMENDATION_STOP_POPUP);
}
}
}
}

View File

@@ -22,6 +22,7 @@ export const WIZARD_INPUT_COMPONENT_WIDTH = '600px';
export class WizardController {
private _wizardObject!: azdata.window.Wizard;
private _model!: MigrationStateModel;
private _disposables: vscode.Disposable[] = [];
constructor(private readonly extensionContext: vscode.ExtensionContext, model: MigrationStateModel) {
this._model = model;
}
@@ -111,16 +112,16 @@ export class WizardController {
this._model.extensionContext.subscriptions.push(this._wizardObject.doneButton.onClick(async (e) => {
await stateModel.startMigration();
}));
saveAndCloseButton.onClick(async () => {
this._disposables.push(saveAndCloseButton.onClick(async () => {
await stateModel.saveInfo(serverName, this._wizardObject.currentPage);
await this._wizardObject.close();
if (stateModel.performanceCollectionInProgress()) {
void vscode.window.showInformationMessage(loc.SAVE_AND_CLOSE_POPUP);
}
});
}));
this._wizardObject.cancelButton.onClick(e => {
this._disposables.push(this._wizardObject.cancelButton.onClick(e => {
sendSqlMigrationActionEvent(
TelemetryViews.SqlMigrationWizard,
TelemetryAction.PageButtonClick,
@@ -129,11 +130,11 @@ export class WizardController {
'buttonPressed': TelemetryAction.Cancel,
'pageTitle': this._wizardObject.pages[this._wizardObject.currentPage].title
}, {});
});
}));
this._wizardObject.doneButton.label = loc.START_MIGRATION_TEXT;
this._wizardObject.doneButton.onClick(e => {
this._disposables.push(this._wizardObject.doneButton.onClick(e => {
sendSqlMigrationActionEvent(
TelemetryViews.SqlMigrationWizard,
TelemetryAction.PageButtonClick,
@@ -142,7 +143,7 @@ export class WizardController {
'buttonPressed': TelemetryAction.Done,
'pageTitle': this._wizardObject.pages[this._wizardObject.currentPage].title
}, {});
});
}));
}
private async sendPageButtonClickEvent(pageChangeInfo: azdata.window.WizardPageChangeInfo) {