Skip to content

Add LSP tracing #5127

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

Merged
merged 11 commits into from
Oct 31, 2018
Merged

Add LSP tracing #5127

merged 11 commits into from
Oct 31, 2018

Conversation

abgruszecki
Copy link
Contributor

@abgruszecki abgruszecki commented Sep 19, 2018

LSP communication can now be traced remotely.

See https://github.com/lampepfl/dotty-remote-tracer for server implementation.

);
});
zip.pipe(output);
zip.glob('./**/*.{scala,sbt}', { cwd: rootPath });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this include .dotty-ide.json and .dotty-ide-artifact? We should be able to recreate them from the build definition, but they may be useful?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should include the java sources too, because they may be needed to build the project.

if (!fs.existsSync(storagePath)) fs.mkdirSync(storagePath);
const outputPath = path.join(storagePath, 'workspace-dump.zip');
if (fs.existsSync(outputPath)) fs.unlinkSync(outputPath);
let output = fs.createWriteStream(outputPath);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be a const


const localLspOutputChannel = vscode.window.createOutputChannel('Dotty LSP Communication')
try {
return this.createRemoteLspOutputChannel(remoteTracingUrl, localLspOutputChannel);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that it would be good to also add something in the status bar to show that everything is being recorded and sent

'Do you want to help EPFL develop this plugin by uploading your usage data? ' +
'PLEASE BE AWARE that this will upload all of your keystrokes and all of your code, ' +
'among other things.',
'yes', 'no'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that just saying "among other things" is scary. We should either exhaustively list what's being uploaded here or include a link to a page that exhaustively lists what's being uploaded.

Also, I would replace "all of your keystrokes" by "every action performed in Dotty IDE". Keystrokes outside of the IDE are not recorded.

@abgruszecki abgruszecki force-pushed the lsp-tracing branch 2 times, most recently from b7d6d17 to 277dd8b Compare October 12, 2018 16:41
@abgruszecki
Copy link
Contributor Author

@Duhemm fixed most of the things you mentioned. Tracing popup now directly mentions that we simply upload all LSP communication, which contains all the files and all the keystrokes. Added a statusbar item which tells the user tracing is on and allows them to adjust their consent.

There are still some outlying issues (Dotty codebase cannot be really traced, b/c the files it contains are too large; websocket connections get dropped if internet connection disappers for a second and cannot be recreated because the server does not support it; we should probably clean the LSP output channel from time to time to avoid too much trash, but do so in a way consistent with other plugins), but this was meant to work for students and it should be sufficient for them. @smarter?

@smarter
Copy link
Member

smarter commented Oct 12, 2018

Dotty codebase cannot be really traced, b/c the files it contains are too large

What's the exact issue here? Can we work around it by sending compressed files ?

@abgruszecki
Copy link
Contributor Author

@smarter I think I found a good solution. The problem starts with the fact that LSP sometimes sends entire files in one message, at least when the file is opened. This causes issues, since there's a limit on the size of a message sent through WebSocket (probably both in Play Framework and Nginx), and it may not be possible (or desireable) to completely remove it. Allowing arbitrary size messages may open the server to easy DoS, and setting a limit on the size of message will ultimately just delay the problem.

The solution would be to send messages in chunks if they are too large, and save each chunk to disk immediately after it is received. This avoid the problem of too large messages, but creates a possibility where the last line of the log on the disk is malformed (because not all chunks were sent/received). I think we can work around that limitation more easily, since it's enough to just check if the file ends in a newline.

@@ -4,10 +4,58 @@
"lockfileVersion": 1,
"requires": true,
"dependencies": {
<<<<<<< HEAD
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like conflicts haven't been properly fixed in this file?

Copy link
Member

@smarter smarter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's merge this once it's rebased

Aleksander Boruch-Gruszecki added 4 commits October 29, 2018 12:54
An item in status bar now shows tracing status and can be clicked to
adjust consent.

Tracing and workspace dump now take into account that consent can be
given/revoked - workspace dump is only initialized after consent is
given, tracing socket is only created lazily as necessary.
Remote useless info, say when starting to zip.
Note that server doesn't care if the messages are proper JSON or not.
@abgruszecki
Copy link
Contributor Author

abgruszecki commented Oct 29, 2018

Rebased, updated my local npm to a version which actually notices and uses the package-lock.json, added a setting for maximum message size. Could not get the connection to fail while opening files in Dotty repo.

Copy link
Member

@smarter smarter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: instead of "trace"/"tracing" let's call this "telemetry" since this is the term vscode and others use.

this.sessionId = new Date().toISOString()
}

run(): { lspOutputChannel?: vscode.OutputChannel } {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not run(): vscode.OutputChannel | undefined ?


private initializeAsyncWorkspaceDump() {
if (this.remoteWorkspaceDumpUrl === undefined) return
// convince TS that this is a string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can convince TS of this in a more direct way:

const url = this.remoteWorkspaceDumpUrl
if (url) {
  // ...
}

type: event.type
}))
)
vscode.window.showWarningMessage('An error occured in Dotty LSP remote tracing connection.')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather not show any messages to users if something goes wrong, it's distracting and not very useful for them. What we could do is change the status bar message to have On/Off/Failed

value: T
valueToObject: (t: T) => {}

constructor(value: T, valueToObject: (t: T) => {}) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can directly create an immutable class field and assign by writing constructor(readonly value: T, ...)

return new SafeJsonifier(e, (e) => e.toString())
}

class SafeJsonifier<T> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some documentation would be nice :)


this.tracingConsent = new TracingConsentCache(ctx.extensionContext.workspaceState)

this.remoteWorkspaceDumpUrl = this.ctx.extensionConfig.get<string>('remoteWorkspaceDumpUrl')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these should be in "tracing." like maximumMessageSize

}

private createLspOutputChannel(): vscode.OutputChannel | undefined {
if (!this.remoteTracingUrl) return undefined
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless I'm missing something, it looks like this means that we don't get any outputchannel, even a local one, when remoteTracingUrl is undefined. Suggestion: make an LspOutputChannel that extends OutputChannel and take as argument a (local) OutputChannel, then every method of LspOutputChannel just forwards to the underlying OutputChannel and also does network stuff if tracing is enabled.

@smarter smarter merged commit 2f685d2 into scala:master Oct 31, 2018
@Blaisorblade Blaisorblade deleted the lsp-tracing branch November 14, 2018 19:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants