-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Add telemetry for Language Server download, extraction, and analysis (startup) time. #2593
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
Conversation
- Simple fix to add telemetry in the existing manner - Testing will have to be done a different way
- versus hard-coding the string in multiple places.
- Move telemetry into the languageServer class and out of downloader. - Add telemetry properties. - Add telemetry for languageServer startup time.
- last change introduced a bug to do with async/await order - moved sendTelemetryWhenDone up a level to compensate
- Telemetry will show success/fail on the analysis time this way. - Alphabetize PYTHON_LANGUAGE_SERVER_... constants
throw new Error(err); | ||
try { | ||
await this.downloadFile(downloadUri, 'Downloading Microsoft Python Language Server... ') | ||
.then((tmpFilePath: string) => { |
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.
You don't need the .then
. Just use the await, and next line initialize stats.
I.e. you can revert the change.
timer.reset(); | ||
try { | ||
await this.unpackArchive(context.extensionPath, localTempFilePath) | ||
.then(() => { |
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.
no need of .then
.
Just initialize the stats
immediately after await
line
@@ -57,6 +57,20 @@ export type DebuggerPerformanceTelemetry = { | |||
duration: number; | |||
action: 'stepIn' | 'stepOut' | 'continue' | 'next' | 'launch'; | |||
}; | |||
export type LanguageServerInstallTelemetry = { | |||
downloadSuccess: boolean; |
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.
all of these properties should be nullable.
Default values cannot be false. Cuz its misleading to have downloadSuccess = false and extractSuccess = false. Cuz if download fails, then extraction was never attempted. Hence it should not be false, else we end up with skewed data.
public async downloadLanguageServer(context: IExtensionContext): Promise<void> { | ||
public async downloadLanguageServer(context: IExtensionContext): Promise<LanguageServerInstallTelemetry> { | ||
const stats: LanguageServerInstallTelemetry = { | ||
downloadMs: -1, |
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.
Please remove the time = -1
.
Default should be undefined
@@ -41,22 +43,48 @@ export class LanguageServerDownloader { | |||
return DownloadLinks[platformString]; | |||
} | |||
|
|||
public async downloadLanguageServer(context: IExtensionContext): Promise<void> { | |||
public async downloadLanguageServer(context: IExtensionContext): Promise<LanguageServerInstallTelemetry> { |
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.
You should be able to revert the changes to this method and use captureTelemetry
decorator in telemetry/index.ts
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.
All you'll need to do is add the decorator the to downloadFile
and unpackArchieve
methods.
You might want to tweak the captureTelemetry
function to capture failures (minor tweak).
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.
With that you'll be able to reduce the changes to the code, with the power of decorators :)
}; | ||
sendTelemetryWhenDone( | ||
PYTHON_LANGUAGE_SERVER_STARTUP, | ||
this.startLanguageClient() |
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.
Again, you should be able to use the decorator here.
Please note, you cannot just send the entire error object via telemetry.
We need to be aware of GDPR, sending error object could contain stack traces, that could contain PII (user name, etc).
|
||
export class ProgressReporting { | ||
private statusBarMessage: Disposable | undefined; | ||
private progress: Progress<{ message?: string; increment?: number }> | undefined; | ||
private progressDeferred: Deferred<void> | undefined; | ||
private progressTimer: StopWatch | undefined; |
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.
Or a more simpler way is private progressTimer?: StopWatch;
No changes necessary here, just letting you know there's a shorter syntax for nullable.
this.progressTimer = new StopWatch(); | ||
this.progressTimeout = setTimeout( | ||
// tslint:disable-next-line:no-any | ||
(...args: any[]) => { |
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.
please change to argumentless anonymous func as follows:
this.progressTimeout = setTimeout(()=> {
...
});
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.e. you do not need (...args: any[]) = >
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.
Can we move this callback into a separate function, e.g.
this.progressTimeOut = setTimeout(()=> this.handleProgressTimeout());
@@ -6,6 +6,8 @@ export const PYTHON = [ | |||
{ scheme: 'untitled', language: PYTHON_LANGUAGE } | |||
]; | |||
|
|||
export const PVSC_EXTENSION_ID = 'ms-python.python'; |
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.
👍
Fixes microsoft#2461 (alternate fix to PR microsoft#2593) - Capture telemetry surrounds methods, minimizing change - Telemetry type can be altered with less code later. - Add success/fail props modifyer func to `captureTelemetry`
Closing in favour of #2597. |
Fixes microsoft#2461 (alternate fix to PR microsoft#2593) - Capture telemetry surrounds methods, minimizing change - Telemetry type can be altered with less code later. - Add success/fail props modifyer func to `captureTelemetry`
Completes #2461
Note: I had to add telemetry to the ProgressReporting class to figure out when the LS reports that it is completed the analysis for the workspace. If there is a better way for me to do this, let me know! I believe that once the analysis reporting that the LS is doing today is fixed up, the two telemetry measurements I am sending (
PYTHON_LANGUAGE_SERVER_ANALYSISTIME
andPYTHON_LANGUAGE_SERVER_STARTUP
) should be pretty much equal.Pull request represents a single change (i.e. not fixing disparate/unrelated things in a single PR)
Title summarizes what is changing
Has a news entry file (remember to thank yourself!)
Has unit tests & system/integration tests(Telemetry isn't really testable yet)Any new/changed dependencies inpackage.json
are pinned (e.g."1.2.3"
, not"^1.2.3"
for the specified version)package-lock.json
has been regenerated by runningnpm install
(if dependencies have changed)Remove
.then
from await code that was altered in my prior change and not updated with a later change.Change from default values for download/extract being
false
to beingundefined
and nullable.Change the download/extract time records to defaulting to
undefined
instead of-1
.Investigate (and use) decorators over return values in the capturing of the downloader telemetry.
Do not send error messages into telemetry without sanitizing them first (or just sending a meaningful telemetry string for the failure that avoids PII issues).
Don't bother giving argument lists to anonymous functions that never make use of those arguments.
Create a separate method to deal with the analysis time measurement instead of just duplicating code in anonymous functions.