问题
New to Nest.js,
I am trying to implement a simple logger for tracing HTTP requests like :
:method :url :status :res[content-length] - :response-time ms
From my understanding the best place for that would be interceptors. But I Also use Guards and as mentionned, Guards are triggered after middlewares but before interceptors.
Meaning, my forrbidden accesses are not logged. I could write the logging part in two different places but rather not. Any idea?
Thanks!
My Interceptor code:
import { Injectable, NestInterceptor, ExecutionContext, HttpException, HttpStatus } from '@nestjs/common';
import { Observable, throwError } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';
@Injectable()
export class HTTPLoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, call$: Observable<any>): Observable<any> {
const now = Date.now();
const request = context.switchToHttp().getRequest();
const method = request.method;
const url = request.originalUrl;
return call$.pipe(
tap(() => {
const response = context.switchToHttp().getResponse();
const delay = Date.now() - now;
console.log(`${response.statusCode} | [${method}] ${url} - ${delay}ms`);
}),
catchError((error) => {
const response = context.switchToHttp().getResponse();
const delay = Date.now() - now;
console.error(`${response.statusCode} | [${method}] ${url} - ${delay}ms`);
return throwError(error);
}),
);
}
}
回答1:
I had a similar issue with logging the correct status code due to the filters running after the interceptor. The only solution I could come to that I was comfortable with was to implement the logging in the interceptor. Very similar to how you have done so in your code. While the filter runs after the interceptor runs the observable can be leveraged to execute a function after it completes successfully or errors.
The trick for me was that the statuscode on the response is not guaranteed to be set properly even in the tap or the catchError operators. I solved this by checking the method of the request and if it's a POST method then I know the successful response is a 201 else it is always a 200.
If I receive an error I grab the status code from the error and use that instead of the status code on the response object. Since my Exception filter will run before the observable completes I know that a statusCode will exist on my error object at this time.
回答2:
I ended up injecting a classic logger on the raw app. This solution is not the best since it is not integrated to the Nest flow but works well for standard logging needs.
import { NestFactory } from '@nestjs/core';
import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify';
import { ApplicationModule } from './app.module';
import * as morgan from 'morgan';
async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>(ApplicationModule, new FastifyAdapter());
app.use(morgan('tiny'));
await app.listen(process.env.PORT, '0.0.0.0');
}
if (isNaN(parseInt(process.env.PORT))) {
console.error('No port provided. 👏');
process.exit(666);
}
bootstrap().then(() => console.log('Service listening 👍: ', process.env.PORT));
来源:https://stackoverflow.com/questions/55093055/logging-request-response-in-nest-js