Skip to content
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

Figure out why EH debugging doesn't work in Live Share #56471

Closed
weinand opened this issue Aug 15, 2018 · 19 comments
Closed

Figure out why EH debugging doesn't work in Live Share #56471

weinand opened this issue Aug 15, 2018 · 19 comments
Assignees
Labels
debt Code quality issues debug Debug viewlet, configurations, breakpoints, adapter issues verified Verification succeeded
Milestone

Comments

@weinand
Copy link
Contributor

weinand commented Aug 15, 2018

Currently EH Debugging is not supported in Live Share.

With this issue we want to figure out what are the obstacles and how to address them.

@weinand weinand added feature-request Request for new features or functionality debug Debug viewlet, configurations, breakpoints, adapter issues labels Aug 15, 2018
@weinand weinand added this to the August 2018 milestone Aug 15, 2018
@weinand weinand self-assigned this Aug 15, 2018
@weinand
Copy link
Contributor Author

weinand commented Aug 15, 2018

EH debugging uses a debugger of type "extensionHost", but this debugger is almost identically to the node debugger and has only a few lines of code where its behaviour differs.

EH debugging is based on the "attach" setup available for node.js debugging:

  • VS Code creates a new workspace window and configures the associated extension host process to listen on a specific debug port,
  • node-debug attaches to the debug port and the debug session is started,
  • if the EH terminates, the debug session ends,

Instead of using the "extensionHost" debugger for this, it is possible to use a regular "node" debugger. In this case the launch of the VS Code workspace window and EH process must be done manually and a debug configuration of type "attach" could be used to attach to the EH.

The reason why we've introduced a new debug type "extensionHost" is because we want to support some typical EH debugging workflows automatically and we use the debug type as a discriminator.

One typical EH debugging workflow is the EH restart which frequently occurs when opening a new project or when the "Reload Window" action is run. When a reload happens VS Code broadcasts a "reattach" event which is picked up by VS Code debugger UI to terminate the debug session with the old EH and attach to a new extension host process (with a different debug port).

Here is a minimal debug configuration for EH debugging:

        {
            "name": "Launch Extension",
            "type": "extensionHost",
            "request": "launch",
            "runtimeExecutable": "${execPath}",
            "args": [
                "--extensionDevelopmentPath=${workspaceRoot}",
            ]
        },

Since VS Code controls the lifecycle of the EH, the node.js process is not directly launched from the debug adapter and hence it is not specified in the launch configuration. Instead we use the VS Code executable itself (available in the variable ${execPath}) to create a new workspace window and launch the node.js used for the extension host process in debug mode.

As arguments only a path to the extension workspace is given but additional arguments are passed behind the scenes from the debug adapter. The debug console shows what gets executed:

/Applications/Visual Studio Code - Insiders.app/Contents/MacOS/Electron --debugBrkPluginHost=41138 --debugId=bc1b9edd-3346-4fdf-8296-f727e82a23f5 --extensionDevelopmentPath=/Users/weinand/MS/Projects/Scenarios/extensions/hello-ext-ts

The --debugBrkPluginHost=41138 asks VS Code to start the EH process in debug mode on the given port and --debugId=bc1b9edd-3346-4fdf-8296-f727e82a23f5 asks VS Code to augment all broadcast events with the given ID so that the VS Code debugger is able to find the associated debug session.

We are passing these arguments behind the scenes because we do not want to leak these implementation details into debug configurations (which avoids data migration issues later).


From my perspective I cannot spot anything that might result in a problem in the LiveShare setup.

@rodrigovaras do you see anything problematic?

@rodrigovaras
Copy link
Contributor

Thanks Andre for the detailed explanation on how the extension host debugging works.
I did experiment a little bit and test with the launch options you mention by spying vscode.
I did use the same launch options from vscode and use a command prompt to execute it. What i observe is a new vsocde window being created and then my first vscode magically attaching to it. How does vscode discover it?
I notice its probably related with the --debugId option? If i change it another value then vscode does not auto attach.

If i understood you correctly should my adapter attempt to launch vscode with the --extensionDevelopmentPath and then at the same time launch the node adapter with something like this:
{
"type": "node",
"request": "attach",
"name": "Attach by Inspector",
"protocol": "inspector",
"port": {myPort}
},

A couple of questions:

  • What port is safe to use, how vscode figure out something not being used?
  • What should i pass on the --debugId option, should we generate a new guid ?

@weinand
Copy link
Contributor Author

weinand commented Aug 16, 2018

I think the important thing to understand is that the "node-debug2" DA is registered under two different names: "node" and "extensionHost".

"node" is used to launch node.js programs and "extensionHost" is used to launch node.js as an extension host in the context of VS Code. So the launching of the debuggees (either plain node.js or VS Code's node.js) is implemented in the DA "node-debug2". There is no need for you to do anything special (like writing any launching code).

The "node-debug2" DA will find a free port and pass this to either node.js or VS Code as the debug port to use. And since the DA knows the debug port it will be able to attach to it for debugging.

A small difference is the additional "debugId" argument. The debug ID is a session ID that the VS Code debug UI creates for a debug session. VS Code passes it as an (undocumented) attribute "__sessionId" on the arguments of the DAP "launch" request and the "extensionHost" debug adapter adds it to the arguments passed to vscode debuggee. But LiveShare should not have to deal with this in any way because VS Code passes the sessionID and the DA picks it up.

To emphasize how similar node.js and EH debugging are, here are the steps done in the "node-debug2" DA:

for debug type "node":

DA was launched by VS Code
DAP "launch" request received (with a "program" attribute having the value "program.js")
if no port provided DA picks free port
DA launches "node --inspect=12345 program.js"
DA attaches to debug port 12345
... DA processes DAP requests ....
DA terminates node.js

for debug type "extensionHost":

DA was launched by VS Code
DAP "launch" request received (which includes the "__sessionId" attribute)
if no port provided DA picks free port
DA launches "vsode --debugBrkPluginHost=12345 --extensionDevelopmentPath=..."
DA attaches to debug port 12345
... DA processes DAP requests ....
DA terminates node.js (which takes down the enclosing vscode window).

As you can see there is no big difference between regular node.js debugging and extension host debugging (which is the reason why "node" and "extensionHost" share the same implementation).

However, from a LiveShare perspective there might be catch:

The EH node.js is running in a new VS Code workbench window which is independent from the project in which the debugger is running. For LiveShare this probably means that the new VS Code instance is not automatically shared with other LiveShare parties (but I'm not sure about this).

Basically this is the same as opening a new workspace window from a LiveShare shared VS Code project. Is the new project window automatically shared via LiveShare? If not, then the EH window will not be either.

@rodrigovaras
Copy link
Contributor

Can you point me to the code of the DA (node2) that does the launch, etc..
Also here is the big difference to understand, from the point of view of vscode the debug adapter being launched is live share, not the 'extensionHost' (we do this when we hook up to the resolveDebugConfiguration provider) and so the there will be no '__sessionId'. We could attempt to 'inject' this additional parameters on our DA code but we need to understand what exactly has to be passed in order to enable this scenario.

@weinand
Copy link
Contributor Author

weinand commented Aug 16, 2018

The launch code is here: https://github.com/Microsoft/vscode-node-debug2/blob/ed7e076778a09e1445e7e883e6f20369f7759a71/src/nodeDebugAdapter.ts#L231-L262
But this is really an implementation detail of our debug extension that LiveShare should not need to know (and we are changing it frequently).

The "liveShare" DA is basically a transparent proxy for any DA including the "extensionHost" DA. Any additional argument passed from the user's launch configuration via the DAP "launch" request to the final DA must be tunnelled through the "liveShare" DA transparently, because a user is free to add additional arguments to its launch config and they must arrive at the DA intact. The "__sessionID" is just one additional attribute that VS Code adds. So you should not need to know the potential arguments but you should pass everything unmodified.

@weinand
Copy link
Contributor Author

weinand commented Aug 16, 2018

A more direct response to your previous question:

If i understood you correctly should my adapter attempt to launch vscode with the --extensionDevelopmentPath and then at the same time launch the node adapter with something like this...

no, your adapter should just forward all DAP requests to whatever target DA you are proxying to.
The target DA will launch VS Code which then configures the node.js process within it correctly for EH debugging.

@rodrigovaras
Copy link
Contributor

Understood.
Before i was pointing that my investigation and test of separate launching manually vscode with the proper arguments and then use a regular node debugging 'attach' seems to work for me.

FYI, our node debugging proxy works, we are capable to launch from our code the node debug adapter by using the 'fork' technique we mimic.
What we are investigating is why this doe NOT work for extensionHost type, there is a tiny detail that is missing.
Any way we can enable some sort of DPA protocol spying pn both the node DA and vscode itself?

We are trying to figure out why the extension host debugging is not working when live share attempt to proxy.

@weinand
Copy link
Contributor Author

weinand commented Aug 16, 2018

  • when proxying the extensionHost DA, does the launch of VS Code succeed and you get a new window? Please note that the VS Code launched by the EH DA is just a short living stub that connects to the already running VS Code and asks it to create a new workspace window in debug mode.
  • how exactly does EH debugging fail?
  • you can enable tracing by setting the "trace" attribute to true in the EH launch config (see https://code.visualstudio.com/docs/nodejs/nodejs-debugging#_launch-configuration-attributes). The loacation of the log file appears in the debug console:
    2018-08-16_19-16-55

@weinand
Copy link
Contributor Author

weinand commented Aug 16, 2018

I did some more debugging of the EH debugging and saw one additional detail which might be the reason for the problem you are seeing:

Launching of VS Code and attaching the debugger to it are done with two subsequent EH-DAs!

First VS Code starts an EH-DA and then sends a "launch" request to it.
The "launch" request launches another instance of VS Code which will create the EH node.js process in debug mode and announces this by broadcasting an "attach" event. After that the EH-DA terminates.

Then the VS Code debugger of the first VS Code instance picks up the "attach" event, extracts the port number from it and starts another EH DA for attaching to the received port of the EH process. This (second) EH DA will be used for the course of the debug session.

When the EH process needs to be restarted (which is frequently required for specific operations like opening a new folder), VS Code starts a new EH process, terminates the old EH process, and sends again the "attach" broadcast (which will be picked up again by the VS Code debugger and result in a new EH-DA).

@rodrigovaras
Copy link
Contributor

So, is more complex than i thought, and also multiple steps can fail.
I did more research and find a problem on our side when we proxy the 'launch' request we were not passing the '__sesionId' property. I did fix it and now it goes further.

What i observe now is that a new vscode window is being created and also i notice the '[Extension Host Development]' title;
From the vscode console i see this:
C:\Program Files\Microsoft VS Code Insiders\Code - Insiders.exe --debugBrkPluginHost=8891 --debugId=4ec8fd0e-a85c-4c2a-858e-18eb3fbedc30 --extensionDevelopmentPath=E:\github\vscode-mock-debug

So it seems right at first glance.
I see later the debug toolbar to appear for a while, but then the debugged vscode window is being refreshed and repeated for ever.
It looks like vscode did not proper recognize the expected 'attach' you mention before.

Also i notice our vscode.DebugConfigurationProvider interface is being called multiple times.

@weinand
Copy link
Contributor Author

weinand commented Aug 16, 2018

If the LiveShare-DA does not automatically pass all unknown attributes to the target DA, then please make sure that a "restart": true attribute is correctly passed to the "Disconnect" request.
This attribute is proposed but not yet in the spec.

@rodrigovaras
Copy link
Contributor

Andre,
I did a couple of other things that could affect the extension host debugging on our side, mostly passing some properties and correcting the attach/launch request.
This time the debugging session goes much further and i can see our debug host adapter log with around 70k of data (attached..please take a look).
20180816_232011_Debug.HostAdapter.log

I do see now a 'terminated' event coming from the node (the second one that attach through the port), it looks that it could not find a module, i suspect some working directories or env variables are not properly setup during our fork.

Also i never found a restart: true option.
Here is the log from the vscode window:
C:\Program Files\Microsoft VS Code Insiders\Code - Insiders.exe --debugBrkPluginHost=4313 --debugId=f7b63582-afe2-4aec-8ea2-ea0d8c5fa538 --extensionDevelopmentPath=E:\github\vscode-mock-debug
Object
errorCode:"load"
moduleId:"iconv-lite"
neededBy:Array[1]
detail:Object
Object
errorCode:"load"
moduleId:"node-pty"
neededBy:Array[1]
detail:Object

@weinand
Copy link
Contributor Author

weinand commented Aug 17, 2018

I'm currently looking into the log.

two comments:

  • It would be great if you could provide the node-debug2 trace as well. Yes, it is included in the *.log as well but I want to compare it with a trace from a non-LiveShare setup.

  • Instead of using the "mock-debug" extension as sample I suggest to use a simple "hello world" extension. When using "mock-debug" the word "debug" appears in many places in the logs and traces and it is confusing because of the other debug adapters that are involved.
    Creating an up-to-date "hello world" extension is simple: https://code.visualstudio.com/docs/extensions/example-hello-world#_generate-a-new-extension
    just run this:

    npm install -g yo generator-code
    yo code
    

@rodrigovaras
Copy link
Contributor

rodrigovaras commented Aug 17, 2018 via email

@rodrigovaras
Copy link
Contributor

Here is a run with a simplified 'hello-world' extension and now the 2 host adapter logs. The first one is shorter and it seems to launch the vscode EH, the second one is the attach. Please notice the first host adapter debug adapter is still alive and running, the second one get terminated abruptly with the java script runtime error. I suspect the EH vscode launch is missing some options to cause the java script engine to miss some other dependent modules to be found.
Please note the more details log i see on the vscode console window:
C:\Program Files\Microsoft VS Code Insiders\Code - Insiders.exe --debugBrkPluginHost=34844 --debugId=4a223fb0-509d-46b9-9e74-1f9803b86902 --extensionDevelopmentPath=C:\Users\rodrigov\source\repos\hello-world-extension
Object
errorCode:"load"
moduleId:"iconv-lite"
neededBy:Array[1]
0:"vs/base/node/encoding"
detail:Object
code:"MODULE_NOT_FOUND"
Object
errorCode:"load"
moduleId:"node-pty"
neededBy:Array[1]
0:"vs/workbench/parts/terminal/node/terminalProcess"
detail:Object
code:"MODULE_NOT_FOUND"
20180817_154943_Debug.HostAdapter.log
20180817_154939_Debug.HostAdapter.log

@rodrigovaras
Copy link
Contributor

Hi Andre,
The miracle happen, the live share debug adapter can co-debug vscode extension. I did battle for another day and found a couple of issues that i correct but in general things looks good, thanks for all your help.
I did find one thing that needs to be corrected on the vscode side, apparently sometimes vscode shows the debugged sessions as 'attached' instead 'launched', i suspect is related to part of the code assuming the type is 'extensionHost' (which is not on our case), so it has to check if type === 'vslsShare' and then check the underlying type to be 'extensionHost'.

I will be OOF for 2 weeks, when i come back i will mention another issue i found that is not fully related to this problem but will be important to fix.

@weinand
Copy link
Contributor Author

weinand commented Aug 18, 2018

Hi Rodrigo, great to hear that you managed to get EH debugging work under LiveShare.

I've looked into the issue that VS Code sometimes relies on the debug type 'extensionHost'.
We have three places where the debugger's logic makes use of the extensionHost debug type (and fails for LiveShare).

Ideally we should try to eliminate them. @isidorn we should brainstorm how we could do this.

In general I see three ways to address this:

  • we could check for both extensionHost and vslsShare (not a real fix but just a workaround),
  • propagate the target debug type extensionHost through the 'vslsShare' DA so that VS Code always sees the "real" DA and not the wrapping vslsShare DA. We could extend the DAP for this.
  • Instead of wrapping DAs we could support the "spy protocol" approach. I'm currently exploring this in Explore API for injecting a middle-man into DAP communication #55945.

@rodrigovaras
Copy link
Contributor

rodrigovaras commented Aug 18, 2018 via email

@weinand weinand added debt Code quality issues and removed feature-request Request for new features or functionality labels Aug 27, 2018
@weinand
Copy link
Contributor Author

weinand commented Aug 27, 2018

the identified issues will be addressed in the upcoming milestones.

Since there is nothing to verify in August, I've added the "verified" label.

@weinand weinand closed this as completed Aug 27, 2018
@weinand weinand added the verified Verification succeeded label Aug 27, 2018
@vscodebot vscodebot bot locked and limited conversation to collaborators Oct 11, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
debt Code quality issues debug Debug viewlet, configurations, breakpoints, adapter issues verified Verification succeeded
Projects
None yet
Development

No branches or pull requests

2 participants