日志分为三类:普通日志、异常日志和控制台日志。其中普通日志和异常日志会生成日志文件,持久化存储。控制台日志只展示在控制台中,用于辅助开发。

控制台日志

控制台日志用于辅助开发,一般我们使用 nestjs 内置的日志模块以保持日志格式的一致性。

  1. import { Logger } from '@nestjs/common'
  2. Logger.log('app is listening to 8080')

普通日志

普通日志记录请求信息,包括请求的 id、用时、method、url、headers 等信息。
在中间件中实现,使用了 express-winstonwinstonwinston-daily-rotate-file

  1. import { Logger } from '@nestjs/common'
  2. import * as expressWinston from 'express-winston'
  3. import { format } from 'winston'
  4. import * as DailyRotateFile from 'winston-daily-rotate-file'
  5. import config from '../config'
  6. const { combine, timestamp, printf } = format
  7. export default expressWinston.logger({
  8. format: combine(
  9. timestamp(),
  10. printf(({ timestamp, meta }) => {
  11. // 设置日志信息、格式
  12. const { req, res, responseTime } = meta
  13. const { id, url, headers, method } = req
  14. Logger.log(`>> ${method}: ${url} ${responseTime}ms [${id}]`)
  15. const data = {
  16. requestId: id,
  17. time: responseTime,
  18. code: res.statusCode,
  19. method,
  20. url,
  21. headers
  22. }
  23. return `${timestamp} ${JSON.stringify(data)}`
  24. })
  25. ),
  26. transports: [
  27. new DailyRotateFile({
  28. filename: '%DATE%.log',
  29. ...config.LOGGER
  30. })
  31. ],
  32. requestWhitelist: [
  33. 'url',
  34. 'headers',
  35. 'method',
  36. 'httpVersion',
  37. 'originalUrl',
  38. 'query',
  39. 'id'
  40. ]
  41. })

异常日志

异常日志在异常过滤器中捕获,记录请求 id、method、url、exception 等信息。

  1. // log util
  2. import { createLogger, format } from 'winston'
  3. import { Logger } from '@nestjs/common'
  4. import * as DailyRotateFile from 'winston-daily-rotate-file'
  5. import config from '../config'
  6. const { combine, timestamp, printf } = format
  7. export const error = createLogger({
  8. format: combine(
  9. timestamp(),
  10. printf(({ timestamp, id, method, url ,exception }) => {
  11. Logger.error(exception)
  12. return `${timestamp} ${id} ${method} ${url}: ${JSON.stringify(exception)}`
  13. })
  14. ),
  15. transports: [
  16. new DailyRotateFile({
  17. filename: '%DATE%.error.log',
  18. level: 'error',
  19. ...config.LOGGER
  20. })
  21. ]
  22. })
  1. import { HttpException, Catch, ArgumentsHost } from '@nestjs/common'
  2. import { BaseExceptionFilter } from '@nestjs/core'
  3. import { error as logger } from './errorlogger'
  4. @Catch(HttpException)
  5. export class ExceptionFilter extends BaseExceptionFilter {
  6. catch(exception, host: ArgumentsHost) {
  7. const ctx = host.switchToHttp();
  8. const request = ctx.getRequest<any>();
  9. const { id, method, url } = request
  10. logger.error('', {
  11. id,
  12. method,
  13. url,
  14. exception
  15. })
  16. super.catch(exception, host);
  17. }
  18. }

如果需要自定义日志,可以参考 日志