Skip to content

Commit 45530ab

Browse files
authored
Add telemetry (#6)
* remove unwanted and unused deps and features * enable decorators * telemetry helper * telemetry for activation of extension * moved type declaration close to source * changes to how conda version is captured * telemetry for formatters * telemetry added * capture telemetry when interpreter is set * resolved linter warning * added telemetry for workspace symbols * added telemetry for code execution * refactorred telemetry code * added telemetry for unit tests * added copyright header * fix test runner id * more strictness for later * add copyright header * tests for interpreter and pip version * missed colon * do not stop discovery when running tests * incorrect telemetry scope for running unittests * fixed unit tests * fixed license headers * use regex when extracting version info * removed license header * fixed test * fixed typo * removed unwanted props * fixed typo * Simplify copyright header * Simplify copyright header * Simplify copyright header * Simplify copyright header * Simplify copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Remove copyright header * Simplify copyright header * Remove copyright header
1 parent 1187381 commit 45530ab

70 files changed

Lines changed: 1031 additions & 570 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/client/common/telemetry.ts

Lines changed: 0 additions & 79 deletions
This file was deleted.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
export const COMPLETION = 'COMPLETION';
4+
export const DEFINITION = 'DEFINITION';
5+
export const HOVER_DEFINITION = 'HOVER_DEFINITION';
6+
export const REFERENCE = 'REFERENCE';
7+
export const SIGNATURE = 'SIGNATURE';
8+
export const SYMBOL = 'SYMBOL';
9+
export const FORMAT_SORT_IMPORTS = 'FORMAT.SORT_IMPORTS';
10+
export const FORMAT = 'FORMAT.FORMAT';
11+
export const EDITOR_LOAD = 'EDITOR.LOAD';
12+
export const LINTING = 'LINTING';
13+
export const GO_TO_OBJECT_DEFINITION = 'GO_TO_OBJECT_DEFINITION';
14+
export const UPDATE_PYSPARK_LIBRARY = 'UPDATE_PYSPARK_LIBRARY';
15+
export const REFACTOR_RENAME = 'REFACTOR_RENAME';
16+
export const REFACTOR_EXTRACT_VAR = 'REFACTOR_EXTRACT_VAR';
17+
export const REFACTOR_EXTRACT_FUNCTION = 'REFACTOR_EXTRACT_FUNCTION';
18+
export const REPL = 'REPL';
19+
export const PYTHON_INTERPRETER = 'PYTHON_INTERPRETER';
20+
export const WORKSPACE_SYMBOLS_BUILD = 'WORKSPACE_SYMBOLS.BUILD';
21+
export const WORKSPACE_SYMBOLS_GO_TO = 'WORKSPACE_SYMBOLS.GO_TO';
22+
export const EXECUTION_CODE = 'EXECUTION_CODE';
23+
export const EXECUTION_DJANGO = 'EXECUTION_DJANGO';
24+
export const DEBUGGER = 'DEBUGGER';
25+
export const UNITTEST_STOP = 'UNITTEST.STOP';
26+
export const UNITTEST_RUN = 'UNITTEST.RUN';
27+
export const UNITTEST_DISCOVER = 'UNITTEST.DISCOVER';
28+
export const UNITTEST_VIEW_OUTPUT = 'UNITTEST.VIEW_OUTPUT';
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
import { StopWatch } from './stopWatch';
5+
import { getTelemetryReporter } from './telemetry';
6+
import { TelemetryProperties } from './types';
7+
8+
export function sendTelemetryEvent(eventName: string, durationMs?: number, properties?: TelemetryProperties) {
9+
const reporter = getTelemetryReporter();
10+
const measures = typeof durationMs === 'number' ? { duration: durationMs } : undefined;
11+
12+
// tslint:disable-next-line:no-any
13+
const customProperties: { [key: string]: string } = {};
14+
if (properties) {
15+
// tslint:disable-next-line:prefer-type-cast no-any
16+
const data = properties as any;
17+
Object.getOwnPropertyNames(data).forEach(prop => {
18+
// tslint:disable-next-line:prefer-type-cast no-any no-unsafe-any
19+
(customProperties as any)[prop] = typeof data[prop] === 'string' ? data[prop] : data[prop].toString();
20+
});
21+
}
22+
//
23+
reporter.sendTelemetryEvent(eventName, properties ? customProperties : undefined, measures);
24+
}
25+
26+
// tslint:disable-next-line:no-any function-name
27+
export function captureTelemetry(eventName: string) {
28+
// tslint:disable-next-line:no-function-expression no-any
29+
return function (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) {
30+
const originalMethod = descriptor.value;
31+
// tslint:disable-next-line:no-function-expression no-any
32+
descriptor.value = function (...args: any[]) {
33+
const stopWatch = new StopWatch();
34+
// tslint:disable-next-line:no-invalid-this no-use-before-declare no-unsafe-any
35+
const result = originalMethod.apply(this, args);
36+
37+
// If method being wrapped returns a promise then wait for it.
38+
// tslint:disable-next-line:no-unsafe-any
39+
if (result && typeof result.then === 'function' && typeof result.catch === 'function') {
40+
// tslint:disable-next-line:prefer-type-cast
41+
(result as Promise<void>)
42+
.then(data => {
43+
sendTelemetryEvent(eventName, stopWatch.elapsedTime);
44+
return data;
45+
})
46+
// tslint:disable-next-line:promise-function-async
47+
.catch(ex => {
48+
sendTelemetryEvent(eventName, stopWatch.elapsedTime);
49+
return Promise.reject(ex);
50+
});
51+
} else {
52+
sendTelemetryEvent(eventName, stopWatch.elapsedTime);
53+
}
54+
55+
return result;
56+
};
57+
58+
return descriptor;
59+
};
60+
}
61+
62+
// tslint:disable-next-line:no-any function-name
63+
export function sendTelemetryWhenDone(eventName: string, promise: Promise<any> | Thenable<any>,
64+
stopWatch?: StopWatch, properties?: TelemetryProperties) {
65+
stopWatch = stopWatch ? stopWatch : new StopWatch();
66+
if (typeof promise.then === 'function') {
67+
// tslint:disable-next-line:prefer-type-cast no-any
68+
(promise as Promise<any>)
69+
.then(data => {
70+
// tslint:disable-next-line:no-non-null-assertion
71+
sendTelemetryEvent(eventName, stopWatch!.elapsedTime, properties);
72+
return data;
73+
// tslint:disable-next-line:promise-function-async
74+
}, ex => {
75+
// tslint:disable-next-line:no-non-null-assertion
76+
sendTelemetryEvent(eventName, stopWatch!.elapsedTime, properties);
77+
return Promise.reject(ex);
78+
});
79+
} else {
80+
throw new Error('Method is neither a Promise nor a Theneable');
81+
}
82+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
export class StopWatch {
5+
private started: number = Date.now();
6+
private stopped?: number;
7+
public get elapsedTime() {
8+
return (this.stopped ? this.stopped : Date.now()) - this.started;
9+
}
10+
public stop() {
11+
this.stopped = Date.now();
12+
}
13+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
// tslint:disable-next-line:no-reference
5+
/// <reference path="./vscode-extension-telemetry.d.ts" />
6+
import { extensions } from 'vscode';
7+
// tslint:disable-next-line:import-name
8+
import TelemetryReporter from 'vscode-extension-telemetry';
9+
10+
// tslint:disable-next-line:no-any
11+
let telemetryReporter: TelemetryReporter;
12+
export function getTelemetryReporter() {
13+
if (telemetryReporter) {
14+
return telemetryReporter;
15+
}
16+
const extensionId = 'donjayamanne.python';
17+
// tslint:disable-next-line:no-non-null-assertion
18+
const extension = extensions.getExtension(extensionId)!;
19+
// tslint:disable-next-line:no-unsafe-any
20+
const extensionVersion = extension.packageJSON.version;
21+
// tslint:disable-next-line:no-unsafe-any
22+
const aiKey = extension.packageJSON.contributes.debuggers[0].aiKey;
23+
24+
// tslint:disable-next-line:no-unsafe-any
25+
return telemetryReporter = new TelemetryReporter(extensionId, extensionVersion, aiKey);
26+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
export type EditorLoadTelemetry = {
4+
condaVersion: string;
5+
};
6+
export type FormatTelemetry = {
7+
tool: 'autoppep8' | 'yapf';
8+
hasCustomArgs: boolean;
9+
formatSelection: boolean;
10+
};
11+
export type LintingTelemetry = {
12+
tool: 'flake8' | 'mypy' | 'pep8' | 'prospector' | 'pydocstyle' | 'pylama' | 'pylint';
13+
hasCustomArgs: boolean;
14+
trigger: 'save' | 'auto';
15+
executableSpecified: boolean;
16+
};
17+
export type PythonInterpreterTelemetry = {
18+
trigger: 'ui' | 'shebang' | 'load';
19+
failed: boolean;
20+
version: string;
21+
pipVersion: string;
22+
};
23+
export type CodeExecutionTelemetry = {
24+
scope: 'file' | 'selection';
25+
};
26+
export type DebuggerTelemetry = {
27+
trigger: 'launch' | 'attach'
28+
console?: 'none' | 'integratedTerminal' | 'externalTerminal';
29+
debugOptions?: string;
30+
pyspark?: boolean;
31+
hasEnvVars?: boolean;
32+
};
33+
export type TestRunTelemetry = {
34+
tool: 'nosetest' | 'pytest' | 'unittest'
35+
scope: 'currentFile' | 'all' | 'file' | 'class' | 'function' | 'failed';
36+
debugging: boolean;
37+
trigger: 'ui' | 'codelens' | 'commandpalette' | 'auto';
38+
failed: boolean;
39+
};
40+
export type TestDiscoverytTelemetry = {
41+
tool: 'nosetest' | 'pytest' | 'unittest'
42+
trigger: 'ui' | 'commandpalette';
43+
failed: boolean;
44+
};
45+
export type TelemetryProperties = FormatTelemetry | LintingTelemetry | EditorLoadTelemetry | PythonInterpreterTelemetry | CodeExecutionTelemetry | TestRunTelemetry | TestDiscoverytTelemetry;

src/client/typings/vscode-extension-telemetry/vscode-extension-telemetry.d.ts renamed to src/client/common/telemetry/vscode-extension-telemetry.d.ts

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,26 @@
1-
declare module "vscode-extension-telemetry" {
1+
declare module 'vscode-extension-telemetry' {
22
export default class TelemetryReporter {
3-
private extensionId;
4-
private extensionVersion;
5-
private appInsightsClient;
6-
private commonProperties;
7-
private static SQM_KEY;
8-
private static REGISTRY_USERID_VALUE;
9-
private static REGISTRY_MACHINEID_VALUE;
10-
113
/**
124
* Constructs a new telemetry reporter
135
* @param {string} extensionId All events will be prefixed with this event name
146
* @param {string} extensionVersion Extension version to be reported with each event
157
* @param {string} key The application insights key
168
*/
9+
// tslint:disable-next-line:no-empty
1710
constructor(extensionId: string, extensionVersion: string, key: string);
18-
private setupAIClient(client);
19-
private loadVSCodeCommonProperties(machineId, sessionId, version);
20-
private loadCommonProperties();
21-
private addCommonProperties(properties);
22-
private getWinRegKeyData(key, name, hive, callback);
2311

2412
/**
2513
* Sends a telemetry event
2614
* @param {string} eventName The event name
2715
* @param {object} properties An associative array of strings
2816
* @param {object} measures An associative array of numbers
2917
*/
30-
sendTelemetryEvent(eventName: string, properties?: {
18+
// tslint:disable-next-line:member-access
19+
public sendTelemetryEvent(eventName: string, properties?: {
3120
[key: string]: string;
3221
}, measures?: {
3322
[key: string]: number;
23+
// tslint:disable-next-line:no-empty
3424
}): void;
3525
}
36-
}
26+
}

src/client/common/telemetryContracts.ts

Lines changed: 0 additions & 31 deletions
This file was deleted.

src/client/common/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ export function areBasePathsSame(path1: string, path2: string) {
423423
path2 = IS_WINDOWS ? path2.replace(/\//g, "\\") : path2;
424424
return path.dirname(path1).toUpperCase() === path.dirname(path2).toUpperCase();
425425
}
426-
export async function getInterpreterDisplayName(pythonPath: string) {
426+
export async function getInterpreterVersion(pythonPath: string) {
427427
return await new Promise<string>((resolve, reject) => {
428428
child_process.execFile(pythonPath, ['--version'], (error, stdout, stdErr) => {
429429
const out = (typeof stdErr === 'string' ? stdErr : '') + os.EOL + (typeof stdout === 'string' ? stdout : '');

0 commit comments

Comments
 (0)