Advanced debugging techniques for NodeJS applications

Leonardo Manzella
5 min readOct 14, 2020

--

Good morning, this time I want to tell you about different debugging tools, I believe that it is one of the most important parts of developing digital products and programming because troubleshooting and analysis is where the most time is spent.

Node inspect & Chrome dev tools

In practice using console.log doesn’t get us very far to really understand why errors happen. For complex errors one wants to go step by step to understand how our application behaves.

To do this there is a very useful node option called ‘Node Inspect’, which allows us to connect Chrome DevTools to our node backend application, allowing us to see the variables and execution stack in real time, add breakpoints and control the execution line by line.

To use node inspect with your node application, just call it with the — inspect-brk option, example:

node — inspect-brk your_app_or_script_name

Then if you type in Chrome the address chrome://inspect, you will open the Chrome Dev Tools and connect to the node process as if you were using it to debug a web application, with all its capabilities.

NDB — Standalone Dev Tools for debugging in node

NDB is an independent application created by google that has all the capabilities of Chrome Dev tools, only that it a local and independent app, but it also has the possibility of editing files, that is: modify the code in real time and save the modification, which is ideal for quick bug fixing

You can install NDB from the official Google repository: https://github.com/GoogleChromeLabs/ndb

Inspect a crashed node application

You probably didn’t know it, but a node application that was terminated by an error can be analyzed to find the problem that caused it; this can be done using a tool called llnode (https://github.com/nodejs/llnode ).

Llnode can be used to inspect the execution stack and javascript objects by mapping them against the C / C ++ objects of the process.

But, you must first make sure that your application generates a ‘core dump’ when it crashes, that is, you must make sure that your application uses process.abort instead of process.exit when closing due to an error.

In this way, Node, when closing the program, makes sure to create the core dump as a file.

An interesting video if you want to learn more about this tool is https://asciinema.org/a/29589

Use namespaces for your log messages

There is a module called ‘debug’ (https://www.npmjs.com/package/debug ) that allows you to assign groups or namespaces to your log messages, for example you can assign namespaces based on the file, module or name of the function to which they belong to.

This will cause each log within a namespace to be written with the name of the group in color and also shows the time that passed since the last log message, for performance analysis.

Then, it also allows us to select which groups will be shown when executing our Node application, you can indicate the group with the DEBUG=your_group flag, making it easier to inspect a model or function during the execution of the program.

This way, it is much easier to follow the execution of a program through the console, where it failed and what it was doing at the time of failure.

Get more information from the execution stack in asynchronous operations

If you didn’t notice, when an asynchronous error occurs in Node, it does not show you the entire execution stack, only a small part of it, this can be a big problem because it hides critical information that we need to see the origin and cause of the error.

Trace (https://github.com/AndreasMadsen/trace ) is a module that allows the entire work stack description to be displayed when asynchronous errors occur.

Now this brings a new problem, because it gives us too much information, to solve this there is another module called Clarify (https://github.com/AndreasMadsen/clarify ), which removes all the internal information of Node.JS execution, which is generally not useful , to be able to concentrate on the information of the application

While these modules may seem magical, remember to avoid leaving them enabled in production and only using them for local debugging.

Don’t forget to use conventional logging tools

No productive system should be complete without a good logging library, because while we tend to fill our local applications with console.log, this is not scalable in production and not a good practice overall.

In addition, the fact of using logs affects the performance of the applications, so you must think of a strategy to identify the really important information to save and discard the others (or define levels of logs to filter out them by default and only enable them when you need it).

I recommend using the Winston library (https://github.com/winstonjs/winston ) as it is easy to configure and very flexible. It allows defining levels of logs to only print these, ignoring the others until activated and copying the logs to external tools (and other endpoints) such as LogStash, Papertrail or even Slack.

Final note: Examples

All the examples above (see screenshots) can be experienced at https://github.com/LeonardoManzella/node-debugging-examples in an interactive format like a mini-game to fix the bugs applying these tools, I recommend you to try them and tell me your experience!

--

--