Original link: https://www.barretlee.com/blog/2019/11/15/vscode-study-03-debug-protocol/
VS Code related series of articles, I have written three articles recently ( startup process , installation , development and debugging ), and will continue to output in the process of research and learning, hoping to bring some help to interested readers .
The style of my articles is generally to continue to dig out the underlying principles, break the casserole and ask the bottom line, and I will not stop until the depth that the public can understand. Therefore, when I make an introduction, I will occasionally talk about other related technologies. In order to pave the way for readers to understand.
Usually we often use Chrome for JS breakpoint debugging. Have you ever thought about why the program stops when I set a breakpoint? Why can breakpoints be possible without Chrome Devtool on VS Code? Behind it is How? This is what the text will take you to understand.
Debugging for Node.js
Many languages can be debugged on VS Code, just install the corresponding debugging package. This article takes Node.js as an example. Readers can follow the gourd and try to debug other languages. The principle is clear, and the rest is physical strength live.
First, let’s take a look at how Node.js is debugged. In fact, this blog has introduced it many times, and this time we will discuss it in more depth.
Connect Node.js Debugger
In Node.js before version 6.3, the debugging tool is relatively simple, and the debugging tool that is more active in the community is called node-inspector
. What is the principle of this thing, why can it be debugged, we can achieve it with a few simple lines of code A node-inspector
with a single function, as shown below is the code to be debugged:
// file: test.js |
Through node --debug test.js
startup program, we started an HTTP Server on port 8888.
Here, please use nvm to switch the version number of node to below 6.3, such as
v6.2.2
version. The difference between the old version of Node and the v6.3+ version of Node will be discussed later.
Then initiate a request as follows:
➜ curl 127.0.0.1:8888 |
You will see that the command line only outputs hello\n
, and then enters the pending state. Let’s understand step by step why this is the case:
- Start Node.js with the
--debug
parameter, and the program will open a built-inDebugger
module - Since we did not specify a parameter,
--debug=PORT
, the default port is 5858, and theDebugger
module will listen to port 5858 - When a request is made, if
debugger
keyword is encountered, the program will suspend execution until it receives the “continue to the next step” instruction
Demo source address: barrel/node-legacy-debug
We can write a program to see what the Debugger
module does:
// File: debugClient.js |
We use the Net
module to connect to the monitor that the program opened on port 5858 just now. When it is connected, it will print the following information:
Type : connect |
It means to tell you that you tried to connect to the Debugger module, and the connection has been successful. The V8 version number used by the current debug program is 5.0.71.52
, the protocol version used is 1
, and the Node version number is v6.2.2
. This information In fact, it is telling you what protocol to use to communicate with the debugger. The protocol used in the v6.2.2
version is V8 Debugger Protocol .
In order to print comprehensive information, pay attention to the sequence of operations, first use the debug module to start the program test.js, then start debugClient.js, and finally execute curl to initiate a request.
When curl initiates a request, Debugger will send a message to debugClient:
Content-Length : 283 |
Didn’t curl
just now enter pending? Let’s try to send a command to the Debugger (refer to the protocol content ) to tell it to enter the next breakpoint. The content is:
{ "seq" : 1 , "type" : "request" , "command" : "continue" } |
In debugClient, we monitor process.stdin
, so you can directly paste the above content into the command line and press Enter, and you will also see the feedback sent by Debugger:
{ "seq" : 1 , "request_seq" : 1 , "type" : "response" , "command" : "continue" , "success" : true , "running" : true } |
Tell you that you have successfully entered the next breakpoint. At this time, you will also see that curl has output world
.
In the above program, you can enter other commands on the command line, such as querying the value of the url of req during pause:
{ "seq" : 2 , "type" : "request" , "command" : "evaluate" , "arguments" : { "expression" : "req.url" } } |
You will receive a response like this:
Content-Length : 177 |
Have you ever seen the picture of debugging Node.js in your mind? That’s right, that’s how it works.
node-inspector, the debugging agent
The debugging principle has probably been figured out, but I believe that few people are willing to debug the program through the above method, because it is too troublesome, not only to know the names of various instructions, but also to know the parameters of the instructions and the specifications of the protocol , sequence count, etc., so there is node-inspector
, which can help us debug Node.js programs visually on Chrome Devtool, so what does it do?
+-----------------+ |
To put it simply, node inspector
establishes a channel with Chrome Devtool through Chrome’s Remote Debugging Protocol
, and then establishes a connection with the Debugger
module of the program through V8 Debugging Protocol
, so that developers can implement Node.js through visual operations on Chrome. Debugging, so I call it “debugging proxy”, which is a protocol transit service.
Since node-inspector
greatly improves the debugging experience of Node, in v6.3, Node.js officials directly integrated this capability into it. You will see that when debugging the program in Node.js using v6.3+, it will print a websocket link adapted to the CRDP protocol:
➜ node --inspect test.js |
We can directly configure this address on Chrome Devtool to enter visual debugging, so the whole link becomes:
+------------------+ +---------------+ |
Without the access of debugging agent, it will be much easier for developers to use, and the CRDP specification is very frequently used in the community, and there are many codes for reference in the implementation.
Speaking of this, if we want to implement a visual debugging interface by ourselves, is it a bit clear:
+-----------------+ +----------------+ |
You only need to implement Debug Client
part in the figure below, and the linkage between Debug Client
and the view of the IDE, and you can realize customized visual debugging.
If your requirement is to customize the visual debugging of Node.js, this article can end here. I believe that you are fully capable of implementing a debugging interface with the knowledge learned above. But in VS Code, we need to expand more space.
Debug Adapter Protocol
The cost of implementing a Debug Client is actually quite high. You need to thoroughly understand all debugging protocols, such as the V8 Debugging Protocol, which contains dozens of instructions, and each instruction needs to be adapted for communication and UI. This is just a language , if your IDE is oriented to multiple languages, you need to adapt to multiple debugging protocols. The differences between different protocols may be quite large, and these tasks will completely crash you.
In addition, from the perspective of the community, this kind of construction can be abstracted. Just imagine, Atom needs to implement a Debug Client to debug Node. It is not necessary, so there is Debug Adaptor Protocol
, which is a set of general debugging protocols proposed by Microsoft, which has become the de facto standard in the community.
So which layer is this DAP in debugging? We can look at this graph ( source ):
You can debug all languages by implementing only one communication and UI adaptation to the DAP protocol on the IDE. All you need to do is:
- Does the community have a DAP implementation of the target language? If so, use it directly, so that it can be quickly adapted and debugged
- If not, use the knowledge we have learned above to implement a DA and contribute to the community
This set of protocols regulates 5 pieces of content:
-
Base Protocol
, which describes the communication format of requests, responses, events, errors, etc. -
Events
, describing more than a dozen event standards such as initialization, configuration completion, output, breakpoint, stop, etc. -
Request
, which describes the request format of various instructions for debugging -
Response
, describes the response format of various commands for debugging -
Types
, describing the types and interface descriptions involved in the above various contents
In principle, all the content mentioned in the specification needs to be implemented in DA. Even if the underlying engine of the language does not have this capability, an error should be thrown to ensure consistency.
Implement a Node.js debugger
In order to understand the several protocols mentioned above, I wrote a DEMO by hand, and realized the simplest operation: display the stack information of the current Debug, as shown in the following figure:
The warehouse address is: barrellee/node-debug
You can download it and run it, and start it after downloading the dependencies:
npm run init; |
The completion of this demo is very low, and the key links are Mock, just to help myself understand the whole process. After understanding, I will not continue to improve the details. Interested students can study it.
I didn’t implement a complete Node.js Debug Adapter by myself, not because of the complexity, so I directly researched VS Code and open sourced two Adaptors, which are:
- vscode-node-debug , this is the implementation of versions below v6.3
- vscode-node-debug2 , this is the implementation of v6.3 and above
Choose which version to use based on Embedding-Host
information returned when connecting. VS Code seems to install these two packages by default. The overall idea is the same as what I mentioned above.
The specific implementation of VS Code
There are two ways to debug a program, one is to debug a program that has been started, and the other is to debug a program that has not been started. The former VS Code will directly attach
it, and the latter will first fork a process launch
program. Here we only briefly introduce VS Code Several knowledge points in the actual operation process:
There is no debug parameter when the program starts
If the Node.js program does not start with --debug
or --inspect
parameter, the Debugger module of Node.js will not be started by default. In this case, it is not impossible to debug. We can start it manually Debug module:
# Find the PID of the corresponding Node.js process |
stopOnEntry
When forking a Node.js process for debugging, there are two types of input parameters:
-
--debug
and--inspect
, the default execution program -
--debug-brk
and--inspect-brk
, breakpoint directly on the first line by default
Generally speaking, we will choose the first method. If your program will be executed directly and the speed is very fast, you can consider the second method for debugging.
How VS Code connects to the Node.js debugging process
The core content of the Debug Adapter for VS Code debugging Node.js is in the vscode-chrome-debug-core package, which is actually a specific implementation of the Chrome Remote Debugging Protocol, with a lot of internal logic, which seems a bit difficult.
summary
Well, I will write here first, and there are still many details that I will not describe one by one. It is of little value. I have done a lot of preliminary work in writing this article. I have studied DAP and Node.js Debugger for several nights, but Finally, I understand it better. If you have any questions during the test, please leave a message below .
This article is transferred from: https://www.barretlee.com/blog/2019/11/15/vscode-study-03-debug-protocol/
This site is only for collection, and the copyright belongs to the original author.