How to Remote Debug and Profile Node.js Apps?

Debugging is an important skill for every developer. Here’s how to quickly setup debugging for nodejs with free tools everyone has.

Introduction

There are many fancy tools for debugging your application.  Data dog, rookout, aspecto and sentry to name a few. They are all commercial solutions though. They cost money, and have their learning curve for new developers coming into the team.

There is a tool that almost every computer in the world has that can give you debugging and profiling capabilities for your nodejs applications: chrome dev tools.

Logs debugging

When it comes to debugging nodejs applications, the first tool that comes to mind is the almighty `console.log`.

You just sprinkle your codebase with console.log s in the right places, spin up your nodejs server and see the values of your objects at any given time.

But that’s a primitive way of debugging. More like logs reading… And what about profiling your application and checking memory usage and cpu consumption?

How to really debug a nodejs application?

With Chrome dev tools it’s very easy.  

Let’s demo that. For this demo I’ll be using this repository: https://github.com/YonatanKra/nodejs-perf-demo

1. You can clone it and try along (don’t forget to yarn or npm install after you clone it).

2. We start the application with the --inspect flag:

node --inspect gc/gc-example.js

3. We head over to chrome and browse to chrome://inspect:

Figure 1 Browsing to the chrome inspect page

4. Inside, we should see our server running (see the Target section in the image below).

Figure 2 The chrome inspect page

5. Click the inspect link under the running process’s name and you should get to the nodejs chrome dev tools:

Figure 3 Chrome DevTools for nodejs

Once there, you can use the nodejs console, see the source files and add debug points, and profile the app’s memory or CPU usage.

How to add a debug point to a nodejs application?

We head over to the Sources tab and hit Ctrl+P (or cmnd + p on Mac).  This will allow you to search for your file. In my case, I’ll search for gc-example.js:

Figure 4 searching for a file using Ctrl/Cmnd + P in the Sources tab

After I open the file, I just set a debug point wherever I want. In this case, I’ll add it to the API entry point:

Add a debug breakpoint in google chrome DevTools
Figure 5 Setting a debug point in line 34

Because in my case, the server is running locally on port 8080, I can trigger my API using curl like this:

curl localhost:8080

Because our server is serving using the GET method, we could have reached the same effect by browsing to this URL. Sometimes you have a POST gateway to test, so you’d have to use curl or tools like postman.

Triggering the API will result in the code stopping at the breakpoint:

Figure 6 Debug point triggered after triggering the API

How to profile the CPU usage of a nodejs application?

For this part, we’ll head over to the Profiler tab:

Figure 7 The profiler tab. You can start recording the CPU.

We can click on the “Start” button or the small record button at the top left part and it will start recording our application.

We will use the curl trick from above to trigger the code of our application and then click on the record button again or on the Stop button that replaced the start button:

Figure 8 The profiler tab while recording

Once we stop the recording, we will get to a flame chart of the recording:

Figure 9 The flame chart of a recording. The flame chart shows when code ran during the recording and how long it took it to run. We can see some “flames” where code runs. The first “flame” (A in Figure 9) is the request handler.  At around 3000ms we see the first function that ran (B) and at around 4500ms the second function (C).

A record item, named “Profile 1”, is created. If we record again, we’d have more than one recording and we can browse them using the left CPU profiles menu.

You can zoom in and see exactly what functions ran, how long it took every function to run, garbage collection instances etc.:

Figure 10 Zooming in on the first function (Figure 9 B). It shows a lot of garbage collection instances (gray bars under buildArray1.

There’s much more information but that’s beyond the scope of this article. 

How to profile the memory of a nodejs application?

Now we head over to the memory tab:

Figure 11 The memory tab in Chrome DevTools for nodejs

Explaining about it is a bit out of the scope of this article, but you can take a heap snapshot (what objects live in your app’s memory), track allocation of memory in your app and even what applications allocated how much memory.  

With all of these tools you can easily solve memory issues – the most (in)famous of them is the dreadful memory leak. You can dig a bit deeper with this video.

How to debug multiple applications?

The --inspect flag opens the debugging connection on 127.0.0.1:9229 as default. Trying to run two debugging instances will result in an error:

Figure 12 “address already in use” error when trying to debug with the default debug URL twice.

How to solve “address already in use” error when debugging nodejs?

In order to solve this, you can set the url and port when starting your debug session like this:

node --inspect=127.0.0.1:9230

Doing that, will not show your app in the chrome://inspect page automatically. There’s another step you need to do in order to make this work.

In the chrome://inspect page there’s a link to open the nodejs dedicated devtools:

Figure 13 The link to. open the dedicated DevTools for node

This will open the dedicated devtools where you will have a Connection page:

Figure 14 Dedicated DevTools for node connection tab.

Just click the “Add connection” button and add your debug url and port (the one you set when running the --inspect=<yourDebugUrl>:<port>).

How to debug and profile a nodejs app remotely?

All this is nice, and we can debug and profile the application when it is running locally. How about remotely? 

In order for an app to be exposed to the world, you should expose it in the url 0.0.0.0:<port>.

Serving your app through 0.0.0.0 exposes your server to everyone.  This is highly insecure and blocked by most cloud vendors by default (and probably your devops team will object to that as well).  

In order to get over this obstacle, you can leave the debug URL local (e.g. 127.0.0.1:<port>) like this:

node --inspect=localhost:9230


and access the server via SSH tunnel like this:

ssh -L 9221:localhost:9230 user@myServiceDomain.com

You would usually be prompted for a password or use a key file (pem) in order to access the machine, but your computer will have access to the machine’s localhost just as if you debug it locally.

Chrome dev tools have localhost:9221 set up by default.  If you are using a different port, just set it up in the connection page.

Summary

Debugging is a necessary phase in the development process.  No matter how many tests you write, and how many years of experience you have – solving a bug will require a kind of debugging (I usually debug the code when running the tests).

Using the knowledge in this article, you can now debug nodejs applications using chrome dev tools. More than that – you can profile your applications and solve performance issues. If you want to read more about profiling JS applications click here. You can browse the performance category to see more related articles.

Remote debugging is rarely needed in my experience, but chrome dev tools allows you that as well by connecting to remote servers via the Connection tab.

Thanks a lot to Yuval Bar Levi and Miki Ezra Stanger  the kind and thorough review!

Sign up to my newsletter to enjoy more content:

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments