Introduction to NestJS Logging
Hello guys and welcome. My name is Vlad. In this tutorial, we are going to learn how to use logging in NestJS. So you might want to use logging at two different levels. One is inside your app, inside your services, inside your business logic, for instance, to log any arbitrary value or to see how your logic basically executes.
And the other place where you would want to use a logger is in the middleware, so you can log the requests that are coming to your app. So it can be a POST request, a GET request. You might want to log the body that's coming. So all that will be done at this level, at the request level.
So before we start, I would appreciate if you can like this video and subscribe to this channel. It will help me to make more of those videos. By the way, all the code here that you see here is available on GitHub in the link in the description below. So feel free to clone the repo and follow along if you want.
We have a very simple application here, basically the starter NestJS starter. So we have a server running on port 3333. The reason why I'm not running it on port 3000 is because I often have React running on 3000, so I use 3333. We have an App Service that just returns a string, 'Hello World', and we have an App Controller that has basically two routes that we are going to use for testing: a GET route and a POST route on the root route. So if it's nothing here, so it will be like that. And we have a simple App Module, nothing nothing fancy here.
Using the Built-In Service Logger
So the first logging level is at the service's level. So you would want to log something on the service. This is because in the controller, the logic is pretty simple, so it's pretty self-explanatory. You would want to use a logging where the logic is dense and complex. So you want to know what is happening if this getHello for instance has 300 lines of codes and a lot of things is happening there, you might want to put some logs.
For logging you could very well use console.log something like that, right? console.log('test'). But the thing is, it's not very well... it doesn't look as good, I would say. So if we open the terminal here and we start that server and I will just make a curl request to the local host. There we go. If we do that, well, we will have a console.log test. But see that thing, these green lines? Those come from actually the built-in NestJS logger. So we can actually use the NestJS logger to do all that all that stuff. And let's inject it.
So we need to declare it here, logger, and it will be injected from the @nestjs/common. We need to instantiate it in the constructor as well. this.logger = new Logger(). Right, and instead of doing console.log, we can do this.logger.log(). And here we go. We have this log if we call it again, we will see it again.
We can have different types of log. You have log, you have warn, and you have debug as well that might be useful. You can of course use some other loggers like Winston or Morgan, but why use something external if you have that built in, right? So that is that.
You might also want to kind of personalize the logger. So you can say 'Custom Logger', and that will actually use that namespace when it logs. So you have Custom Logger here. You can also do something like AppService.name, and that will actually use the name of that class, if that makes sense. So you have AppService. That's quite cool. I will put it back to none here.
Production Logging Considerations & External Services
And that's it. You want to use your logger inside your services mainly, just to make sure that the logic is executed properly. This of course will be probably disabled in production unless you are using an asynchronous cron job or something like that. If this service is a cronjob, you might want to use this type of logger a lot. But again, if you're using a cron job, you would want to customize your logger so it uses an external logger service, like something like Paper Trails, SolarWinds, or any alternative that does basically the same thing, which is basically an aggregation of your logs. And you can customize that based on the documentation of NestJS. You can use your own custom logger or you can use any other transport. It's a bit similar to what we have in Winston, Morgan. But this logger you'll probably use mainly when you're developing, you want to have some overview of the values that exist in your app. You would want to use that.
Implementing a Request Logger Middleware
Okay, so let's go to the HTTP logger, so the request logger. This is good to see what is happening in your app. If you want to see the requests that are coming to your app, for instance, if is it a GET request, POST request, what kind of values are passed, you will want to use a middleware. Why middleware? It's because in Nest, middlewares are executed before any logic. So before guards, before interceptors. So if you have something like a rejected request because the authorization is not right or because the token, JWT token is incorrect, this logic would simply not execute. So it's important to put your logger before everything.
So we have a logger middleware here. This is a pretty simple logic here. Again, it's using a namespace called HTTP. You can use whatever you want. Again, this code is available on GitHub. So if you fail to follow, just check on GitHub. And here we are just using the method, so POST, GET, whatever, the original URL, status code, and any information that you want to log basically.
And the only thing that we need to do, we need to inject that logger middleware into our app. You can do it globally in the main.ts, but I don't recommend it because, well, you lose the capacity to use dependency injection. You might want to use it. So we need to inject it in AppModule. And I'll just reset it here because I have already done here. And here we go.
So the AppModule needs to implement NestModule and it just needs to have a configure function that will apply the middleware on all the routes. You can apply the logger on certain routes only. But you know you're going to use that in development mainly, not in production. In production, you are going to use a reverse proxy, something like Nginx, and probably this thing will handle the logs because it's much faster. And so this is all that mainly is used in development. And that way you can use the dependency injection in the middleware if you inject it inside the app module like that.
Demonstrating the Middleware Logger
So we are going to restart our server. Yeah, it's already restarted. Let's do the curl. And you see that you have our internal logger and we also have the the request logger. So let's go back into LoggerMiddleware. And I have another, I have another route here a POST route. So let me curl into that route: post. And you see that now it's written that it's a POST with status 201, etc. So you can literally log whatever you want here in the middleware.
For instance, I would want to log a body. So I would say if, so method is not equal to GET, so you would have a probably body if the method is not GET, something like POST, PUT, PATCH. You'll probably want to have a body here. So let's log that body. So this.logger.log() maybe actually something like another color, error. And it would be request.body. Right? So basically if we are going to use the POST request, it will log the the body which is null. I can provide one... and just quickly... yeah I think it will it works. And now if we use the GET request by default, it will not log the body.
Conclusion & Production Best Practices
So here we go, folks. I hope it was useful. This is how I personally use logger in NestJS mainly for development, not really for production. If you have any questions, feel free to drop them in the comment section below. And see you soon.