Added data points for Table Designer (#18182)

* added server infor and metrics for table designer

* update generate script

* pr comments

* format more files

* pr comments

* make changes to core

* remove unused imports

* add server info

* revert enum change and add publish event

* format doc

* nitpicks

* remove os version

* remove modifier from telemetry info

* remove error message
This commit is contained in:
Aditya Bist
2022-02-02 12:40:05 -08:00
committed by GitHub
parent de1a0f4f0f
commit de5090e47a
14 changed files with 117 additions and 19 deletions

View File

@@ -28,7 +28,7 @@ import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { serializableToMap } from 'sql/base/common/map';
import { IAssessmentService } from 'sql/workbench/services/assessment/common/interfaces';
import { IDataGridProviderService } from 'sql/workbench/services/dataGridProvider/common/dataGridProviderService';
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
import { IAdsTelemetryService, ITelemetryEventProperties } from 'sql/platform/telemetry/common/telemetry';
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
import { ITableDesignerService } from 'sql/workbench/services/tableDesigner/common/interface';
@@ -646,8 +646,8 @@ export class MainThreadDataProtocol extends Disposable implements MainThreadData
}
// Table Designer
public $openTableDesigner(providerId: string, tableInfo: azdata.designers.TableInfo): void {
this._tableDesignerService.openTableDesigner(providerId, tableInfo);
public $openTableDesigner(providerId: string, tableInfo: azdata.designers.TableInfo, telemetryInfo?: ITelemetryEventProperties): void {
this._tableDesignerService.openTableDesigner(providerId, tableInfo, telemetryInfo);
}
public $unregisterProvider(handle: number): Promise<any> {

View File

@@ -14,6 +14,7 @@ import { IURITransformer } from 'vs/base/common/uriIpc';
import { URI, UriComponents } from 'vs/base/common/uri';
import { RunOnceScheduler } from 'vs/base/common/async';
import { mapToSerializable } from 'sql/base/common/map';
import { ITelemetryEventProperties } from 'sql/platform/telemetry/common/telemetry';
export class ExtHostDataProtocol extends ExtHostDataProtocolShape {
@@ -916,8 +917,8 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape {
return this._resolveProvider<azdata.designers.TableDesignerProvider>(handle).disposeTableDesigner(table);
}
public override $openTableDesigner(providerId: string, tableInfo: azdata.designers.TableInfo): Promise<void> {
this._proxy.$openTableDesigner(providerId, tableInfo);
public override $openTableDesigner(providerId: string, tableInfo: azdata.designers.TableInfo, telemetryInfo?: ITelemetryEventProperties): Promise<void> {
this._proxy.$openTableDesigner(providerId, tableInfo, telemetryInfo);
return Promise.resolve();
}
}

View File

@@ -36,6 +36,7 @@ import { IExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { ExtHostWorkspace } from 'sql/workbench/api/common/extHostWorkspace';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
import { URI } from 'vs/base/common/uri';
import { ITelemetryEventProperties } from 'sql/platform/telemetry/common/telemetry';
export interface IAzdataExtensionApiFactory {
(extension: IExtensionDescription): typeof azdata;
@@ -578,8 +579,8 @@ export function createAdsApiFactory(accessor: ServicesAccessor): IAdsExtensionAp
TableIndexProperty: sqlExtHostTypes.designers.TableIndexProperty,
TableIndexColumnSpecificationProperty: sqlExtHostTypes.designers.TableIndexColumnSpecificationProperty,
DesignerEditType: sqlExtHostTypes.designers.DesignerEditType,
openTableDesigner(providerId, tableInfo: azdata.designers.TableInfo): Promise<void> {
return extHostDataProvider.$openTableDesigner(providerId, tableInfo);
openTableDesigner(providerId, tableInfo: azdata.designers.TableInfo, telemetryInfo?: ITelemetryEventProperties): Promise<void> {
return extHostDataProvider.$openTableDesigner(providerId, tableInfo, telemetryInfo);
}
};

View File

@@ -28,6 +28,7 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'
import { IQueryEvent } from 'sql/workbench/services/query/common/queryModel';
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
import { TreeDataTransferDTO } from 'vs/workbench/api/common/shared/treeDataTransfer';
import { ITelemetryEventProperties } from 'sql/platform/telemetry/common/telemetry';
export abstract class ExtHostAccountManagementShape {
$autoOAuthCancelled(handle: number): Thenable<void> { throw ni(); }
@@ -560,7 +561,7 @@ export abstract class ExtHostDataProtocolShape {
/**
* Open a new instance of table designer.
*/
$openTableDesigner(providerId: string, tableInfo: azdata.designers.TableInfo, designerInfo: azdata.designers.TableDesignerInfo): void { throw ni(); }
$openTableDesigner(providerId: string, tableInfo: azdata.designers.TableInfo, telemetryInfo?: ITelemetryEventProperties): void { throw ni(); }
}
/**
@@ -650,7 +651,7 @@ export interface MainThreadDataProtocolShape extends IDisposable {
$onSessionStopped(handle: number, response: azdata.ProfilerSessionStoppedParams): void;
$onProfilerSessionCreated(handle: number, response: azdata.ProfilerSessionCreatedParams): void;
$onJobDataUpdated(handle: Number): void;
$openTableDesigner(providerId: string, tableInfo: azdata.designers.TableInfo): void;
$openTableDesigner(providerId: string, tableInfo: azdata.designers.TableInfo, telemetryInfo?: ITelemetryEventProperties): void;
/**
* Callback when a session has completed initialization

View File

@@ -27,11 +27,12 @@ export class TableDesignerInput extends EditorInput {
constructor(
private _provider: TableDesignerProvider,
private _tableInfo: azdata.designers.TableInfo,
telemetryInfo: { [key: string]: string },
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@IEditorService editorService: IEditorService,
@INotificationService private readonly _notificationService: INotificationService) {
super();
this._designerComponentInput = this._instantiationService.createInstance(TableDesignerComponentInput, this._provider, this._tableInfo);
this._designerComponentInput = this._instantiationService.createInstance(TableDesignerComponentInput, this._provider, this._tableInfo, telemetryInfo);
this._register(this._designerComponentInput.onStateChange((e) => {
if (e.currentState.dirty !== e.previousState.dirty) {
this._onDidChangeDirty.fire();

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import { DesignerViewModel, DesignerEdit, DesignerComponentInput, DesignerView, DesignerTab, DesignerDataPropertyInfo, DropDownProperties, DesignerTableProperties, DesignerEditProcessedEventArgs, DesignerAction, DesignerStateChangedEventArgs } from 'sql/workbench/browser/designer/interfaces';
import { DesignerViewModel, DesignerEdit, DesignerComponentInput, DesignerView, DesignerTab, DesignerDataPropertyInfo, DropDownProperties, DesignerTableProperties, DesignerEditProcessedEventArgs, DesignerAction, DesignerStateChangedEventArgs, DesignerEditPath } from 'sql/workbench/browser/designer/interfaces';
import { TableDesignerProvider } from 'sql/workbench/services/tableDesigner/common/interface';
import { localize } from 'vs/nls';
import { designers } from 'sql/workbench/api/common/sqlExtHostTypes';
@@ -14,6 +14,8 @@ import { deepClone, equals } from 'vs/base/common/objects';
import { IQueryEditorService } from 'sql/workbench/services/queryEditor/common/queryEditorService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { TableDesignerPublishDialogResult, TableDesignerPublishDialog } from 'sql/workbench/services/tableDesigner/browser/tableDesignerPublishDialog';
import { IAdsTelemetryService, ITelemetryEventProperties } from 'sql/platform/telemetry/common/telemetry';
import { TelemetryAction, TelemetryView } from 'sql/platform/telemetry/common/telemetryKeys';
export class TableDesignerComponentInput implements DesignerComponentInput {
@@ -31,9 +33,15 @@ export class TableDesignerComponentInput implements DesignerComponentInput {
public readonly onEditProcessed: Event<DesignerEditProcessedEventArgs> = this._onEditProcessed.event;
public readonly onStateChange: Event<DesignerStateChangedEventArgs> = this._onStateChange.event;
private readonly designerEditTypeDisplayValue: { [key: number]: string } = {
0: 'Add', 1: 'Remove', 2: 'Update'
};
constructor(private readonly _provider: TableDesignerProvider,
private _tableInfo: azdata.designers.TableInfo,
private _telemetryInfo: ITelemetryEventProperties,
@INotificationService private readonly _notificationService: INotificationService,
@IAdsTelemetryService readonly _adsTelemetryService: IAdsTelemetryService,
@IQueryEditorService private readonly _queryEditorService: IQueryEditorService,
@IInstantiationService private readonly _instantiationService: IInstantiationService) {
}
@@ -63,6 +71,11 @@ export class TableDesignerComponentInput implements DesignerComponentInput {
}
processEdit(edit: DesignerEdit): void {
const telemetryInfo = this.createTelemetryInfo();
telemetryInfo.tableObjectType = this.getObjectTypeFromPath(edit.path);
const editAction = this._adsTelemetryService.createActionEvent(TelemetryView.TableDesigner,
this.designerEditTypeDisplayValue[edit.type]).withAdditionalProperties(telemetryInfo);
const startTime = new Date().getTime();
this.updateState(this.valid, this.dirty, 'processEdit');
this._provider.processTableEdit(this._tableInfo, edit).then(
result => {
@@ -76,10 +89,15 @@ export class TableDesignerComponentInput implements DesignerComponentInput {
errors: result.errors
}
});
editAction.withAdditionalMeasurements({
'elapsedTimeMs': new Date().getTime() - startTime
}).send();
},
error => {
this._notificationService.error(localize('tableDesigner.errorProcessingEdit', "An error occured while processing the change: {0}", error?.message ?? error));
this.updateState(this.valid, this.dirty);
this._adsTelemetryService.createErrorEvent(TelemetryView.TableDesigner,
this.designerEditTypeDisplayValue[edit.type]).withAdditionalProperties(telemetryInfo).send();
}
);
}
@@ -90,35 +108,49 @@ export class TableDesignerComponentInput implements DesignerComponentInput {
message: localize('tableDesigner.generatingScript', "Generating script..."),
sticky: true
});
const telemetryInfo = this.createTelemetryInfo();
const generateScriptEvent = this._adsTelemetryService.createActionEvent(TelemetryView.TableDesigner, TelemetryAction.GenerateScript).withAdditionalProperties(telemetryInfo);
const startTime = new Date().getTime();
try {
this.updateState(this.valid, this.dirty, 'generateScript');
const script = await this._provider.generateScript(this._tableInfo);
this._queryEditorService.newSqlEditor({ initalContent: script });
this.updateState(this.valid, this.dirty);
notificationHandle.updateMessage(localize('tableDesigner.generatingScriptCompleted', "Script generated."));
generateScriptEvent.withAdditionalMeasurements({
'elapsedTimeMs': new Date().getTime() - startTime
}).send();
} catch (error) {
notificationHandle.updateSeverity(Severity.Error);
notificationHandle.updateMessage(localize('tableDesigner.generateScriptError', "An error occured while generating the script: {0}", error?.message ?? error));
this.updateState(this.valid, this.dirty);
this._adsTelemetryService.createErrorEvent(TelemetryView.TableDesigner, TelemetryAction.GenerateScript).withAdditionalProperties(telemetryInfo).send();
}
}
async publishChanges(): Promise<void> {
const telemetryInfo = this.createTelemetryInfo();
const publishEvent = this._adsTelemetryService.createActionEvent(TelemetryView.TableDesigner, TelemetryAction.PublishChanges).withAdditionalProperties(telemetryInfo);
const saveNotificationHandle = this._notificationService.notify({
severity: Severity.Info,
message: localize('tableDesigner.savingChanges', "Saving table designer changes..."),
sticky: true
});
const startTime = new Date().getTime();
try {
this.updateState(this.valid, this.dirty, 'save');
await this._provider.publishChanges(this._tableInfo);
this._originalViewModel = this._viewModel;
this.updateState(true, false);
saveNotificationHandle.updateMessage(localize('tableDesigner.publishChangeSuccess', "The changes have been successfully published."));
publishEvent.withAdditionalMeasurements({
'elapsedTimeMs': new Date().getTime() - startTime
}).send();
} catch (error) {
saveNotificationHandle.updateSeverity(Severity.Error);
saveNotificationHandle.updateMessage(localize('tableDesigner.publishChangeError', "An error occured while publishing changes: {0}", error?.message ?? error));
this.updateState(this.valid, this.dirty);
this._adsTelemetryService.createErrorEvent(TelemetryView.TableDesigner, TelemetryAction.PublishChanges).withAdditionalProperties(telemetryInfo).send();
}
}
@@ -580,4 +612,36 @@ export class TableDesignerComponentInput implements DesignerComponentInput {
this._viewModel[property] = {};
}
}
private createTelemetryInfo(): ITelemetryEventProperties {
let telemetryInfo = {
provider: this._provider.providerId,
isNewTable: this._tableInfo.isNewTable,
};
Object.assign(telemetryInfo, this._telemetryInfo);
return telemetryInfo;
}
/**
* 1. 'Add' scenario
a. ['propertyName1']. Example: add a column to the columns property: ['columns'].
b. ['propertyName1',index-1,'propertyName2']. Example: add a column mapping to the first foreign key: ['foreignKeys',0,'mappings'].
2. 'Update' scenario
a. ['propertyName1']. Example: update the name of the table: ['name'].
b. ['propertyName1',index-1,'propertyName2']. Example: update the name of a column: ['columns',0,'name'].
c. ['propertyName1',index-1,'propertyName2',index-2,'propertyName3']. Example: update the source column of an entry in a foreign key's column mapping table: ['foreignKeys',0,'mappings',0,'source'].
3. 'Remove' scenario
a. ['propertyName1',index-1]. Example: remove a column from the columns property: ['columns',0'].
b. ['propertyName1',index-1,'proper
The return values would be the propertyNames followed by slashes in level order. Eg.: propertyName1/propertyName2/...
*/
private getObjectTypeFromPath(path: DesignerEditPath): string {
let typeArray = [];
for (let i = 0; i < path.length; i++) {
if (i % 2 === 0) {
typeArray.push(path[i]);
}
}
return typeArray.join('/');
}
}

View File

@@ -9,7 +9,7 @@ import * as azdata from 'azdata';
import { ACTIVE_GROUP, IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { TableDesignerInput } from 'sql/workbench/browser/editor/tableDesigner/tableDesignerInput';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
import { IAdsTelemetryService, ITelemetryEventProperties } from 'sql/platform/telemetry/common/telemetry';
import { TelemetryAction, TelemetryView } from 'sql/platform/telemetry/common/telemetryKeys';
export class TableDesignerService implements ITableDesignerService {
@@ -43,13 +43,13 @@ export class TableDesignerService implements ITableDesignerService {
throw invalidProvider(providerId);
}
public async openTableDesigner(providerId: string, tableInfo: azdata.designers.TableInfo): Promise<void> {
public async openTableDesigner(providerId: string, tableInfo: azdata.designers.TableInfo, telemetryInfo?: ITelemetryEventProperties): Promise<void> {
this._adsTelemetryService.createActionEvent(TelemetryView.TableDesigner, TelemetryAction.Open).withAdditionalProperties({
provider: providerId,
newTable: tableInfo.isNewTable
}).send();
const provider = this.getProvider(providerId);
const tableDesignerInput = this._instantiationService.createInstance(TableDesignerInput, provider, tableInfo);
const tableDesignerInput = this._instantiationService.createInstance(TableDesignerInput, provider, tableInfo, telemetryInfo);
await this._editorService.openEditor(tableDesignerInput, { pinned: true }, ACTIVE_GROUP);
}
}

View File

@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import { ITelemetryEventProperties } from 'sql/platform/telemetry/common/telemetry';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
@@ -36,5 +37,5 @@ export interface ITableDesignerService {
* @param providerId The provider id
* @param tableInfo The table information
*/
openTableDesigner(providerId: string, tableInfo: azdata.designers.TableInfo): Promise<void>;
openTableDesigner(providerId: string, tableInfo: azdata.designers.TableInfo, telemetryInfo?: ITelemetryEventProperties): Promise<void>;
}