mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
Extension telemetry feature cleanup (#21779)
* Extension telemetry feature cleanup * one more
This commit is contained in:
@@ -24,6 +24,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
|
|||||||
const ssmsMinVer = JSON.parse(rawConfig.toString()).version;
|
const ssmsMinVer = JSON.parse(rawConfig.toString()).version;
|
||||||
exePath = path.join(context.extensionPath, 'ssmsmin', 'Windows', ssmsMinVer, 'ssmsmin.exe');
|
exePath = path.join(context.extensionPath, 'ssmsmin', 'Windows', ssmsMinVer, 'ssmsmin.exe');
|
||||||
registerCommands(context);
|
registerCommands(context);
|
||||||
|
context.subscriptions.push(TelemetryReporter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import * as vscode from 'vscode';
|
|||||||
import * as nls from 'vscode-nls';
|
import * as nls from 'vscode-nls';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { getCommonLaunchArgsAndCleanupOldLogFiles } from './utils';
|
import { getCommonLaunchArgsAndCleanupOldLogFiles } from './utils';
|
||||||
import { Telemetry, LanguageClientErrorHandler } from './telemetry';
|
import { TelemetryReporter, LanguageClientErrorHandler } from './telemetry';
|
||||||
import { SqlOpsDataClient, ClientOptions } from 'dataprotocol-client';
|
import { SqlOpsDataClient, ClientOptions } from 'dataprotocol-client';
|
||||||
import { SerializationFeature } from './features/serializationFeature';
|
import { SerializationFeature } from './features/serializationFeature';
|
||||||
import { TelemetryFeature } from './features/telemetryFeature';
|
import { TelemetryFeature } from './features/telemetryFeature';
|
||||||
@@ -48,7 +48,7 @@ export class AzureMonitorServer {
|
|||||||
vscode.commands.registerCommand('azuremonitor.loadCompletionExtension', (params: CompletionExtensionParams) => {
|
vscode.commands.registerCommand('azuremonitor.loadCompletionExtension', (params: CompletionExtensionParams) => {
|
||||||
this.client.sendRequest(CompletionExtLoadRequest.type, params);
|
this.client.sendRequest(CompletionExtLoadRequest.type, params);
|
||||||
});
|
});
|
||||||
Telemetry.sendTelemetryEvent('startup/LanguageClientStarted', {
|
TelemetryReporter.sendTelemetryEvent('startup/LanguageClientStarted', {
|
||||||
installationTime: String(installationComplete - installationStart),
|
installationTime: String(installationComplete - installationStart),
|
||||||
processStartupTime: String(processEnd - processStart),
|
processStartupTime: String(processEnd - processStart),
|
||||||
totalTime: String(processEnd - installationStart),
|
totalTime: String(processEnd - installationStart),
|
||||||
@@ -61,7 +61,7 @@ export class AzureMonitorServer {
|
|||||||
await Promise.all([clientReadyPromise]);
|
await Promise.all([clientReadyPromise]);
|
||||||
return this.client;
|
return this.client;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Telemetry.sendTelemetryEvent('ServiceInitializingFailed');
|
TelemetryReporter.sendTelemetryEvent('ServiceInitializingFailed');
|
||||||
vscode.window.showErrorMessage(localize('failedToStartServiceErrorMsg', "Failed to start {0}", Constants.serviceName));
|
vscode.window.showErrorMessage(localize('failedToStartServiceErrorMsg', "Failed to start {0}", Constants.serviceName));
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export const serviceName = 'AzureMonitor Tools Service';
|
|||||||
export const providerId = 'LOGANALYTICS';
|
export const providerId = 'LOGANALYTICS';
|
||||||
export const serviceCrashLink = 'https://github.com/Microsoft/azuredatastudio/issues';
|
export const serviceCrashLink = 'https://github.com/Microsoft/azuredatastudio/issues';
|
||||||
export const extensionConfigSectionName = 'azuremonitor';
|
export const extensionConfigSectionName = 'azuremonitor';
|
||||||
|
export const packageName = 'Microsoft.azuremonitor';
|
||||||
|
|
||||||
// DATA PROTOCOL VALUES ///////////////////////////////////////////////////////////
|
// DATA PROTOCOL VALUES ///////////////////////////////////////////////////////////
|
||||||
export const azureMonitorClusterProviderName = 'azureMonitorCluster';
|
export const azureMonitorClusterProviderName = 'azureMonitorCluster';
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { NotificationType, RequestType } from 'vscode-languageclient';
|
import { NotificationType, RequestType } from 'vscode-languageclient';
|
||||||
import { ITelemetryEventProperties, ITelemetryEventMeasures } from '../telemetry';
|
import * as telemetry from '@microsoft/ads-extension-telemetry';
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
|
|
||||||
// ------------------------------- < Telemetry Sent Event > ------------------------------------
|
// ------------------------------- < Telemetry Sent Event > ------------------------------------
|
||||||
@@ -22,8 +22,8 @@ export namespace TelemetryNotification {
|
|||||||
export class TelemetryParams {
|
export class TelemetryParams {
|
||||||
public params!: {
|
public params!: {
|
||||||
eventName: string;
|
eventName: string;
|
||||||
properties: ITelemetryEventProperties;
|
properties: telemetry.TelemetryEventProperties;
|
||||||
measures: ITelemetryEventMeasures;
|
measures: telemetry.TelemetryEventMeasures;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import { SqlOpsDataClient } from 'dataprotocol-client';
|
import { SqlOpsDataClient } from 'dataprotocol-client';
|
||||||
import { ClientCapabilities, StaticFeature } from 'vscode-languageclient';
|
import { ClientCapabilities, StaticFeature } from 'vscode-languageclient';
|
||||||
import { Telemetry } from '../telemetry';
|
import { TelemetryReporter } from '../telemetry';
|
||||||
import * as contracts from './contracts';
|
import * as contracts from './contracts';
|
||||||
import * as Utils from '../utils';
|
import * as Utils from '../utils';
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ export class TelemetryFeature implements StaticFeature {
|
|||||||
|
|
||||||
initialize(): void {
|
initialize(): void {
|
||||||
this._client.onNotification(contracts.TelemetryNotification.type, e => {
|
this._client.onNotification(contracts.TelemetryNotification.type, e => {
|
||||||
Telemetry.sendTelemetryEvent(e.params.eventName, e.params.properties, e.params.measures);
|
TelemetryReporter.sendTelemetryEvent(e.params.eventName, e.params.properties, e.params.measures);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { AzureMonitorIconProvider } from './iconProvider';
|
|||||||
import { createAzureMonitorApi } from './azuremonitorApiFactory';
|
import { createAzureMonitorApi } from './azuremonitorApiFactory';
|
||||||
import { AzureMonitorServer } from './azuremonitorServer';
|
import { AzureMonitorServer } from './azuremonitorServer';
|
||||||
import { promises as fs } from 'fs';
|
import { promises as fs } from 'fs';
|
||||||
|
import { TelemetryReporter } from './telemetry';
|
||||||
|
|
||||||
const localize = nls.loadMessageBundle();
|
const localize = nls.loadMessageBundle();
|
||||||
|
|
||||||
@@ -54,7 +55,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<IExten
|
|||||||
const server = new AzureMonitorServer();
|
const server = new AzureMonitorServer();
|
||||||
context.subscriptions.push(server);
|
context.subscriptions.push(server);
|
||||||
await server.start(appContext);
|
await server.start(appContext);
|
||||||
|
context.subscriptions.push(TelemetryReporter);
|
||||||
return createAzureMonitorApi(appContext);
|
return createAzureMonitorApi(appContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,118 +4,18 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as nls from 'vscode-nls';
|
import AdsTelemetryReporter from '@microsoft/ads-extension-telemetry';
|
||||||
import TelemetryReporter from '@microsoft/ads-extension-telemetry';
|
|
||||||
import { ErrorAction, ErrorHandler, Message, CloseAction } from 'vscode-languageclient';
|
import { ErrorAction, ErrorHandler, Message, CloseAction } from 'vscode-languageclient';
|
||||||
|
|
||||||
import * as Utils from './utils';
|
|
||||||
import * as Constants from './constants';
|
import * as Constants from './constants';
|
||||||
|
import * as nls from 'vscode-nls';
|
||||||
|
|
||||||
|
|
||||||
const localize = nls.loadMessageBundle();
|
const localize = nls.loadMessageBundle();
|
||||||
|
|
||||||
const packageJson = require('../package.json');
|
|
||||||
const viewKnownIssuesAction = localize('viewKnownIssuesText', "View Known Issues");
|
const viewKnownIssuesAction = localize('viewKnownIssuesText', "View Known Issues");
|
||||||
|
|
||||||
export interface ITelemetryEventProperties {
|
const packageInfo = vscode.extensions.getExtension(Constants.packageName)?.packageJSON;
|
||||||
[key: string]: string;
|
export const TelemetryReporter = new AdsTelemetryReporter<string, string>(packageInfo?.name, packageInfo?.version, packageInfo?.aiKey);
|
||||||
}
|
|
||||||
|
|
||||||
export interface ITelemetryEventMeasures {
|
|
||||||
[key: string]: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filters error paths to only include source files. Exported to support testing
|
|
||||||
*/
|
|
||||||
export function FilterErrorPath(line: string): string | undefined {
|
|
||||||
if (line) {
|
|
||||||
let values: string[] = line.split('/out/');
|
|
||||||
if (values.length <= 1) {
|
|
||||||
// Didn't match expected format
|
|
||||||
return line;
|
|
||||||
} else {
|
|
||||||
return values[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Telemetry {
|
|
||||||
private static reporter: TelemetryReporter;
|
|
||||||
private static disabled: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disable telemetry reporting
|
|
||||||
*/
|
|
||||||
public static disable(): void {
|
|
||||||
this.disabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the telemetry reporter for use.
|
|
||||||
*/
|
|
||||||
public static initialize(): void {
|
|
||||||
if (typeof this.reporter === 'undefined') {
|
|
||||||
// Check if the user has opted out of telemetry
|
|
||||||
if (!vscode.workspace.getConfiguration('telemetry').get<boolean>('enableTelemetry', true)) {
|
|
||||||
this.disable();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let packageInfo = Utils.getPackageInfo(packageJson)!;
|
|
||||||
this.reporter = new TelemetryReporter(packageInfo.name, packageInfo.version, packageInfo.aiKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a telemetry event for an exception
|
|
||||||
*/
|
|
||||||
public static sendTelemetryEventForException(
|
|
||||||
err: any, methodName: string, _extensionConfigName: string): void {
|
|
||||||
let stackArray: string[];
|
|
||||||
let firstLine: string = '';
|
|
||||||
if (err !== undefined && err.stack !== undefined) {
|
|
||||||
stackArray = err.stack.split('\n');
|
|
||||||
if (stackArray !== undefined && stackArray.length >= 2) {
|
|
||||||
firstLine = stackArray[1]; // The fist line is the error message and we don't want to send that telemetry event
|
|
||||||
firstLine = FilterErrorPath(firstLine)!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only adding the method name and the fist line of the stack trace. We don't add the error message because it might have PII
|
|
||||||
this.sendTelemetryEvent('Exception', { methodName: methodName, errorLine: firstLine });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a telemetry event using application insights
|
|
||||||
*/
|
|
||||||
public static sendTelemetryEvent(
|
|
||||||
eventName: string,
|
|
||||||
properties?: ITelemetryEventProperties,
|
|
||||||
measures?: ITelemetryEventMeasures): void {
|
|
||||||
|
|
||||||
if (typeof this.disabled === 'undefined') {
|
|
||||||
this.disabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.disabled || typeof (this.reporter) === 'undefined') {
|
|
||||||
// Don't do anything if telemetry is disabled
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!properties || typeof properties === 'undefined') {
|
|
||||||
properties = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.reporter.sendTelemetryEvent(eventName, properties, measures);
|
|
||||||
} catch (telemetryErr) {
|
|
||||||
// If sending telemetry event fails ignore it so it won't break the extension
|
|
||||||
console.error('Failed to send telemetry event. error: ' + telemetryErr);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle Language Service client errors
|
* Handle Language Service client errors
|
||||||
@@ -127,12 +27,12 @@ export class LanguageClientErrorHandler implements ErrorHandler {
|
|||||||
* @memberOf LanguageClientErrorHandler
|
* @memberOf LanguageClientErrorHandler
|
||||||
*/
|
*/
|
||||||
showOnErrorPrompt(): void {
|
showOnErrorPrompt(): void {
|
||||||
Telemetry.sendTelemetryEvent(Constants.serviceName + 'Crash');
|
TelemetryReporter.sendTelemetryEvent(Constants.serviceName + 'Crash');
|
||||||
vscode.window.showErrorMessage(
|
void vscode.window.showErrorMessage(
|
||||||
localize('serviceCrashMessage', "{0} component exited unexpectedly. Please restart Azure Data Studio.", Constants.serviceName),
|
localize('serviceCrashMessage', "{0} component exited unexpectedly. Please restart Azure Data Studio.", Constants.serviceName),
|
||||||
viewKnownIssuesAction).then(action => {
|
viewKnownIssuesAction).then(action => {
|
||||||
if (action && action === viewKnownIssuesAction) {
|
if (action && action === viewKnownIssuesAction) {
|
||||||
vscode.env.openExternal(vscode.Uri.parse(Constants.serviceCrashLink));
|
void vscode.env.openExternal(vscode.Uri.parse(Constants.serviceCrashLink));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -163,5 +63,3 @@ export class LanguageClientErrorHandler implements ErrorHandler {
|
|||||||
return CloseAction.DoNotRestart;
|
return CloseAction.DoNotRestart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Telemetry.initialize();
|
|
||||||
|
|||||||
@@ -6,9 +6,11 @@
|
|||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { DataTierApplicationWizard } from './wizard/dataTierApplicationWizard';
|
import { DataTierApplicationWizard } from './wizard/dataTierApplicationWizard';
|
||||||
|
import { TelemetryReporter } from './telemetry';
|
||||||
|
|
||||||
export async function activate(context: vscode.ExtensionContext) {
|
export async function activate(context: vscode.ExtensionContext) {
|
||||||
vscode.commands.registerCommand('dacFx.start', (profile: azdata.IConnectionProfile) => new DataTierApplicationWizard(undefined, context).start(profile));
|
context.subscriptions.push(vscode.commands.registerCommand('dacFx.start', (profile: azdata.IConnectionProfile) => new DataTierApplicationWizard(undefined, context).start(profile)));
|
||||||
|
context.subscriptions.push(TelemetryReporter);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deactivate(): void {
|
export function deactivate(): void {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { ProjectDashboard } from './dialogs/projectDashboard';
|
|||||||
import { getAzdataApi } from './common/utils';
|
import { getAzdataApi } from './common/utils';
|
||||||
import { createNewProjectWithQuickpick } from './dialogs/newProjectQuickpick';
|
import { createNewProjectWithQuickpick } from './dialogs/newProjectQuickpick';
|
||||||
import Logger from './common/logger';
|
import Logger from './common/logger';
|
||||||
|
import { TelemetryReporter } from './common/telemetry';
|
||||||
|
|
||||||
export async function activate(context: vscode.ExtensionContext): Promise<IExtension> {
|
export async function activate(context: vscode.ExtensionContext): Promise<IExtension> {
|
||||||
const startTime = new Date().getTime();
|
const startTime = new Date().getTime();
|
||||||
@@ -103,6 +104,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<IExten
|
|||||||
IconPathHelper.setExtensionContext(context);
|
IconPathHelper.setExtensionContext(context);
|
||||||
Logger.log(`IconPathHelper took ${new Date().getTime() - iconPathHelperTime}ms`);
|
Logger.log(`IconPathHelper took ${new Date().getTime() - iconPathHelperTime}ms`);
|
||||||
|
|
||||||
|
context.subscriptions.push(TelemetryReporter);
|
||||||
Logger.log(`Finished activating Data Workspace extension. Total time = ${new Date().getTime() - startTime}ms`);
|
Logger.log(`Finished activating Data Workspace extension. Total time = ${new Date().getTime() - startTime}ms`);
|
||||||
return Promise.resolve(dataWorkspaceExtension);
|
return Promise.resolve(dataWorkspaceExtension);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ export const sqlFileExtension = 'sql';
|
|||||||
export const virtualizeDataCommand = 'virtualizedatawizard.cmd.open';
|
export const virtualizeDataCommand = 'virtualizedatawizard.cmd.open';
|
||||||
export const virtualizeDataTask = 'virtualizedatawizard.task.open';
|
export const virtualizeDataTask = 'virtualizedatawizard.task.open';
|
||||||
export const mssqlHdfsTableFromFileCommand = 'mssqlHdfsTableWizard.cmd.open';
|
export const mssqlHdfsTableFromFileCommand = 'mssqlHdfsTableWizard.cmd.open';
|
||||||
|
export const packageName = 'Microsoft.datavirtualization';
|
||||||
|
|
||||||
export const ctp24Version = 'CTP2.4';
|
export const ctp24Version = 'CTP2.4';
|
||||||
export const ctp25Version = 'CTP2.5';
|
export const ctp25Version = 'CTP2.5';
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { DataSourceWizardService } from './services/contracts';
|
|||||||
import { managerInstance, ApiType } from './services/serviceApiManager';
|
import { managerInstance, ApiType } from './services/serviceApiManager';
|
||||||
import { OpenVirtualizeDataWizardCommand, OpenVirtualizeDataWizardTask, OpenMssqlHdfsTableFromFileWizardCommand } from './wizards/wizardCommands';
|
import { OpenVirtualizeDataWizardCommand, OpenVirtualizeDataWizardTask, OpenMssqlHdfsTableFromFileWizardCommand } from './wizards/wizardCommands';
|
||||||
import { ServiceClient } from './services/serviceClient';
|
import { ServiceClient } from './services/serviceClient';
|
||||||
|
import { TelemetryReporter } from './services/telemetry';
|
||||||
|
|
||||||
export function activate(extensionContext: vscode.ExtensionContext): void {
|
export function activate(extensionContext: vscode.ExtensionContext): void {
|
||||||
let apiWrapper = new ApiWrapper();
|
let apiWrapper = new ApiWrapper();
|
||||||
@@ -38,4 +39,5 @@ export function activate(extensionContext: vscode.ExtensionContext): void {
|
|||||||
serviceClient.startService(extensionContext).then(success => undefined, err => {
|
serviceClient.startService(extensionContext).then(success => undefined, err => {
|
||||||
apiWrapper.showErrorMessage(utils.getErrorMessage(err));
|
apiWrapper.showErrorMessage(utils.getErrorMessage(err));
|
||||||
});
|
});
|
||||||
|
extensionContext.subscriptions.push(TelemetryReporter);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { ClientCapabilities as VSClientCapabilities, RequestType, NotificationType } from 'vscode-languageclient';
|
import { RequestType, NotificationType } from 'vscode-languageclient';
|
||||||
import * as types from 'dataprotocol-client/lib/types';
|
import * as telemetry from '@microsoft/ads-extension-telemetry';
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,19 +29,11 @@ export namespace TelemetryNotification {
|
|||||||
export class TelemetryParams {
|
export class TelemetryParams {
|
||||||
public params: {
|
public params: {
|
||||||
eventName: string;
|
eventName: string;
|
||||||
properties: ITelemetryEventProperties;
|
properties: telemetry.TelemetryEventProperties;
|
||||||
measures: ITelemetryEventMeasures;
|
measures: telemetry.TelemetryEventMeasures;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITelemetryEventProperties {
|
|
||||||
[key: string]: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ITelemetryEventMeasures {
|
|
||||||
[key: string]: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------- </ Telemetry Sent Event > ----------------------------------
|
// ------------------------------- </ Telemetry Sent Event > ----------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import * as UUID from 'vscode-languageclient/lib/utils/uuid';
|
|||||||
import { Disposable } from 'vscode';
|
import { Disposable } from 'vscode';
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
|
|
||||||
import { Telemetry } from './telemetry';
|
import { TelemetryReporter } from './telemetry';
|
||||||
import * as serviceUtils from './serviceUtils';
|
import * as serviceUtils from './serviceUtils';
|
||||||
import {
|
import {
|
||||||
TelemetryNotification,
|
TelemetryNotification,
|
||||||
@@ -33,7 +33,7 @@ export class TelemetryFeature implements StaticFeature {
|
|||||||
|
|
||||||
initialize(): void {
|
initialize(): void {
|
||||||
this._client.onNotification(TelemetryNotification.type, e => {
|
this._client.onNotification(TelemetryNotification.type, e => {
|
||||||
Telemetry.sendTelemetryEvent(e.params.eventName, e.params.properties, e.params.measures);
|
TelemetryReporter.sendTelemetryEvent(e.params.eventName, e.params.properties, e.params.measures);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const localize = nls.loadMessageBundle();
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { EventAndListener } from 'eventemitter2';
|
import { EventAndListener } from 'eventemitter2';
|
||||||
|
|
||||||
import { Telemetry, LanguageClientErrorHandler } from './telemetry';
|
import { LanguageClientErrorHandler, TelemetryReporter } from './telemetry';
|
||||||
import { ApiWrapper } from '../apiWrapper';
|
import { ApiWrapper } from '../apiWrapper';
|
||||||
import * as Constants from '../constants';
|
import * as Constants from '../constants';
|
||||||
import { TelemetryFeature, DataSourceWizardFeature } from './features';
|
import { TelemetryFeature, DataSourceWizardFeature } from './features';
|
||||||
@@ -51,7 +51,7 @@ export class ServiceClient {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.statusView.hide();
|
this.statusView.hide();
|
||||||
}, 1500);
|
}, 1500);
|
||||||
Telemetry.sendTelemetryEvent('startup/LanguageClientStarted', {
|
TelemetryReporter.sendTelemetryEvent('startup/LanguageClientStarted', {
|
||||||
installationTime: String(installationComplete - installationStart),
|
installationTime: String(installationComplete - installationStart),
|
||||||
processStartupTime: String(processEnd - processStart),
|
processStartupTime: String(processEnd - processStart),
|
||||||
totalTime: String(processEnd - installationStart),
|
totalTime: String(processEnd - installationStart),
|
||||||
@@ -64,7 +64,7 @@ export class ServiceClient {
|
|||||||
context.subscriptions.push(disposable);
|
context.subscriptions.push(disposable);
|
||||||
resolve();
|
resolve();
|
||||||
}, e => {
|
}, e => {
|
||||||
Telemetry.sendTelemetryEvent('ServiceInitializingFailed');
|
TelemetryReporter.sendTelemetryEvent('ServiceInitializingFailed');
|
||||||
this.apiWrapper.showErrorMessage(localize('serviceStartFailed', 'Failed to start {0}: {1}', Constants.serviceName, e));
|
this.apiWrapper.showErrorMessage(localize('serviceStartFailed', 'Failed to start {0}: {1}', Constants.serviceName, e));
|
||||||
// Just resolve to avoid unhandled promise. We show the error to the user.
|
// Just resolve to avoid unhandled promise. We show the error to the user.
|
||||||
resolve();
|
resolve();
|
||||||
|
|||||||
@@ -4,17 +4,17 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { ErrorAction, CloseAction } from 'vscode-languageclient';
|
import { ErrorAction, CloseAction } from 'vscode-languageclient';
|
||||||
import TelemetryReporter from '@microsoft/ads-extension-telemetry';
|
|
||||||
import { PlatformInformation } from '@microsoft/ads-service-downloader/out/platform';
|
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as nls from 'vscode-nls';
|
import * as nls from 'vscode-nls';
|
||||||
const localize = nls.loadMessageBundle();
|
const localize = nls.loadMessageBundle();
|
||||||
|
|
||||||
import { ApiWrapper } from '../apiWrapper';
|
import { ApiWrapper } from '../apiWrapper';
|
||||||
import * as constants from '../constants';
|
import * as constants from '../constants';
|
||||||
import * as serviceUtils from './serviceUtils';
|
import { IMessage } from './contracts';
|
||||||
import { IMessage, ITelemetryEventProperties, ITelemetryEventMeasures } from './contracts';
|
import AdsTelemetryReporter from '@microsoft/ads-extension-telemetry';
|
||||||
|
|
||||||
|
const packageInfo = vscode.extensions.getExtension(constants.packageName)?.packageJSON;
|
||||||
|
export const TelemetryReporter = new AdsTelemetryReporter<string, string>(packageInfo?.name, packageInfo?.version, packageInfo?.aiKey);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle Language Service client errors
|
* Handle Language Service client errors
|
||||||
@@ -36,9 +36,8 @@ export class LanguageClientErrorHandler {
|
|||||||
* Show an error message prompt with a link to known issues wiki page
|
* Show an error message prompt with a link to known issues wiki page
|
||||||
* @memberOf LanguageClientErrorHandler
|
* @memberOf LanguageClientErrorHandler
|
||||||
*/
|
*/
|
||||||
showOnErrorPrompt(): void {
|
public showOnErrorPrompt(): void {
|
||||||
// TODO add telemetry
|
TelemetryReporter.sendTelemetryEvent(constants.serviceName + 'Crash');
|
||||||
// Telemetry.sendTelemetryEvent('SqlToolsServiceCrash');
|
|
||||||
let crashButtonText = localize('serviceCrashButton', 'View Known Issues');
|
let crashButtonText = localize('serviceCrashButton', 'View Known Issues');
|
||||||
this.apiWrapper.showErrorMessage(
|
this.apiWrapper.showErrorMessage(
|
||||||
localize('serviceCrashMessage', 'service component could not start'),
|
localize('serviceCrashMessage', 'service component could not start'),
|
||||||
@@ -60,7 +59,7 @@ export class LanguageClientErrorHandler {
|
|||||||
*
|
*
|
||||||
* @memberOf LanguageClientErrorHandler
|
* @memberOf LanguageClientErrorHandler
|
||||||
*/
|
*/
|
||||||
error(error: Error, message: IMessage, count: number): ErrorAction {
|
public error(error: Error, message: IMessage, count: number): ErrorAction {
|
||||||
this.showOnErrorPrompt();
|
this.showOnErrorPrompt();
|
||||||
|
|
||||||
// we don't retry running the service since crashes leave the extension
|
// we don't retry running the service since crashes leave the extension
|
||||||
@@ -75,7 +74,7 @@ export class LanguageClientErrorHandler {
|
|||||||
*
|
*
|
||||||
* @memberOf LanguageClientErrorHandler
|
* @memberOf LanguageClientErrorHandler
|
||||||
*/
|
*/
|
||||||
closed(): CloseAction {
|
public closed(): CloseAction {
|
||||||
this.showOnErrorPrompt();
|
this.showOnErrorPrompt();
|
||||||
|
|
||||||
// we don't retry running the service since crashes leave the extension
|
// we don't retry running the service since crashes leave the extension
|
||||||
@@ -83,134 +82,3 @@ export class LanguageClientErrorHandler {
|
|||||||
return CloseAction.DoNotRestart;
|
return CloseAction.DoNotRestart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Filters error paths to only include source files. Exported to support testing
|
|
||||||
*/
|
|
||||||
export function FilterErrorPath(line: string): string {
|
|
||||||
if (line) {
|
|
||||||
let values: string[] = line.split('/out/');
|
|
||||||
if (values.length <= 1) {
|
|
||||||
// Didn't match expected format
|
|
||||||
return line;
|
|
||||||
} else {
|
|
||||||
return values[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Telemetry {
|
|
||||||
private static reporter: TelemetryReporter;
|
|
||||||
private static userId: string;
|
|
||||||
private static platformInformation: PlatformInformation;
|
|
||||||
private static disabled: boolean;
|
|
||||||
|
|
||||||
// Get the unique ID for the current user of the extension
|
|
||||||
public static getUserId(): Promise<string> {
|
|
||||||
return new Promise<string>(resolve => {
|
|
||||||
// Generate the user id if it has not been created already
|
|
||||||
if (typeof this.userId === 'undefined') {
|
|
||||||
let id = serviceUtils.generateUserId();
|
|
||||||
id.then(newId => {
|
|
||||||
this.userId = newId;
|
|
||||||
resolve(this.userId);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
resolve(this.userId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static getPlatformInformation(): Promise<PlatformInformation> {
|
|
||||||
if (this.platformInformation) {
|
|
||||||
return Promise.resolve(this.platformInformation);
|
|
||||||
} else {
|
|
||||||
return new Promise<PlatformInformation>(resolve => {
|
|
||||||
PlatformInformation.getCurrent().then(info => {
|
|
||||||
this.platformInformation = info;
|
|
||||||
resolve(this.platformInformation);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disable telemetry reporting
|
|
||||||
*/
|
|
||||||
public static disable(): void {
|
|
||||||
this.disabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the telemetry reporter for use.
|
|
||||||
*/
|
|
||||||
public static initialize(): void {
|
|
||||||
if (typeof this.reporter === 'undefined') {
|
|
||||||
// Check if the user has opted out of telemetry
|
|
||||||
if (!vscode.workspace.getConfiguration('telemetry').get<boolean>('enableTelemetry', true)) {
|
|
||||||
this.disable();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let packageInfo = vscode.extensions.getExtension('Microsoft.datavirtualization').packageJSON;
|
|
||||||
this.reporter = new TelemetryReporter(packageInfo.name, packageInfo.version, packageInfo.aiKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a telemetry event for an exception
|
|
||||||
*/
|
|
||||||
public static sendTelemetryEventForException(
|
|
||||||
err: any, methodName: string, extensionConfigName: string): void {
|
|
||||||
try {
|
|
||||||
let stackArray: string[];
|
|
||||||
let firstLine: string = '';
|
|
||||||
if (err !== undefined && err.stack !== undefined) {
|
|
||||||
stackArray = err.stack.split('\n');
|
|
||||||
if (stackArray !== undefined && stackArray.length >= 2) {
|
|
||||||
firstLine = stackArray[1]; // The fist line is the error message and we don't want to send that telemetry event
|
|
||||||
firstLine = FilterErrorPath(firstLine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only adding the method name and the fist line of the stack trace. We don't add the error message because it might have PII
|
|
||||||
this.sendTelemetryEvent('Exception', { methodName: methodName, errorLine: firstLine });
|
|
||||||
// Utils.logDebug('Unhandled Exception occurred. error: ' + err + ' method: ' + methodName, extensionConfigName);
|
|
||||||
} catch (telemetryErr) {
|
|
||||||
// If sending telemetry event fails ignore it so it won't break the extension
|
|
||||||
// Utils.logDebug('Failed to send telemetry event. error: ' + telemetryErr, extensionConfigName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a telemetry event using application insights
|
|
||||||
*/
|
|
||||||
public static sendTelemetryEvent(
|
|
||||||
eventName: string,
|
|
||||||
properties?: ITelemetryEventProperties,
|
|
||||||
measures?: ITelemetryEventMeasures): void {
|
|
||||||
|
|
||||||
if (typeof this.disabled === 'undefined') {
|
|
||||||
this.disabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.disabled || typeof (this.reporter) === 'undefined') {
|
|
||||||
// Don't do anything if telemetry is disabled
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!properties || typeof properties === 'undefined') {
|
|
||||||
properties = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Augment the properties structure with additional common properties before sending
|
|
||||||
Promise.all([this.getUserId(), this.getPlatformInformation()]).then(() => {
|
|
||||||
properties['userId'] = this.userId;
|
|
||||||
properties['distribution'] = (this.platformInformation && this.platformInformation.distribution) ?
|
|
||||||
`${this.platformInformation.distribution.name}, ${this.platformInformation.distribution.version}` : '';
|
|
||||||
|
|
||||||
this.reporter.sendTelemetryEvent(eventName, properties, measures);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Telemetry.initialize();
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export const providerId = 'FlatFileImport';
|
|||||||
export const configLogDebugInfo = 'logDebugInfo';
|
export const configLogDebugInfo = 'logDebugInfo';
|
||||||
export const sqlConfigSectionName = 'sql';
|
export const sqlConfigSectionName = 'sql';
|
||||||
export const mssqlProvider = 'MSSQL';
|
export const mssqlProvider = 'MSSQL';
|
||||||
|
export const packageName = 'Microsoft.import';
|
||||||
|
|
||||||
// allow-any-unicode-next-line
|
// allow-any-unicode-next-line
|
||||||
export const summaryErrorSymbol = '✗ ';
|
export const summaryErrorSymbol = '✗ ';
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import * as vscode from 'vscode';
|
|||||||
|
|
||||||
import ControllerBase from './controllers/controllerBase';
|
import ControllerBase from './controllers/controllerBase';
|
||||||
import MainController from './controllers/mainController';
|
import MainController from './controllers/mainController';
|
||||||
|
import { TelemetryReporter } from './services/telemetry';
|
||||||
|
|
||||||
let controllers: ControllerBase[] = [];
|
let controllers: ControllerBase[] = [];
|
||||||
|
|
||||||
@@ -18,6 +19,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
|
|||||||
context.subscriptions.push(mainController);
|
context.subscriptions.push(mainController);
|
||||||
|
|
||||||
await mainController.activate();
|
await mainController.activate();
|
||||||
|
context.subscriptions.push(TelemetryReporter);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deactivate() {
|
export function deactivate() {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { RequestType, NotificationType } from 'vscode-languageclient';
|
import { RequestType, NotificationType } from 'vscode-languageclient';
|
||||||
|
import * as telemetry from '@microsoft/ads-extension-telemetry';
|
||||||
|
|
||||||
export interface IMessage {
|
export interface IMessage {
|
||||||
jsonrpc: string;
|
jsonrpc: string;
|
||||||
@@ -24,19 +25,11 @@ export namespace TelemetryNotification {
|
|||||||
export class TelemetryParams {
|
export class TelemetryParams {
|
||||||
public params: {
|
public params: {
|
||||||
eventName: string;
|
eventName: string;
|
||||||
properties: ITelemetryEventProperties;
|
properties: telemetry.TelemetryEventProperties;
|
||||||
measures: ITelemetryEventMeasures;
|
measures: telemetry.TelemetryEventMeasures;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITelemetryEventProperties {
|
|
||||||
[key: string]: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ITelemetryEventMeasures {
|
|
||||||
[key: string]: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contract Classes
|
* Contract Classes
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
import * as UUID from 'vscode-languageclient/lib/utils/uuid';
|
import * as UUID from 'vscode-languageclient/lib/utils/uuid';
|
||||||
import { Disposable } from 'vscode';
|
import { Disposable } from 'vscode';
|
||||||
|
|
||||||
import { Telemetry } from './telemetry';
|
import { TelemetryReporter } from './telemetry';
|
||||||
import * as serviceUtils from './serviceUtils';
|
import * as serviceUtils from './serviceUtils';
|
||||||
import * as Contracts from './contracts';
|
import * as Contracts from './contracts';
|
||||||
import { managerInstance, ApiType } from './serviceApiManager';
|
import { managerInstance, ApiType } from './serviceApiManager';
|
||||||
@@ -30,7 +30,7 @@ export class TelemetryFeature implements StaticFeature {
|
|||||||
|
|
||||||
initialize(): void {
|
initialize(): void {
|
||||||
this._client.onNotification(Contracts.TelemetryNotification.type, e => {
|
this._client.onNotification(Contracts.TelemetryNotification.type, e => {
|
||||||
Telemetry.sendTelemetryEvent(e.params.eventName, e.params.properties, e.params.measures);
|
TelemetryReporter.sendTelemetryEvent(e.params.eventName, e.params.properties, e.params.measures);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const localize = nls.loadMessageBundle();
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { EventAndListener } from 'eventemitter2';
|
import { EventAndListener } from 'eventemitter2';
|
||||||
|
|
||||||
import { Telemetry, LanguageClientErrorHandler } from './telemetry';
|
import { TelemetryReporter, LanguageClientErrorHandler } from './telemetry';
|
||||||
import * as Constants from '../common/constants';
|
import * as Constants from '../common/constants';
|
||||||
import { TelemetryFeature, FlatFileImportFeature } from './features';
|
import { TelemetryFeature, FlatFileImportFeature } from './features';
|
||||||
import { promises as fs } from 'fs';
|
import { promises as fs } from 'fs';
|
||||||
@@ -43,7 +43,7 @@ export class ServiceClient {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.statusView.hide();
|
this.statusView.hide();
|
||||||
}, 1500);
|
}, 1500);
|
||||||
Telemetry.sendTelemetryEvent('startup/LanguageClientStarted', {
|
TelemetryReporter.sendTelemetryEvent('startup/LanguageClientStarted', {
|
||||||
installationTime: String(installationComplete - installationStart),
|
installationTime: String(installationComplete - installationStart),
|
||||||
processStartupTime: String(processEnd - processStart),
|
processStartupTime: String(processEnd - processStart),
|
||||||
totalTime: String(processEnd - installationStart),
|
totalTime: String(processEnd - installationStart),
|
||||||
@@ -57,7 +57,7 @@ export class ServiceClient {
|
|||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
Telemetry.sendTelemetryEvent('ServiceInitializingFailed');
|
TelemetryReporter.sendTelemetryEvent('ServiceInitializingFailed');
|
||||||
vscode.window.showErrorMessage(localize('flatFileImport.serviceStartFailed', "Failed to start {0}: {1}", Constants.serviceName, error));
|
vscode.window.showErrorMessage(localize('flatFileImport.serviceStartFailed', "Failed to start {0}: {1}", Constants.serviceName, error));
|
||||||
// Just resolve to avoid unhandled promise. We show the error to the user.
|
// Just resolve to avoid unhandled promise. We show the error to the user.
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|||||||
@@ -4,12 +4,14 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { ErrorAction, CloseAction } from 'vscode-languageclient';
|
import { ErrorAction, CloseAction } from 'vscode-languageclient';
|
||||||
import TelemetryReporter from '@microsoft/ads-extension-telemetry';
|
import AdsTelemetryReporter from '@microsoft/ads-extension-telemetry';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
import * as constants from '../common/constants';
|
import * as constants from '../common/constants';
|
||||||
import { IMessage, ITelemetryEventProperties, ITelemetryEventMeasures } from './contracts';
|
import { IMessage } from './contracts';
|
||||||
|
|
||||||
|
const packageInfo = vscode.extensions.getExtension(constants.packageName)?.packageJSON;
|
||||||
|
export const TelemetryReporter = new AdsTelemetryReporter<string, string>(packageInfo?.name, packageInfo?.version, packageInfo?.aiKey);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle Language Service client errors
|
* Handle Language Service client errors
|
||||||
@@ -29,8 +31,7 @@ export class LanguageClientErrorHandler {
|
|||||||
* @memberOf LanguageClientErrorHandler
|
* @memberOf LanguageClientErrorHandler
|
||||||
*/
|
*/
|
||||||
showOnErrorPrompt(): void {
|
showOnErrorPrompt(): void {
|
||||||
// TODO add telemetry
|
TelemetryReporter.sendTelemetryEvent(constants.serviceName + 'Crash');
|
||||||
// Telemetry.sendTelemetryEvent('SqlToolsServiceCrash');
|
|
||||||
vscode.window.showErrorMessage(
|
vscode.window.showErrorMessage(
|
||||||
constants.serviceCrashMessageText,
|
constants.serviceCrashMessageText,
|
||||||
constants.crashButtonText
|
constants.crashButtonText
|
||||||
@@ -68,62 +69,3 @@ export class LanguageClientErrorHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export class Telemetry {
|
|
||||||
private static reporter: TelemetryReporter;
|
|
||||||
private static disabled: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disable telemetry reporting
|
|
||||||
*/
|
|
||||||
public static disable(): void {
|
|
||||||
this.disabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the telemetry reporter for use.
|
|
||||||
*/
|
|
||||||
public static initialize(): void {
|
|
||||||
if (typeof this.reporter === 'undefined') {
|
|
||||||
// Check if the user has opted out of telemetry
|
|
||||||
if (!vscode.workspace.getConfiguration('telemetry').get<boolean>('enableTelemetry', true)) {
|
|
||||||
this.disable();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let packageInfo = vscode.extensions.getExtension('Microsoft.import').packageJSON;
|
|
||||||
this.reporter = new TelemetryReporter(packageInfo.name, packageInfo.version, packageInfo.aiKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a telemetry event using application insights
|
|
||||||
*/
|
|
||||||
public static sendTelemetryEvent(
|
|
||||||
eventName: string,
|
|
||||||
properties?: ITelemetryEventProperties,
|
|
||||||
measures?: ITelemetryEventMeasures): void {
|
|
||||||
|
|
||||||
if (typeof this.disabled === 'undefined') {
|
|
||||||
this.disabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.disabled || typeof (this.reporter) === 'undefined') {
|
|
||||||
// Don't do anything if telemetry is disabled
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!properties || typeof properties === 'undefined') {
|
|
||||||
properties = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.reporter.sendTelemetryEvent(eventName, properties, measures);
|
|
||||||
} catch (telemetryErr) {
|
|
||||||
// If sending telemetry event fails ignore it so it won't break the extension
|
|
||||||
console.error('Failed to send telemetry event. error: ' + telemetryErr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Telemetry.initialize();
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export const serviceName = 'Kusto Tools Service';
|
|||||||
export const providerId = 'KUSTO';
|
export const providerId = 'KUSTO';
|
||||||
export const serviceCrashLink = 'https://github.com/Microsoft/vscode-kusto/wiki/SqlToolsService-Known-Issues';
|
export const serviceCrashLink = 'https://github.com/Microsoft/vscode-kusto/wiki/SqlToolsService-Known-Issues';
|
||||||
export const extensionConfigSectionName = 'kusto';
|
export const extensionConfigSectionName = 'kusto';
|
||||||
|
export const packageName = 'Microsoft.kusto';
|
||||||
|
|
||||||
// DATA PROTOCOL VALUES ///////////////////////////////////////////////////////////
|
// DATA PROTOCOL VALUES ///////////////////////////////////////////////////////////
|
||||||
export const kustoClusterProviderName = 'kustoCluster';
|
export const kustoClusterProviderName = 'kustoCluster';
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { NotificationType, RequestType } from 'vscode-languageclient';
|
import { NotificationType, RequestType } from 'vscode-languageclient';
|
||||||
import { ITelemetryEventProperties, ITelemetryEventMeasures } from './telemetry';
|
import * as telemetry from '@microsoft/ads-extension-telemetry';
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
|
|
||||||
// ------------------------------- < Telemetry Sent Event > ------------------------------------
|
// ------------------------------- < Telemetry Sent Event > ------------------------------------
|
||||||
@@ -22,8 +22,8 @@ export namespace TelemetryNotification {
|
|||||||
export class TelemetryParams {
|
export class TelemetryParams {
|
||||||
public params!: {
|
public params!: {
|
||||||
eventName: string;
|
eventName: string;
|
||||||
properties: ITelemetryEventProperties;
|
properties: telemetry.TelemetryEventProperties;
|
||||||
measures: ITelemetryEventMeasures;
|
measures: telemetry.TelemetryEventMeasures;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import * as nls from 'vscode-nls';
|
|||||||
import { SqlOpsDataClient, SqlOpsFeature } from 'dataprotocol-client';
|
import { SqlOpsDataClient, SqlOpsFeature } from 'dataprotocol-client';
|
||||||
import { ClientCapabilities, StaticFeature, RPCMessageType, ServerCapabilities } from 'vscode-languageclient';
|
import { ClientCapabilities, StaticFeature, RPCMessageType, ServerCapabilities } from 'vscode-languageclient';
|
||||||
import { Disposable, window } from 'vscode';
|
import { Disposable, window } from 'vscode';
|
||||||
import { Telemetry } from './telemetry';
|
import { TelemetryReporter } from './telemetry';
|
||||||
import * as contracts from './contracts';
|
import * as contracts from './contracts';
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
import * as Utils from './utils';
|
import * as Utils from './utils';
|
||||||
@@ -25,7 +25,7 @@ export class TelemetryFeature implements StaticFeature {
|
|||||||
|
|
||||||
initialize(): void {
|
initialize(): void {
|
||||||
this._client.onNotification(contracts.TelemetryNotification.type, e => {
|
this._client.onNotification(contracts.TelemetryNotification.type, e => {
|
||||||
Telemetry.sendTelemetryEvent(e.params.eventName, e.params.properties, e.params.measures);
|
TelemetryReporter.sendTelemetryEvent(e.params.eventName, e.params.properties, e.params.measures);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import * as vscode from 'vscode';
|
|||||||
import * as nls from 'vscode-nls';
|
import * as nls from 'vscode-nls';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { getCommonLaunchArgsAndCleanupOldLogFiles } from './utils';
|
import { getCommonLaunchArgsAndCleanupOldLogFiles } from './utils';
|
||||||
import { Telemetry, LanguageClientErrorHandler } from './telemetry';
|
import { TelemetryReporter, LanguageClientErrorHandler } from './telemetry';
|
||||||
import { SqlOpsDataClient, ClientOptions } from 'dataprotocol-client';
|
import { SqlOpsDataClient, ClientOptions } from 'dataprotocol-client';
|
||||||
import { TelemetryFeature, SerializationFeature, AccountFeature } from './features';
|
import { TelemetryFeature, SerializationFeature, AccountFeature } from './features';
|
||||||
import { AppContext } from './appContext';
|
import { AppContext } from './appContext';
|
||||||
@@ -46,7 +46,7 @@ export class KustoServer {
|
|||||||
vscode.commands.registerCommand('kusto.loadCompletionExtension', (params: CompletionExtensionParams) => {
|
vscode.commands.registerCommand('kusto.loadCompletionExtension', (params: CompletionExtensionParams) => {
|
||||||
this.client.sendRequest(CompletionExtLoadRequest.type, params);
|
this.client.sendRequest(CompletionExtLoadRequest.type, params);
|
||||||
});
|
});
|
||||||
Telemetry.sendTelemetryEvent('startup/LanguageClientStarted', {
|
TelemetryReporter.sendTelemetryEvent('startup/LanguageClientStarted', {
|
||||||
installationTime: String(installationComplete - installationStart),
|
installationTime: String(installationComplete - installationStart),
|
||||||
processStartupTime: String(processEnd - processStart),
|
processStartupTime: String(processEnd - processStart),
|
||||||
totalTime: String(processEnd - installationStart),
|
totalTime: String(processEnd - installationStart),
|
||||||
@@ -59,7 +59,7 @@ export class KustoServer {
|
|||||||
await Promise.all([clientReadyPromise]);
|
await Promise.all([clientReadyPromise]);
|
||||||
return this.client;
|
return this.client;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Telemetry.sendTelemetryEvent('ServiceInitializingFailed');
|
TelemetryReporter.sendTelemetryEvent('ServiceInitializingFailed');
|
||||||
vscode.window.showErrorMessage(localize('failedToStartServiceErrorMsg', "Failed to start {0}", Constants.serviceName));
|
vscode.window.showErrorMessage(localize('failedToStartServiceErrorMsg', "Failed to start {0}", Constants.serviceName));
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { KustoIconProvider } from './iconProvider';
|
|||||||
import { createKustoApi } from './kustoApiFactory';
|
import { createKustoApi } from './kustoApiFactory';
|
||||||
import { KustoServer } from './kustoServer';
|
import { KustoServer } from './kustoServer';
|
||||||
import { promises as fs } from 'fs';
|
import { promises as fs } from 'fs';
|
||||||
|
import { TelemetryReporter } from './telemetry';
|
||||||
|
|
||||||
const localize = nls.loadMessageBundle();
|
const localize = nls.loadMessageBundle();
|
||||||
|
|
||||||
@@ -53,8 +54,8 @@ export async function activate(context: vscode.ExtensionContext): Promise<IExten
|
|||||||
// initialize client last so we don't have features stuck behind it
|
// initialize client last so we don't have features stuck behind it
|
||||||
const server = new KustoServer();
|
const server = new KustoServer();
|
||||||
context.subscriptions.push(server);
|
context.subscriptions.push(server);
|
||||||
await server.start(appContext); // Commented out until we have Kusto binaries properly setup in Blob location.
|
await server.start(appContext);
|
||||||
|
context.subscriptions.push(TelemetryReporter);
|
||||||
return createKustoApi(appContext);
|
return createKustoApi(appContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,118 +4,18 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as nls from 'vscode-nls';
|
import AdsTelemetryReporter from '@microsoft/ads-extension-telemetry';
|
||||||
import TelemetryReporter from '@microsoft/ads-extension-telemetry';
|
|
||||||
import { ErrorAction, ErrorHandler, Message, CloseAction } from 'vscode-languageclient';
|
import { ErrorAction, ErrorHandler, Message, CloseAction } from 'vscode-languageclient';
|
||||||
|
|
||||||
import * as Utils from './utils';
|
|
||||||
import * as Constants from './constants';
|
import * as Constants from './constants';
|
||||||
|
import * as nls from 'vscode-nls';
|
||||||
|
|
||||||
|
|
||||||
const localize = nls.loadMessageBundle();
|
const localize = nls.loadMessageBundle();
|
||||||
|
|
||||||
const packageJson = require('../package.json');
|
|
||||||
const viewKnownIssuesAction = localize('viewKnownIssuesText', "View Known Issues");
|
const viewKnownIssuesAction = localize('viewKnownIssuesText', "View Known Issues");
|
||||||
|
|
||||||
export interface ITelemetryEventProperties {
|
const packageInfo = vscode.extensions.getExtension(Constants.packageName)?.packageJSON;
|
||||||
[key: string]: string;
|
export const TelemetryReporter = new AdsTelemetryReporter<string, string>(packageInfo?.name, packageInfo?.version, packageInfo?.aiKey);
|
||||||
}
|
|
||||||
|
|
||||||
export interface ITelemetryEventMeasures {
|
|
||||||
[key: string]: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filters error paths to only include source files. Exported to support testing
|
|
||||||
*/
|
|
||||||
export function FilterErrorPath(line: string): string | undefined {
|
|
||||||
if (line) {
|
|
||||||
let values: string[] = line.split('/out/');
|
|
||||||
if (values.length <= 1) {
|
|
||||||
// Didn't match expected format
|
|
||||||
return line;
|
|
||||||
} else {
|
|
||||||
return values[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Telemetry {
|
|
||||||
private static reporter: TelemetryReporter;
|
|
||||||
private static disabled: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disable telemetry reporting
|
|
||||||
*/
|
|
||||||
public static disable(): void {
|
|
||||||
this.disabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the telemetry reporter for use.
|
|
||||||
*/
|
|
||||||
public static initialize(): void {
|
|
||||||
if (typeof this.reporter === 'undefined') {
|
|
||||||
// Check if the user has opted out of telemetry
|
|
||||||
if (!vscode.workspace.getConfiguration('telemetry').get<boolean>('enableTelemetry', true)) {
|
|
||||||
this.disable();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let packageInfo = Utils.getPackageInfo(packageJson)!;
|
|
||||||
this.reporter = new TelemetryReporter(packageInfo.name, packageInfo.version, packageInfo.aiKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a telemetry event for an exception
|
|
||||||
*/
|
|
||||||
public static sendTelemetryEventForException(
|
|
||||||
err: any, methodName: string, extensionConfigName: string): void {
|
|
||||||
let stackArray: string[];
|
|
||||||
let firstLine: string = '';
|
|
||||||
if (err !== undefined && err.stack !== undefined) {
|
|
||||||
stackArray = err.stack.split('\n');
|
|
||||||
if (stackArray !== undefined && stackArray.length >= 2) {
|
|
||||||
firstLine = stackArray[1]; // The fist line is the error message and we don't want to send that telemetry event
|
|
||||||
firstLine = FilterErrorPath(firstLine)!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only adding the method name and the fist line of the stack trace. We don't add the error message because it might have PII
|
|
||||||
this.sendTelemetryEvent('Exception', { methodName: methodName, errorLine: firstLine });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a telemetry event using application insights
|
|
||||||
*/
|
|
||||||
public static sendTelemetryEvent(
|
|
||||||
eventName: string,
|
|
||||||
properties?: ITelemetryEventProperties,
|
|
||||||
measures?: ITelemetryEventMeasures): void {
|
|
||||||
|
|
||||||
if (typeof this.disabled === 'undefined') {
|
|
||||||
this.disabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.disabled || typeof (this.reporter) === 'undefined') {
|
|
||||||
// Don't do anything if telemetry is disabled
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!properties || typeof properties === 'undefined') {
|
|
||||||
properties = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.reporter.sendTelemetryEvent(eventName, properties, measures);
|
|
||||||
} catch (telemetryErr) {
|
|
||||||
// If sending telemetry event fails ignore it so it won't break the extension
|
|
||||||
console.error('Failed to send telemetry event. error: ' + telemetryErr);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle Language Service client errors
|
* Handle Language Service client errors
|
||||||
@@ -127,12 +27,12 @@ export class LanguageClientErrorHandler implements ErrorHandler {
|
|||||||
* @memberOf LanguageClientErrorHandler
|
* @memberOf LanguageClientErrorHandler
|
||||||
*/
|
*/
|
||||||
showOnErrorPrompt(): void {
|
showOnErrorPrompt(): void {
|
||||||
Telemetry.sendTelemetryEvent(Constants.serviceName + 'Crash');
|
TelemetryReporter.sendTelemetryEvent(Constants.serviceName + 'Crash');
|
||||||
vscode.window.showErrorMessage(
|
void vscode.window.showErrorMessage(
|
||||||
localize('serviceCrashMessage', "{0} component exited unexpectedly. Please restart Azure Data Studio.", Constants.serviceName),
|
localize('serviceCrashMessage', "{0} component exited unexpectedly. Please restart Azure Data Studio.", Constants.serviceName),
|
||||||
viewKnownIssuesAction).then(action => {
|
viewKnownIssuesAction).then(action => {
|
||||||
if (action && action === viewKnownIssuesAction) {
|
if (action && action === viewKnownIssuesAction) {
|
||||||
vscode.env.openExternal(vscode.Uri.parse(Constants.serviceCrashLink));
|
void vscode.env.openExternal(vscode.Uri.parse(Constants.serviceCrashLink));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -142,7 +42,7 @@ export class LanguageClientErrorHandler implements ErrorHandler {
|
|||||||
*
|
*
|
||||||
* @memberOf LanguageClientErrorHandler
|
* @memberOf LanguageClientErrorHandler
|
||||||
*/
|
*/
|
||||||
error(error: Error, message: Message, count: number): ErrorAction {
|
error(_error: Error, _message: Message, _count: number): ErrorAction {
|
||||||
this.showOnErrorPrompt();
|
this.showOnErrorPrompt();
|
||||||
|
|
||||||
// we don't retry running the service since crashes leave the extension
|
// we don't retry running the service since crashes leave the extension
|
||||||
@@ -163,5 +63,3 @@ export class LanguageClientErrorHandler implements ErrorHandler {
|
|||||||
return CloseAction.DoNotRestart;
|
return CloseAction.DoNotRestart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Telemetry.initialize();
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export const serviceName = 'SQL Tools Service';
|
|||||||
export const providerId = 'MSSQL';
|
export const providerId = 'MSSQL';
|
||||||
export const serviceCrashLink = 'https://github.com/Microsoft/vscode-mssql/wiki/SqlToolsService-Known-Issues';
|
export const serviceCrashLink = 'https://github.com/Microsoft/vscode-mssql/wiki/SqlToolsService-Known-Issues';
|
||||||
export const extensionConfigSectionName = 'mssql';
|
export const extensionConfigSectionName = 'mssql';
|
||||||
|
export const packageName = 'Microsoft.mssql';
|
||||||
|
|
||||||
// DATA PROTOCOL VALUES ///////////////////////////////////////////////////////////
|
// DATA PROTOCOL VALUES ///////////////////////////////////////////////////////////
|
||||||
export const sqlProviderName = 'MSSQL';
|
export const sqlProviderName = 'MSSQL';
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { NotificationType, RequestType } from 'vscode-languageclient';
|
import { NotificationType, RequestType } from 'vscode-languageclient';
|
||||||
import { ITelemetryEventProperties, ITelemetryEventMeasures } from './telemetry';
|
import * as telemetry from '@microsoft/ads-extension-telemetry';
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
import { ConnectParams } from 'dataprotocol-client/lib/protocol';
|
import { ConnectParams } from 'dataprotocol-client/lib/protocol';
|
||||||
import * as mssql from 'mssql';
|
import * as mssql from 'mssql';
|
||||||
@@ -24,8 +24,8 @@ export namespace TelemetryNotification {
|
|||||||
export class TelemetryParams {
|
export class TelemetryParams {
|
||||||
public params: {
|
public params: {
|
||||||
eventName: string;
|
eventName: string;
|
||||||
properties: ITelemetryEventProperties;
|
properties: telemetry.TelemetryEventProperties;
|
||||||
measures: ITelemetryEventMeasures;
|
measures: telemetry.TelemetryEventMeasures;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import * as nls from 'vscode-nls';
|
|||||||
import { SqlOpsDataClient, SqlOpsFeature } from 'dataprotocol-client';
|
import { SqlOpsDataClient, SqlOpsFeature } from 'dataprotocol-client';
|
||||||
import { ClientCapabilities, StaticFeature, RPCMessageType, ServerCapabilities } from 'vscode-languageclient';
|
import { ClientCapabilities, StaticFeature, RPCMessageType, ServerCapabilities } from 'vscode-languageclient';
|
||||||
import { Disposable, window, QuickPickItem, QuickPickOptions } from 'vscode';
|
import { Disposable, window, QuickPickItem, QuickPickOptions } from 'vscode';
|
||||||
import { Telemetry } from './telemetry';
|
import { TelemetryReporter } from './telemetry';
|
||||||
import * as contracts from './contracts';
|
import * as contracts from './contracts';
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
import * as Utils from './utils';
|
import * as Utils from './utils';
|
||||||
@@ -27,7 +27,7 @@ export class TelemetryFeature implements StaticFeature {
|
|||||||
|
|
||||||
initialize(): void {
|
initialize(): void {
|
||||||
this._client.onNotification(contracts.TelemetryNotification.type, e => {
|
this._client.onNotification(contracts.TelemetryNotification.type, e => {
|
||||||
Telemetry.sendTelemetryEvent(e.params.eventName, e.params.properties, e.params.measures);
|
TelemetryReporter.sendTelemetryEvent(e.params.eventName, e.params.properties, e.params.measures);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import { IconPathHelper } from './iconHelper';
|
|||||||
import * as nls from 'vscode-nls';
|
import * as nls from 'vscode-nls';
|
||||||
import { INotebookConvertService } from './notebookConvert/notebookConvertService';
|
import { INotebookConvertService } from './notebookConvert/notebookConvertService';
|
||||||
import { registerTableDesignerCommands } from './tableDesigner/tableDesigner';
|
import { registerTableDesignerCommands } from './tableDesigner/tableDesigner';
|
||||||
|
import { TelemetryReporter } from './telemetry';
|
||||||
|
|
||||||
const localize = nls.loadMessageBundle();
|
const localize = nls.loadMessageBundle();
|
||||||
|
|
||||||
@@ -88,6 +89,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<IExten
|
|||||||
|
|
||||||
registerTableDesignerCommands(appContext);
|
registerTableDesignerCommands(appContext);
|
||||||
|
|
||||||
|
context.subscriptions.push(TelemetryReporter);
|
||||||
return createMssqlApi(appContext, server);
|
return createMssqlApi(appContext, server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import * as Constants from './constants';
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { getCommonLaunchArgsAndCleanupOldLogFiles, getConfigTracingLevel, getOrDownloadServer, getParallelMessageProcessingConfig, TracingLevel } from './utils';
|
import { getCommonLaunchArgsAndCleanupOldLogFiles, getConfigTracingLevel, getOrDownloadServer, getParallelMessageProcessingConfig, TracingLevel } from './utils';
|
||||||
import { Telemetry, LanguageClientErrorHandler } from './telemetry';
|
import { TelemetryReporter, LanguageClientErrorHandler } from './telemetry';
|
||||||
import { SqlOpsDataClient, ClientOptions } from 'dataprotocol-client';
|
import { SqlOpsDataClient, ClientOptions } from 'dataprotocol-client';
|
||||||
import { TelemetryFeature, AgentServicesFeature, SerializationFeature, AccountFeature, SqlAssessmentServicesFeature, ProfilerFeature, TableDesignerFeature, ExecutionPlanServiceFeature } from './features';
|
import { TelemetryFeature, AgentServicesFeature, SerializationFeature, AccountFeature, SqlAssessmentServicesFeature, ProfilerFeature, TableDesignerFeature, ExecutionPlanServiceFeature } from './features';
|
||||||
import { CredentialStore } from './credentialstore/credentialstore';
|
import { CredentialStore } from './credentialstore/credentialstore';
|
||||||
@@ -69,7 +69,7 @@ export class SqlToolsServer {
|
|||||||
vscode.commands.registerCommand('mssql.loadCompletionExtension', (params: CompletionExtensionParams) => {
|
vscode.commands.registerCommand('mssql.loadCompletionExtension', (params: CompletionExtensionParams) => {
|
||||||
return this.client.sendRequest(CompletionExtLoadRequest.type, params);
|
return this.client.sendRequest(CompletionExtLoadRequest.type, params);
|
||||||
});
|
});
|
||||||
Telemetry.sendTelemetryEvent('startup/LanguageClientStarted', {
|
TelemetryReporter.sendTelemetryEvent('startup/LanguageClientStarted', {
|
||||||
installationTime: String(installationComplete - installationStart),
|
installationTime: String(installationComplete - installationStart),
|
||||||
processStartupTime: String(processEnd - processStart),
|
processStartupTime: String(processEnd - processStart),
|
||||||
totalTime: String(processEnd - installationStart),
|
totalTime: String(processEnd - installationStart),
|
||||||
@@ -82,7 +82,7 @@ export class SqlToolsServer {
|
|||||||
await Promise.all([this.activateFeatures(context), clientReadyPromise]);
|
await Promise.all([this.activateFeatures(context), clientReadyPromise]);
|
||||||
return this.client;
|
return this.client;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Telemetry.sendTelemetryEvent('ServiceInitializingFailed');
|
TelemetryReporter.sendTelemetryEvent('ServiceInitializingFailed');
|
||||||
void vscode.window.showErrorMessage(localize('failedToStartServiceErrorMsg', "Failed to start {0}", Constants.serviceName));
|
void vscode.window.showErrorMessage(localize('failedToStartServiceErrorMsg', "Failed to start {0}", Constants.serviceName));
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ import * as azdata from 'azdata';
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { sqlProviderName } from '../constants';
|
import { sqlProviderName } from '../constants';
|
||||||
import { generateUuid } from 'vscode-languageclient/lib/utils/uuid';
|
import { generateUuid } from 'vscode-languageclient/lib/utils/uuid';
|
||||||
import { ITelemetryEventProperties, Telemetry } from '../telemetry';
|
import { fillServerInfo } from '../telemetry';
|
||||||
|
import * as telemetry from '@microsoft/ads-extension-telemetry';
|
||||||
import * as nls from 'vscode-nls';
|
import * as nls from 'vscode-nls';
|
||||||
import { getConfigPreloadDatabaseModel, setConfigPreloadDatabaseModel } from '../utils';
|
import { getConfigPreloadDatabaseModel, setConfigPreloadDatabaseModel } from '../utils';
|
||||||
const localize = nls.loadMessageBundle();
|
const localize = nls.loadMessageBundle();
|
||||||
@@ -60,11 +61,12 @@ export function registerTableDesignerCommands(appContext: AppContext) {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getTelemetryInfo(context: azdata.ObjectExplorerContext, tableType: string): Promise<ITelemetryEventProperties> {
|
async function getTelemetryInfo(context: azdata.ObjectExplorerContext, tableType: string): Promise<telemetry.TelemetryEventProperties> {
|
||||||
const serverInfo = await azdata.connection.getServerInfo(context.connectionProfile.id);
|
const serverInfo = await azdata.connection.getServerInfo(context.connectionProfile.id);
|
||||||
const telemetryInfo: ITelemetryEventProperties = {};
|
const telemetryInfo: telemetry.TelemetryEventProperties = {
|
||||||
Telemetry.fillServerInfo(telemetryInfo, serverInfo);
|
tableType
|
||||||
telemetryInfo['tableType'] = tableType;
|
};
|
||||||
|
fillServerInfo(telemetryInfo, serverInfo);
|
||||||
return telemetryInfo;
|
return telemetryInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,129 +4,30 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import TelemetryReporter from '@microsoft/ads-extension-telemetry';
|
import AdsTelemetryReporter from '@microsoft/ads-extension-telemetry';
|
||||||
import { ErrorAction, ErrorHandler, Message, CloseAction } from 'vscode-languageclient';
|
import { ErrorAction, ErrorHandler, Message, CloseAction } from 'vscode-languageclient';
|
||||||
|
|
||||||
import * as Utils from './utils';
|
|
||||||
import * as Constants from './constants';
|
import * as Constants from './constants';
|
||||||
import * as nls from 'vscode-nls';
|
import * as nls from 'vscode-nls';
|
||||||
import { ServerInfo } from 'azdata';
|
import { ServerInfo } from 'azdata';
|
||||||
|
|
||||||
|
|
||||||
const localize = nls.loadMessageBundle();
|
const localize = nls.loadMessageBundle();
|
||||||
const packageJson = require('../package.json');
|
|
||||||
const viewKnownIssuesAction = localize('viewKnownIssuesText', "View Known Issues");
|
const viewKnownIssuesAction = localize('viewKnownIssuesText', "View Known Issues");
|
||||||
|
|
||||||
export interface ITelemetryEventProperties {
|
const packageInfo = vscode.extensions.getExtension(Constants.packageName)?.packageJSON;
|
||||||
[key: string]: string;
|
export const TelemetryReporter = new AdsTelemetryReporter<string, string>(packageInfo?.name, packageInfo?.version, packageInfo?.aiKey);
|
||||||
}
|
|
||||||
|
|
||||||
export interface ITelemetryEventMeasures {
|
|
||||||
[key: string]: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filters error paths to only include source files. Exported to support testing
|
|
||||||
*/
|
|
||||||
function FilterErrorPath(line: string): string {
|
|
||||||
if (line) {
|
|
||||||
let values: string[] = line.split('/out/');
|
|
||||||
if (values.length <= 1) {
|
|
||||||
// Didn't match expected format
|
|
||||||
return line;
|
|
||||||
} else {
|
|
||||||
return values[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Telemetry {
|
|
||||||
private static reporter: TelemetryReporter;
|
|
||||||
private static disabled: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disable telemetry reporting
|
|
||||||
*/
|
|
||||||
public static disable(): void {
|
|
||||||
this.disabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the telemetry reporter for use.
|
|
||||||
*/
|
|
||||||
public static initialize(): void {
|
|
||||||
if (typeof this.reporter === 'undefined') {
|
|
||||||
// Check if the user has opted out of telemetry
|
|
||||||
if (!vscode.workspace.getConfiguration('telemetry').get<boolean>('enableTelemetry', true)) {
|
|
||||||
this.disable();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let packageInfo = Utils.getPackageInfo(packageJson);
|
|
||||||
this.reporter = new TelemetryReporter(packageInfo.name, packageInfo.version, packageInfo.aiKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a telemetry event for an exception
|
|
||||||
*/
|
|
||||||
public static sendTelemetryEventForException(
|
|
||||||
err: any, methodName: string, extensionConfigName: string): void {
|
|
||||||
let stackArray: string[];
|
|
||||||
let firstLine: string = '';
|
|
||||||
if (err !== undefined && err.stack !== undefined) {
|
|
||||||
stackArray = err.stack.split('\n');
|
|
||||||
if (stackArray !== undefined && stackArray.length >= 2) {
|
|
||||||
firstLine = stackArray[1]; // The fist line is the error message and we don't want to send that telemetry event
|
|
||||||
firstLine = FilterErrorPath(firstLine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only adding the method name and the fist line of the stack trace. We don't add the error message because it might have PII
|
|
||||||
this.sendTelemetryEvent('Exception', { methodName: methodName, errorLine: firstLine });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a telemetry event using application insights
|
|
||||||
*/
|
|
||||||
public static sendTelemetryEvent(
|
|
||||||
eventName: string,
|
|
||||||
properties?: ITelemetryEventProperties,
|
|
||||||
measures?: ITelemetryEventMeasures): void {
|
|
||||||
|
|
||||||
if (typeof this.disabled === 'undefined') {
|
|
||||||
this.disabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.disabled || typeof (this.reporter) === 'undefined') {
|
|
||||||
// Don't do anything if telemetry is disabled
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!properties || typeof properties === 'undefined') {
|
|
||||||
properties = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.reporter.sendTelemetryEvent(eventName, properties, measures);
|
|
||||||
} catch (telemetryErr) {
|
|
||||||
// If sending telemetry event fails ignore it so it won't break the extension
|
|
||||||
console.error('Failed to send telemetry event. error: ' + telemetryErr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Collects server information from ServerInfo to put into a
|
* Collects server information from ServerInfo to put into a
|
||||||
* property bag
|
* property bag
|
||||||
*/
|
*/
|
||||||
public static fillServerInfo(telemetryInfo: { [key: string]: string }, serverInfo: ServerInfo): void {
|
export function fillServerInfo(telemetryInfo: { [key: string]: string }, serverInfo: ServerInfo): void {
|
||||||
telemetryInfo['serverEdition'] = serverInfo?.serverEdition;
|
telemetryInfo['serverEdition'] = serverInfo?.serverEdition;
|
||||||
telemetryInfo['serverLevel'] = serverInfo?.serverLevel;
|
telemetryInfo['serverLevel'] = serverInfo?.serverLevel;
|
||||||
telemetryInfo['serverMajorVersion'] = serverInfo?.serverMajorVersion.toString();
|
telemetryInfo['serverMajorVersion'] = serverInfo?.serverMajorVersion.toString();
|
||||||
telemetryInfo['serverMinorVersion'] = serverInfo?.serverMinorVersion.toString();
|
telemetryInfo['serverMinorVersion'] = serverInfo?.serverMinorVersion.toString();
|
||||||
telemetryInfo['isCloud'] = serverInfo?.isCloud.toString();
|
telemetryInfo['isCloud'] = serverInfo?.isCloud.toString();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -139,7 +40,7 @@ export class LanguageClientErrorHandler implements ErrorHandler {
|
|||||||
* @memberOf LanguageClientErrorHandler
|
* @memberOf LanguageClientErrorHandler
|
||||||
*/
|
*/
|
||||||
showOnErrorPrompt(): void {
|
showOnErrorPrompt(): void {
|
||||||
Telemetry.sendTelemetryEvent(Constants.serviceName + 'Crash');
|
TelemetryReporter.sendTelemetryEvent(Constants.serviceName + 'Crash');
|
||||||
void vscode.window.showErrorMessage(
|
void vscode.window.showErrorMessage(
|
||||||
localize('serviceCrashMessage', "{0} component exited unexpectedly. Please restart Azure Data Studio.", Constants.serviceName),
|
localize('serviceCrashMessage', "{0} component exited unexpectedly. Please restart Azure Data Studio.", Constants.serviceName),
|
||||||
viewKnownIssuesAction).then(action => {
|
viewKnownIssuesAction).then(action => {
|
||||||
@@ -175,5 +76,3 @@ export class LanguageClientErrorHandler implements ErrorHandler {
|
|||||||
return CloseAction.DoNotRestart;
|
return CloseAction.DoNotRestart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Telemetry.initialize();
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import { ExtensionContextHelper } from './common/extensionContextHelper';
|
|||||||
import { BookTreeItem } from './book/bookTreeItem';
|
import { BookTreeItem } from './book/bookTreeItem';
|
||||||
import Logger from './common/logger';
|
import Logger from './common/logger';
|
||||||
import { sendNotebookActionEvent, NbTelemetryView, NbTelemetryAction } from './telemetry';
|
import { sendNotebookActionEvent, NbTelemetryView, NbTelemetryAction } from './telemetry';
|
||||||
|
import { TelemetryReporter } from './telemetry';
|
||||||
|
|
||||||
const localize = nls.loadMessageBundle();
|
const localize = nls.loadMessageBundle();
|
||||||
|
|
||||||
@@ -161,22 +162,23 @@ export async function activate(extensionContext: vscode.ExtensionContext): Promi
|
|||||||
const pinnedBookTreeViewProvider = appContext.pinnedBookTreeViewProvider;
|
const pinnedBookTreeViewProvider = appContext.pinnedBookTreeViewProvider;
|
||||||
await pinnedBookTreeViewProvider.initialized;
|
await pinnedBookTreeViewProvider.initialized;
|
||||||
|
|
||||||
azdata.nb.onDidChangeActiveNotebookEditor(e => {
|
extensionContext.subscriptions.push(azdata.nb.onDidChangeActiveNotebookEditor(e => {
|
||||||
if (e.document.uri.scheme === 'untitled') {
|
if (e.document.uri.scheme === 'untitled') {
|
||||||
void providedBookTreeViewProvider.revealDocumentInTreeView(e.document.uri, false, false);
|
void providedBookTreeViewProvider.revealDocumentInTreeView(e.document.uri, false, false);
|
||||||
} else {
|
} else {
|
||||||
void bookTreeViewProvider.revealDocumentInTreeView(e.document.uri, false, false);
|
void bookTreeViewProvider.revealDocumentInTreeView(e.document.uri, false, false);
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
|
|
||||||
azdata.nb.onDidOpenNotebookDocument(async e => {
|
extensionContext.subscriptions.push(azdata.nb.onDidOpenNotebookDocument(async e => {
|
||||||
if (e.uri.scheme === 'untitled') {
|
if (e.uri.scheme === 'untitled') {
|
||||||
await vscode.commands.executeCommand(BuiltInCommands.SetContext, unsavedBooksContextKey, true);
|
await vscode.commands.executeCommand(BuiltInCommands.SetContext, unsavedBooksContextKey, true);
|
||||||
} else {
|
} else {
|
||||||
await vscode.commands.executeCommand(BuiltInCommands.SetContext, unsavedBooksContextKey, false);
|
await vscode.commands.executeCommand(BuiltInCommands.SetContext, unsavedBooksContextKey, false);
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
|
|
||||||
|
extensionContext.subscriptions.push(TelemetryReporter);
|
||||||
return {
|
return {
|
||||||
getJupyterController() {
|
getJupyterController() {
|
||||||
return controller;
|
return controller;
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
|
|||||||
context.subscriptions.push(vscode.commands.registerCommand('queryHistory.openStorageFolder', async () => {
|
context.subscriptions.push(vscode.commands.registerCommand('queryHistory.openStorageFolder', async () => {
|
||||||
return vscode.env.openExternal(storageUri);
|
return vscode.env.openExternal(storageUri);
|
||||||
}));
|
}));
|
||||||
|
context.subscriptions.push(TelemetryReporter);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function openQuery(item: QueryHistoryItem): Promise<void> {
|
async function openQuery(item: QueryHistoryItem): Promise<void> {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { ResourceTypePickerDialog } from './ui/resourceTypePickerDialog';
|
|||||||
import * as rd from 'resource-deployment';
|
import * as rd from 'resource-deployment';
|
||||||
import { getExtensionApi } from './api';
|
import { getExtensionApi } from './api';
|
||||||
import { UriHandlerService } from './services/uriHandlerService';
|
import { UriHandlerService } from './services/uriHandlerService';
|
||||||
|
import { TelemetryReporter } from './services/telemetryService';
|
||||||
|
|
||||||
const localize = nls.loadMessageBundle();
|
const localize = nls.loadMessageBundle();
|
||||||
|
|
||||||
@@ -46,9 +47,9 @@ export async function activate(context: vscode.ExtensionContext): Promise<rd.IEx
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
vscode.commands.registerCommand('azdata.resource.sql-image.deploy', () => {
|
context.subscriptions.push(vscode.commands.registerCommand('azdata.resource.sql-image.deploy', () => {
|
||||||
openDialog('sql-image');
|
openDialog('sql-image');
|
||||||
});
|
}));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Command to open the Resource Deployment wizard - with options to filter the values shown
|
* Command to open the Resource Deployment wizard - with options to filter the values shown
|
||||||
@@ -59,7 +60,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<rd.IEx
|
|||||||
* @param initialVariableValues - Optional list of initial values to assign to variables. This is an object of key/value pairs in the format
|
* @param initialVariableValues - Optional list of initial values to assign to variables. This is an object of key/value pairs in the format
|
||||||
* { "VARIABLE_NAME": "value", "OTHER_VARIABLE_NAME": "value" }
|
* { "VARIABLE_NAME": "value", "OTHER_VARIABLE_NAME": "value" }
|
||||||
*/
|
*/
|
||||||
vscode.commands.registerCommand('azdata.resource.deploy', (defaultResourceTypeName?: string, resourceTypeNameFilters?: string[], optionValuesFilter?: OptionValuesFilter, initialVariableValues?: InitialVariableValues) => {
|
context.subscriptions.push(vscode.commands.registerCommand('azdata.resource.deploy', (defaultResourceTypeName?: string, resourceTypeNameFilters?: string[], optionValuesFilter?: OptionValuesFilter, initialVariableValues?: InitialVariableValues) => {
|
||||||
if ((resourceTypeNameFilters && !Array.isArray(resourceTypeNameFilters) ||
|
if ((resourceTypeNameFilters && !Array.isArray(resourceTypeNameFilters) ||
|
||||||
(resourceTypeNameFilters && resourceTypeNameFilters.length > 0 && typeof resourceTypeNameFilters[0] !== 'string'))) {
|
(resourceTypeNameFilters && resourceTypeNameFilters.length > 0 && typeof resourceTypeNameFilters[0] !== 'string'))) {
|
||||||
throw new Error('resourceTypeNameFilters must either be undefined or an array of strings');
|
throw new Error('resourceTypeNameFilters must either be undefined or an array of strings');
|
||||||
@@ -76,11 +77,14 @@ export async function activate(context: vscode.ExtensionContext): Promise<rd.IEx
|
|||||||
}
|
}
|
||||||
openDialog(defaultDeploymentType, resourceTypeNameFilters, optionValuesFilter, initialVariableValues);
|
openDialog(defaultDeploymentType, resourceTypeNameFilters, optionValuesFilter, initialVariableValues);
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
vscode.commands.registerCommand('azdata.openNotebookInputDialog', (dialogInfo: NotebookBasedDialogInfo) => {
|
|
||||||
|
context.subscriptions.push(vscode.commands.registerCommand('azdata.openNotebookInputDialog', (dialogInfo: NotebookBasedDialogInfo) => {
|
||||||
const dialog = new DeploymentInputDialog(notebookService, platformService, toolsService, dialogInfo);
|
const dialog = new DeploymentInputDialog(notebookService, platformService, toolsService, dialogInfo);
|
||||||
dialog.open();
|
dialog.open();
|
||||||
});
|
}));
|
||||||
|
|
||||||
|
context.subscriptions.push(TelemetryReporter);
|
||||||
return getExtensionApi();
|
return getExtensionApi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,13 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as mssql from 'mssql';
|
import * as mssql from 'mssql';
|
||||||
import { SchemaCompareMainWindow } from './schemaCompareMainWindow';
|
import { SchemaCompareMainWindow } from './schemaCompareMainWindow';
|
||||||
|
import { TelemetryReporter } from './telemetry';
|
||||||
|
|
||||||
export async function activate(extensionContext: vscode.ExtensionContext): Promise<void> {
|
export async function activate(extensionContext: vscode.ExtensionContext): Promise<void> {
|
||||||
vscode.commands.registerCommand('schemaCompare.start', async (sourceContext: any, targetContext: any = undefined, comparisonResult: any = undefined) => { await new SchemaCompareMainWindow(undefined, extensionContext, undefined).start(sourceContext, targetContext, comparisonResult); });
|
extensionContext.subscriptions.push(vscode.commands.registerCommand('schemaCompare.start', async (sourceContext: any, targetContext: any = undefined, comparisonResult: any = undefined) => { await new SchemaCompareMainWindow(undefined, extensionContext, undefined).start(sourceContext, targetContext, comparisonResult); }));
|
||||||
vscode.commands.registerCommand('schemaCompare.runComparison', async (source: mssql.SchemaCompareEndpointInfo | undefined, target: mssql.SchemaCompareEndpointInfo | undefined, runComparison: boolean = false, comparisonResult: mssql.SchemaCompareResult | undefined) => { await new SchemaCompareMainWindow(undefined, extensionContext, undefined).launch(source, target, runComparison, comparisonResult); });
|
extensionContext.subscriptions.push(vscode.commands.registerCommand('schemaCompare.runComparison', async (source: mssql.SchemaCompareEndpointInfo | undefined, target: mssql.SchemaCompareEndpointInfo | undefined, runComparison: boolean = false, comparisonResult: mssql.SchemaCompareResult | undefined) => { await new SchemaCompareMainWindow(undefined, extensionContext, undefined).launch(source, target, runComparison, comparisonResult); }));
|
||||||
vscode.commands.registerCommand('schemaCompare.openInScmp', async (fileUri: vscode.Uri) => { await new SchemaCompareMainWindow(undefined, extensionContext, undefined).openScmpFile(fileUri); });
|
extensionContext.subscriptions.push(vscode.commands.registerCommand('schemaCompare.openInScmp', async (fileUri: vscode.Uri) => { await new SchemaCompareMainWindow(undefined, extensionContext, undefined).openScmpFile(fileUri); }));
|
||||||
|
extensionContext.subscriptions.push(TelemetryReporter);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deactivate(): void {
|
export function deactivate(): void {
|
||||||
|
|||||||
@@ -6,12 +6,14 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
import MainController from './maincontroller';
|
import MainController from './maincontroller';
|
||||||
|
import { TelemetryReporter } from './telemetry';
|
||||||
|
|
||||||
let mainController: MainController;
|
let mainController: MainController;
|
||||||
|
|
||||||
export function activate(context: vscode.ExtensionContext) {
|
export async function activate(context: vscode.ExtensionContext) {
|
||||||
mainController = new MainController(context);
|
mainController = new MainController(context);
|
||||||
mainController.activate();
|
await mainController.activate();
|
||||||
|
context.subscriptions.push(TelemetryReporter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this method is called when your extension is deactivated
|
// this method is called when your extension is deactivated
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { IExtension, BindingType, GetAzureFunctionsResult, ResultStatus, IConnec
|
|||||||
import { addSqlBinding, createAzureFunction, getAzureFunctions } from './services/azureFunctionsService';
|
import { addSqlBinding, createAzureFunction, getAzureFunctions } from './services/azureFunctionsService';
|
||||||
import { launchAddSqlBindingQuickpick } from './dialogs/addSqlBindingQuickpick';
|
import { launchAddSqlBindingQuickpick } from './dialogs/addSqlBindingQuickpick';
|
||||||
import { promptForBindingType, promptAndUpdateConnectionStringSetting, promptForObjectName, addSqlNugetReferenceToProjectFile } from './common/azureFunctionsUtils';
|
import { promptForBindingType, promptAndUpdateConnectionStringSetting, promptForObjectName, addSqlNugetReferenceToProjectFile } from './common/azureFunctionsUtils';
|
||||||
|
import { TelemetryReporter } from './common/telemetry';
|
||||||
|
|
||||||
export async function activate(context: vscode.ExtensionContext): Promise<IExtension> {
|
export async function activate(context: vscode.ExtensionContext): Promise<IExtension> {
|
||||||
// register the add sql binding command
|
// register the add sql binding command
|
||||||
@@ -16,6 +17,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<IExten
|
|||||||
context.subscriptions.push(vscode.commands.registerCommand('sqlBindings.createAzureFunction', async (node?: ITreeNodeInfo) => {
|
context.subscriptions.push(vscode.commands.registerCommand('sqlBindings.createAzureFunction', async (node?: ITreeNodeInfo) => {
|
||||||
return await createAzureFunction(node);
|
return await createAzureFunction(node);
|
||||||
}));
|
}));
|
||||||
|
context.subscriptions.push(TelemetryReporter);
|
||||||
return {
|
return {
|
||||||
addSqlBinding: async (bindingType: BindingType, filePath: string, functionName: string, objectName: string, connectionStringSetting: string): Promise<ResultStatus> => {
|
addSqlBinding: async (bindingType: BindingType, filePath: string, functionName: string, objectName: string, connectionStringSetting: string): Promise<ResultStatus> => {
|
||||||
return addSqlBinding(bindingType, filePath, functionName, objectName, connectionStringSetting);
|
return addSqlBinding(bindingType, filePath, functionName, objectName, connectionStringSetting);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import * as vscode from 'vscode';
|
|||||||
import { getAzdataApi } from './common/utils';
|
import { getAzdataApi } from './common/utils';
|
||||||
import MainController from './controllers/mainController';
|
import MainController from './controllers/mainController';
|
||||||
import { SqlDatabaseProjectProvider } from './projectProvider/projectProvider';
|
import { SqlDatabaseProjectProvider } from './projectProvider/projectProvider';
|
||||||
|
import { TelemetryReporter } from './common/telemetry';
|
||||||
|
|
||||||
let controllers: MainController[] = [];
|
let controllers: MainController[] = [];
|
||||||
|
|
||||||
@@ -16,7 +17,7 @@ export function activate(context: vscode.ExtensionContext): Promise<SqlDatabaseP
|
|||||||
const mainController = new MainController(context);
|
const mainController = new MainController(context);
|
||||||
controllers.push(mainController);
|
controllers.push(mainController);
|
||||||
context.subscriptions.push(mainController);
|
context.subscriptions.push(mainController);
|
||||||
|
context.subscriptions.push(TelemetryReporter);
|
||||||
return mainController.activate();
|
return mainController.activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,13 @@
|
|||||||
|
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { DashboardWidget } from './dashboard/sqlServerDashboard';
|
import { DashboardWidget } from './dashboard/sqlServerDashboard';
|
||||||
|
import { TelemetryReporter } from './telemetry';
|
||||||
|
|
||||||
let widget: DashboardWidget;
|
let widget: DashboardWidget;
|
||||||
export async function activate(context: vscode.ExtensionContext): Promise<DashboardWidget> {
|
export async function activate(context: vscode.ExtensionContext): Promise<DashboardWidget> {
|
||||||
widget = new DashboardWidget(context);
|
widget = new DashboardWidget(context);
|
||||||
await widget.register();
|
await widget.register();
|
||||||
|
context.subscriptions.push(TelemetryReporter);
|
||||||
return widget;
|
return widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user