-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add telemetry #6
Changes from all commits
d7304ab
0b5f90f
4d93442
0742155
5c1995b
ba24f1b
b9ae68f
731d374
83c2733
9c8ab22
6d33aa7
2a53c3a
b7ee666
70c6054
c69ff4a
2275821
dfa30f7
ad3efb4
8ba7495
c62743a
27701cd
f40ce28
de928ad
92ec931
8a06e98
167c781
4b570a5
01562cb
be4f351
d62a8a2
d57d9e9
04ddb39
d141205
906e43f
d222c44
bc321de
a3cff53
f447ef8
612103f
4c160ba
50e3b65
f2a806b
d666edd
3bb4d50
164b27e
a98b80e
6d88c7b
69ea92d
a2b9292
92671f8
9e27b86
c42d9c4
b67f10b
638407e
d747a2d
b110d7e
0881e49
0fe0b42
3095f8b
e750ff7
31343c0
75ec627
bbd8915
f36a1d5
e114788
a7f3e52
21b924f
da85710
f2d31f6
74ae430
93600b7
4e923af
a89fd8e
d6241ef
f736006
78c0d19
e330ef0
5168eb2
258a381
4247d9b
bb2826e
93c6561
c653c06
e55c15e
a1b9b26
7c56f5a
ef467e2
b7100a7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
export const COMPLETION = 'COMPLETION'; | ||
export const DEFINITION = 'DEFINITION'; | ||
export const HOVER_DEFINITION = 'HOVER_DEFINITION'; | ||
export const REFERENCE = 'REFERENCE'; | ||
export const SIGNATURE = 'SIGNATURE'; | ||
export const SYMBOL = 'SYMBOL'; | ||
export const FORMAT_SORT_IMPORTS = 'FORMAT.SORT_IMPORTS'; | ||
export const FORMAT = 'FORMAT.FORMAT'; | ||
export const EDITOR_LOAD = 'EDITOR.LOAD'; | ||
export const LINTING = 'LINTING'; | ||
export const GO_TO_OBJECT_DEFINITION = 'GO_TO_OBJECT_DEFINITION'; | ||
export const UPDATE_PYSPARK_LIBRARY = 'UPDATE_PYSPARK_LIBRARY'; | ||
export const REFACTOR_RENAME = 'REFACTOR_RENAME'; | ||
export const REFACTOR_EXTRACT_VAR = 'REFACTOR_EXTRACT_VAR'; | ||
export const REFACTOR_EXTRACT_FUNCTION = 'REFACTOR_EXTRACT_FUNCTION'; | ||
export const REPL = 'REPL'; | ||
export const PYTHON_INTERPRETER = 'PYTHON_INTERPRETER'; | ||
export const WORKSPACE_SYMBOLS_BUILD = 'WORKSPACE_SYMBOLS.BUILD'; | ||
export const WORKSPACE_SYMBOLS_GO_TO = 'WORKSPACE_SYMBOLS.GO_TO'; | ||
export const EXECUTION_CODE = 'EXECUTION_CODE'; | ||
export const EXECUTION_DJANGO = 'EXECUTION_DJANGO'; | ||
export const DEBUGGER = 'DEBUGGER'; | ||
export const UNITTEST_STOP = 'UNITTEST.STOP'; | ||
export const UNITTEST_RUN = 'UNITTEST.RUN'; | ||
export const UNITTEST_DISCOVER = 'UNITTEST.DISCOVER'; | ||
export const UNITTEST_VIEW_OUTPUT = 'UNITTEST.VIEW_OUTPUT'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
import { StopWatch } from './stopWatch'; | ||
import { getTelemetryReporter } from './telemetry'; | ||
import { TelemetryProperties } from './types'; | ||
|
||
export function sendTelemetryEvent(eventName: string, durationMs?: number, properties?: TelemetryProperties) { | ||
const reporter = getTelemetryReporter(); | ||
const measures = typeof durationMs === 'number' ? { duration: durationMs } : undefined; | ||
|
||
// tslint:disable-next-line:no-any | ||
const customProperties: { [key: string]: string } = {}; | ||
if (properties) { | ||
// tslint:disable-next-line:prefer-type-cast no-any | ||
const data = properties as any; | ||
Object.getOwnPropertyNames(data).forEach(prop => { | ||
// tslint:disable-next-line:prefer-type-cast no-any no-unsafe-any | ||
(customProperties as any)[prop] = typeof data[prop] === 'string' ? data[prop] : data[prop].toString(); | ||
}); | ||
} | ||
// | ||
reporter.sendTelemetryEvent(eventName, properties ? customProperties : undefined, measures); | ||
} | ||
|
||
// tslint:disable-next-line:no-any function-name | ||
export function captureTelemetry(eventName: string) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I miss context managers from Python. |
||
// tslint:disable-next-line:no-function-expression no-any | ||
return function (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) { | ||
const originalMethod = descriptor.value; | ||
// tslint:disable-next-line:no-function-expression no-any | ||
descriptor.value = function (...args: any[]) { | ||
const stopWatch = new StopWatch(); | ||
// tslint:disable-next-line:no-invalid-this no-use-before-declare no-unsafe-any | ||
const result = originalMethod.apply(this, args); | ||
|
||
// If method being wrapped returns a promise then wait for it. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it worth having two separate functions, e.g. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think so, this is a decorator function (a decorator that can be applied to any method (sync or async). e.g. class Somethind {
@captureTelemetry()
public doSomethingSynchronously(){ }
@captureTelemetry()
public async doSomethingAsynchronously(){ }
} |
||
// tslint:disable-next-line:no-unsafe-any | ||
if (result && typeof result.then === 'function' && typeof result.catch === 'function') { | ||
// tslint:disable-next-line:prefer-type-cast | ||
(result as Promise<void>) | ||
.then(data => { | ||
sendTelemetryEvent(eventName, stopWatch.elapsedTime); | ||
return data; | ||
}) | ||
// tslint:disable-next-line:promise-function-async | ||
.catch(ex => { | ||
sendTelemetryEvent(eventName, stopWatch.elapsedTime); | ||
return Promise.reject(ex); | ||
}); | ||
} else { | ||
sendTelemetryEvent(eventName, stopWatch.elapsedTime); | ||
} | ||
|
||
return result; | ||
}; | ||
|
||
return descriptor; | ||
}; | ||
} | ||
|
||
// tslint:disable-next-line:no-any function-name | ||
export function sendTelemetryWhenDone(eventName: string, promise: Promise<any> | Thenable<any>, | ||
stopWatch?: StopWatch, properties?: TelemetryProperties) { | ||
stopWatch = stopWatch ? stopWatch : new StopWatch(); | ||
if (typeof promise.then === 'function') { | ||
// tslint:disable-next-line:prefer-type-cast no-any | ||
(promise as Promise<any>) | ||
.then(data => { | ||
// tslint:disable-next-line:no-non-null-assertion | ||
sendTelemetryEvent(eventName, stopWatch!.elapsedTime, properties); | ||
return data; | ||
// tslint:disable-next-line:promise-function-async | ||
}, ex => { | ||
// tslint:disable-next-line:no-non-null-assertion | ||
sendTelemetryEvent(eventName, stopWatch!.elapsedTime, properties); | ||
return Promise.reject(ex); | ||
}); | ||
} else { | ||
throw new Error('Method is neither a Promise nor a Theneable'); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
export class StopWatch { | ||
private started: number = Date.now(); | ||
private stopped?: number; | ||
public get elapsedTime() { | ||
return (this.stopped ? this.stopped : Date.now()) - this.started; | ||
} | ||
public stop() { | ||
this.stopped = Date.now(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
// tslint:disable-next-line:no-reference | ||
/// <reference path="./vscode-extension-telemetry.d.ts" /> | ||
import { extensions } from 'vscode'; | ||
// tslint:disable-next-line:import-name | ||
import TelemetryReporter from 'vscode-extension-telemetry'; | ||
|
||
// tslint:disable-next-line:no-any | ||
let telemetryReporter: TelemetryReporter; | ||
export function getTelemetryReporter() { | ||
if (telemetryReporter) { | ||
return telemetryReporter; | ||
} | ||
const extensionId = 'donjayamanne.python'; | ||
// tslint:disable-next-line:no-non-null-assertion | ||
const extension = extensions.getExtension(extensionId)!; | ||
// tslint:disable-next-line:no-unsafe-any | ||
const extensionVersion = extension.packageJSON.version; | ||
// tslint:disable-next-line:no-unsafe-any | ||
const aiKey = extension.packageJSON.contributes.debuggers[0].aiKey; | ||
|
||
// tslint:disable-next-line:no-unsafe-any | ||
return telemetryReporter = new TelemetryReporter(extensionId, extensionVersion, aiKey); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
export type EditorLoadTelemetry = { | ||
condaVersion: string; | ||
}; | ||
export type FormatTelemetry = { | ||
tool: 'autoppep8' | 'yapf'; | ||
hasCustomArgs: boolean; | ||
formatSelection: boolean; | ||
}; | ||
export type LintingTelemetry = { | ||
tool: 'flake8' | 'mypy' | 'pep8' | 'prospector' | 'pydocstyle' | 'pylama' | 'pylint'; | ||
hasCustomArgs: boolean; | ||
trigger: 'save' | 'auto'; | ||
executableSpecified: boolean; | ||
}; | ||
export type PythonInterpreterTelemetry = { | ||
trigger: 'ui' | 'shebang' | 'load'; | ||
failed: boolean; | ||
version: string; | ||
pipVersion: string; | ||
}; | ||
export type CodeExecutionTelemetry = { | ||
scope: 'file' | 'selection'; | ||
}; | ||
export type DebuggerTelemetry = { | ||
trigger: 'launch' | 'attach' | ||
console?: 'none' | 'integratedTerminal' | 'externalTerminal'; | ||
debugOptions?: string; | ||
pyspark?: boolean; | ||
hasEnvVars?: boolean; | ||
}; | ||
export type TestRunTelemetry = { | ||
tool: 'nosetest' | 'pytest' | 'unittest' | ||
scope: 'currentFile' | 'all' | 'file' | 'class' | 'function' | 'failed'; | ||
debugging: boolean; | ||
trigger: 'ui' | 'codelens' | 'commandpalette' | 'auto'; | ||
failed: boolean; | ||
}; | ||
export type TestDiscoverytTelemetry = { | ||
tool: 'nosetest' | 'pytest' | 'unittest' | ||
trigger: 'ui' | 'commandpalette'; | ||
failed: boolean; | ||
}; | ||
export type TelemetryProperties = FormatTelemetry | LintingTelemetry | EditorLoadTelemetry | PythonInterpreterTelemetry | CodeExecutionTelemetry | TestRunTelemetry | TestDiscoverytTelemetry; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,36 +1,26 @@ | ||
declare module "vscode-extension-telemetry" { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there really no There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nope, everyone seems to be creating their own dts for this damn thing... can't understand why. plan was to create a dts a create PR (separate piece of work) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nothing to do here. |
||
declare module 'vscode-extension-telemetry' { | ||
export default class TelemetryReporter { | ||
private extensionId; | ||
private extensionVersion; | ||
private appInsightsClient; | ||
private commonProperties; | ||
private static SQM_KEY; | ||
private static REGISTRY_USERID_VALUE; | ||
private static REGISTRY_MACHINEID_VALUE; | ||
|
||
/** | ||
* Constructs a new telemetry reporter | ||
* @param {string} extensionId All events will be prefixed with this event name | ||
* @param {string} extensionVersion Extension version to be reported with each event | ||
* @param {string} key The application insights key | ||
*/ | ||
// tslint:disable-next-line:no-empty | ||
constructor(extensionId: string, extensionVersion: string, key: string); | ||
private setupAIClient(client); | ||
private loadVSCodeCommonProperties(machineId, sessionId, version); | ||
private loadCommonProperties(); | ||
private addCommonProperties(properties); | ||
private getWinRegKeyData(key, name, hive, callback); | ||
|
||
/** | ||
* Sends a telemetry event | ||
* @param {string} eventName The event name | ||
* @param {object} properties An associative array of strings | ||
* @param {object} measures An associative array of numbers | ||
*/ | ||
sendTelemetryEvent(eventName: string, properties?: { | ||
// tslint:disable-next-line:member-access | ||
public sendTelemetryEvent(eventName: string, properties?: { | ||
[key: string]: string; | ||
}, measures?: { | ||
[key: string]: number; | ||
// tslint:disable-next-line:no-empty | ||
}): void; | ||
} | ||
} | ||
} |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason we need to worry about the unit of measure changing? E.g. should as label the data as
duration-ms
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we'll every want another unit (we can always do the math at the moment of reporting)