Explore the advantages and disadvantages of the Node.js debugging module, console, and how it interacts with standard streams like stdout and stderr.
- [Instructor] Node includes a simple debugging module named Console. It includes a number of methods, like console.log for regular log messages, and console.error for error messages. Is this the best place to be sending log entries? No, because the console can be evil. Not always, but sometimes. Here's why. Let's start with how Node handles input and output. By default, Node.js on its own, has no log file. While there's output or errors, they're sent to what's known as standard streams.
What are standard streams? They're preconnected input and output communication channels between a program and its environment. There are three. The first is standard input, or standard in, which is the interface where the program receives input when starting. The second is standard output, which is where the program sends output during execution. The final is similar, standard error, which is where the program sends errors and other diagnostic information. When commands are executed from an interactive shell, the streams are connected to the text terminal by default.
Streams can be redirected to write to a file, or to another program, which we'll discuss later. So, practically speaking, Node.js reads input from standard in, sends output to standard out, and errors to standard error. Since Node is typically executed from an interactive shell, all these messages are sent to the terminal. If you'd like to learn more about how to access these streams, check out the Node.js API documentation on the built-in process object. Why do I bring up standard streams, and why do they matter in the context of Node.js? Because that's where Node's console writes to.
Console.log writes to standard out, and console.error writes messages and diagnostics to standard error. There's also console.warn, which is just an alias for console.error. That sounds pretty logical. So, Node's console writes to the terminal, so what? Why does that matter? Unless you explicitly redirect the output, those log messages will not be saved anywhere. That means you can fill your code base with helpful console.log and error messages, but without redirection, they're useless.
If a tree falls in a forest, and no one's around, does it make a sound? When developing locally, just writing to the terminal is fine, but not in a production environment. How do we go about redirecting output? You can use the operating system to redirect the output, like piping it to a file. This works, but it has limitations, like not supporting multiple destinations. You can use a process manager like PM2, which automatically redirects output to log and error files.
This is an easy solution that provides a good foundation for other logging tools that we'll be discussing shortly. However, PM2 doesn't support multiple destinations. It also doesn't give more granularity to the levels, log, and error, so we're gonna have to add it ourselves. Finally, there's a question of performance. Node's console is synchronous, which means execution is blocked until it's done. You can write all the asynchronous code you want, but one little console, and everybody has to wait for it to complete.
That's sub-optimal. Now that we've heard about its problems, let's try Node's debugging console to both highlight how to use it, and to see its limitations first-hand. Let's try out the console by implementing a request logger as an express middleware in the web server. A request logger does pretty much what it sounds like, it records a log entry for each request. The best place to put a request logger in a web server is after the static files, but before any routing, ready? Open up Visual Studio Code.
I'm gonna close the terminal, because we don't need it right now. Navigate to servers, web, and open app.js. Scroll down to just after the views configuration, but before the router. We're gonna create a new middleware right here. Start off with app.use to mount a middleware. Use an anonymous function with the parameters, request, response, and next.
In it, we're gonna console log three things. So, start off with console.log. First, the current date in ISO format, so, new date to ISOString. Then the request method, request.method. Then, the request original URL. Request.originalurl. Finally, return next to move on to the next middleware.
Save the changes to the file. If we go up to the file menu, there's an entry for save, along with the keyboard shortcut, which is specific to the operating system. After this point, I'm gonna be using the keyboard shortcut to save. If we open the terminal up again, you'll see that PM2 restarted the process when we saved the file, just like nodemon does. Very convenient. Make sure the browser's up so we can see both, side-by-side. Let's navigate to localhost 5000.
This time, there's a log message over on the left. The current time, the method, and the URL. If we visit a game, now there's a log message that includes the game's ID. Let's break it by going to an invalid game, like, A-S-D-F. We get the same error messages, but right before it, is a log message containing what was requested, which, in our case, was A-S-D-F. Now that we've found a problem, how can we use the console to help fix it?
- Building a troubleshooting mindset
- Why measure performance?
- What's a microservice architecture?
- Managing microservices with PM2
- Effective logging strategies
- Debugging Node.js applications
- Benchmarking performance
- Profiling code execution
- Knowing what to optimize