typescript - Logga förfrågan/svar i Nest.js


Ny på Nest.js,
jag försöker implementera en enkel loggare för att spåra HTTP-förfrågningar som:

:method :url :status :res[content-length] - :response-time ms

Enligt min förståelse skulle det bästa stället för det vara interceptorer. Men jag använder också Guards och som nämnts, triggas Guards efter mellanprogrammen men före interceptorerna.

Det betyder att mina förbjudna åtkomster inte loggas. Jag skulle kunna skriva loggningen på två olika ställen men vill helst inte. Någon idé?

Tack!

Min Interceptor-kod:

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);
      }),
    );
  }
}

Svar #1

https://github.com/julien-sarazin/nest-playground/issues/1#issuecomment-682588094

Du kan använda mellanprogramvara för det.

import { Injectable, NestMiddleware, Logger } from '@nestjs/common';

import { Request, Response, NextFunction } from 'express';

@Injectable()
export class AppLoggerMiddleware implements NestMiddleware {
  private logger = new Logger('HTTP');

  use(request: Request, response: Response, next: NextFunction): void {
    const { ip, method, path: url } = request;
    const userAgent = request.get('user-agent') || '';

    response.on('close', () => {
      const { statusCode } = response;
      const contentLength = response.get('content-length');

      this.logger.log(
        `${method} ${url} ${statusCode} ${contentLength} - ${userAgent} ${ip}`
      );
    });

    next();
  }
}

och i AppModule

export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer): void {
    consumer.apply(AppLoggerMiddleware).forRoutes('*');
  }
}

Svar #2

Jag slutade med att injicera en klassisk loggare på den råa appen. Denna lösning är inte den bästa eftersom den inte är integrerad i Nest-flödet, men fungerar bra för standardloggning.

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));

Svar #3

Vad sägs om att använda finish-händelsen istället för close-händelsen.

import { Request, Response, NextFunction } from "express";
import { Injectable, NestMiddleware, Logger } from "@nestjs/common";

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  private logger = new Logger("HTTP");

  use(request: Request, response: Response, next: NextFunction): void {
    const { ip, method, originalUrl } = request;
    const userAgent = request.get("user-agent") || "";

    response.on("finish", () => {
      const { statusCode } = response;
      const contentLength = response.get("content-length");

      this.logger.log(
        `${method} ${originalUrl} ${statusCode} ${contentLength} - ${userAgent} ${ip}`,
      );
    });

    next();
  }
}

För eftersom jag vet, upprätthålls express-anslutningen efter att svar har skickats.
Så close-händelsen kan inte utlösas

Referens

01. Node-dokument om response-händelsen.
02. Github-ärende

Relaterade artiklar