Preface
Q: How to debug Node?
A: What is debugging?
Generally, when we say "debugging", we mean stepping over, stepping into, stepping out, executing line by line while watching the source code. In this case, debugging server-side programs is no different from general client-side programs, both want to peek into execution flow, call stack, current variable values, etc. In other words, debugging Node services is the same as debugging JS scripts in pages
Of course, server-side has its particularities, much code is closely related to client environment, such as Cookie, Request Header, localStorage, etc. Wanting to debug line by line seems unrealistic. First, where does the service input (client requests) come from? You can simulate requests, or directly simulate data... Going further is actually testing content, not "debugging"
1. Debugger
Node has built-in breakpoint debugging, that is the debugger statement, as follows:
// console.js
debugger;
var value = 1;
var fn1 = function() {
debugger;
value = '2';
console.log('fn1');
};
var fn2 = function() {
debugger;
value = 3;
fn1();
console.log('fn2');
};
console.log(1);
process.nextTick(function () {
debugger;
value = 4;
fn2();
console.log(2);
});
console.log(3);
Where debugger; means setting a breakpoint, asynchronous execution flow will also be interrupted by breakpoints. Of course, debugger only works in debugging environment, enter debug mode through command line:
node debug ./console.js
// For services already running, sending SIGUSR1 signal to its process can enter debug mode
// kill -s USR1 [pid]
Then you can see prompt messages and debug interaction prompts:
< Debugger listening on port 5858
debug> . ok
break in E:\node\learn\debug\console.js:1
> 1 debugger;
2
3 var value = 1;
debug>
Execution flow stops at the first line's debugger;, cursor jumps waiting for debug command input. Node doesn't provide complete support for V8 debugging commands, available commands are as follows:
1. Control Execution Flow
-
c/cont
Continue execution to next breakpoint
-
n/next
Execute to next line
-
s/step
Step into function
-
o/out
Step out from function
-
pause
Pause execution
For example, inputting c will output 1 and 3, then stop at the line above value = 4;. Inputting n again will stop at value = 4;, then inputting n then s enters fn2's function body, stopping at the first line of function body...
Note: Debug commands are not very friendly, if program execution is complete, inputting c again requires killing the process to end debugging
2. Set/Clear Breakpoints
-
sb()/setBreakpoint()
Set breakpoint at current line
-
sb(line)/...
Set breakpoint at line line
-
sb('fn()')/...
Set breakpoint at beginning of function body
-
sb('script.js', 1)/...
Set breakpoint at first line of script.js file
-
cb()/clearBeakpoint()
Clear breakpoint
Note: These commands are very inconvenient to use, suggest using debugger; statement in source code to set breakpoints
3. View Status Information
-
bt/backtrace
Output current stack information
-
list(3)
List 3 lines of source code before and after current
-
watch('expr')
Add expr to watch list
-
unwatch('expr')
Remove expr from watch list
-
watchers
List all expressions and values in watch list
-
repl
Open debugging context, directly input debug code
These commands are quite useful, watch frequently changing variables/expressions, or directly repl into debugging environment within debugging environment, can output anything
2. Debugging Tools
Manually inputting commands is troublesome, so there are debugging tools: node-inspector, npm global install, then run directly:
E:\node\learn\debug>node-inspector
Node Inspector v0.12.7
Visit http://127.0.0.1:8080/?port=5858 to start debugging.
Cannot send response - there is no front-end connection.
Browser (browser must have Blink Developer Tools, such as Chrome and Opera, while FF45 doesn't work) visit http://127.0.0.1:8080/?port=5858, nothing there, wait, last line says can't find what to debug, okay, let's run program and enter debug mode:
node debug ./console.js
// Of course, sending SIGUSR1 signal to process also works
// kill -s USR1 [pid]
Then refresh browser, page shows source code, and displays familiar Dev Tools:
(function (exports, require, module, __filename, __dirname) { debugger;
var value = 1;
var fn1 = function() {
debugger;
value = '2';
console.log('fn1');
};
var fn2 = function() {
debugger;
value = 3;
fn1();
console.log('fn2');
};
console.log(1);
process.nextTick(function () {
debugger;
value = 4;
fn2();
console.log(2);
});
console.log(3);
});
Find code is wrapped by module, so debugging has an advantage of being able to peek into node source code, want to trace back to source, infinite step into can pull out entire execution flow. Similarly, can conveniently view specific execution flow inside third-party modules, useful when analyzing source code
P.S. Running node-inspector first here is to explain order doesn't matter, don't need to strictly debug execute program to be debugged first every time, principle is node provides TCP debugging protocol, through protocol can debug from outside process, node-inspector communicates with process to be debugged through this protocol, executes debugger commands, and displays through Blink Developer Tools interface
3. Summary
Actually whether using commands or tools, feels quite troublesome, and, why need debugging?
Reasons, I can only think of 2 situations:
- Code is messed up (strange errors occurred, can't find error cause through static analysis alone)
Can't figure out execution flow, need to sort it out
- Want to analyze source code
Weakly typed JS has no way to go to definition, analyzing source code through debugging is a good choice
Debugging causes execution interruption, must be done offline. In development, situations needing to watch line by line are extremely rare, should ensure code robustness through unit testing, not debugging as soon as there's a problem
For server-side programs, besides unit testing (mocha, should, muk, rewire, content is quite extensive, we'll discuss later), logging (pm2 comes with simple error logging) is also very necessary. Lock error cause through log analysis, then find corresponding unit test cases, and fix
Reference Materials
- "Dive Into NodeJS"
No comments yet. Be the first to share your thoughts.