How to inspect running Node.js processes

Using the Node.js inspector

In this article I will quickly describe how I analyzed memory usage, mostly for my own future reference.

1. trigger debugger

Node.js has a functionality to start a debugger, which is available through websockets. To start the debugger on a process that is already running, without being prepared, you can just send the respective process a signal USR1 and Node.js will start the debugger.

kill -USR1 <pid>

After this you have to check the stderr output of the respective process, usually that should be forwarded to some kind of log. The message you are looking for should look something like this:

Debugger listening on ws://127.0.0.1:9229/900ebfb3-dd7b-448f-8aac-7b50d4fd7e7e

Of course, the UUID will probably be different. What is most important in this case is the port number the debugger is listening on. In this case, as is the default, the debugger is listening on port 9229. If you can't find this message, you can try just listening on that port anyway.

2. forward port

Usually the process from above will be running on a server that you are not directly working on and/or do not have a graphical interface on. In this case it will be easier if you have some debugger client running on a local machine.

The Node.js debugger will be listening only on the localhost IP address for safety reasons. If you want to access it from another machine, assuming you have SSH access, you can use SSH port forwarding with the following command.

ssh -CqTf -L 9229:localhost:<debugger port> <server name> sleep 10
-C
compress all data
-q
quiet mode, supresses most warnings and errors
-T
prevent a TTY from being allocated
-f
Go into the background just before command execution. This will allow e.g. fingerprint confirmation or password input. Implies -n when command execution starts. This means ssh will exit even if it worked and is still running in the background.
-n
prevent reading from stdin
9229
This is the port on the local machine that will be the "entry portal" for the SSH tunnel.
localhost
This is the target that the server will resolve and connect to. Using localhost means the server will connect to itself
<debugger port>
This is the port on the target that the server will connect to. Here it should be the debugger port obtained in step 1.
<server name>
The name of the server, as if you were making a "normal" ssh connection.
sleep 10
A harmless command that will be run (and will be in the background).

3. connect to the debugger

Now you are ready to connect to the debugger with some kind of client. Note that Chromium (and thus Chrome & Edge) comes with built in tools for Node.js. Go to chrome://inspect or edge://inspect and you should see a link about "dev tools for node".

After that you can access the console, check memory contents with a heap snapshot and much more. Probably everything you want, really.

4. ending the debugging session

The process on the server should keep running unless you stop it or something bad happens. So normally you should be able to just stop the debugging session and the process will also keep running.

To stop the Node.js debugger, you need to go to the console and type the following:

inspector = require('inspector');
inspector.close();

After you have typed this, the dev tools will be disconnected. You can then continue by closing the dev tools and stopping the SSH command so the tunnel will be closed too.