1、安装依赖,以winston为例
winston-daily-rotate-file:日志文件轮换
chalk:日志级别颜色
npm install nest-winston winston winston-daily-rotate-file chalk
2、服务配置文件
新建winston.config.ts文件
// /config/winston.config.ts
import * as chalk from 'chalk';
import { createLogger, format, transports } from 'winston';
import * as DailyRotateFile from 'winston-daily-rotate-file';
// 定义日志级别颜色,日志级别 error > warn > info > verbose > debug > silly
const levelsColors = {
error: 'red',
warn: 'yellow',
info: 'green',
debug: 'blue',
verbose: 'cyan',
}
const winstonLogger = createLogger({
format: format.combine(format.timestamp(), format.errors({ stack: true }), format.splat(), format.json()),
// defaultMeta: { service: 'log-service' }, //默认添加的信息
transports: [
//错误日志
new DailyRotateFile({
filename: 'logs/errors/error-%DATE%.log', // 日志名称,占位符 %DATE% 取值为 datePattern 值。
datePattern: 'YYYY-MM-DD', // 日志的格式和轮换的频率,此处表示每天。
zippedArchive: false, // 是否通过压缩的方式归档被轮换的日志文件。
maxSize: '20m', // 设置日志文件的最大大小,m 表示 mb 。
maxFiles: '14d', // 保留日志文件的最大天数,此处表示自动删除超过 14 天的日志文件。
level: 'error', // 日志类型,此处表示只记录级别最低为error的日志
}),
//运行时日志
new DailyRotateFile({
filename: 'logs/runtime/runtime-%DATE%.log',
datePattern: 'YYYY-MM-DD',
zippedArchive: false,
maxSize: '20m',
maxFiles: '14d',
level: 'debug',
}),
//控制台日志
new transports.Console({
format: format.combine(
format.colorize({
colors: levelsColors,
}),
format.simple(),
format.printf((info) => {
//获取日志级别
const symbols = Object.getOwnPropertySymbols(info);
const color = levelsColors[info[symbols[0]]];
//获取带颜色的日志
const message = `${chalk[color](info[symbols[2]])}`;
return message;
}),
),
level: 'debug',
}),
],
})
export default winstonLogger;
//app.module.ts
import winstonLogger from './config/winston.config';
@Module({
imports: [
WinstonModule.forRoot({
transports: winstonLogger.transports,
format: winstonLogger.format,
defaultMeta: winstonLogger.defaultMeta,
exitOnError: false,
})
]
})
3、全局中间件
新建logger.middleware.ts文件,捕获所有请求并记录
// /middleware/logger.middleware.ts
import { Injectable, Logger, NestMiddleware } from '@nestjs/common';
import * as dayjs from 'dayjs';
import { NextFunction, Request, Response } from 'express';
@Injectable()
export class LoggerMiddleware implements NestMiddleware {
private logger = new Logger();
use(req: Request, res: Response, next: NextFunction) {
// 开始时间
const start = Date.now();
// 获取请求信息
const { method, originalUrl, ip, httpVersion, headers } = req;
// 获取状态码
const { statusCode } = res;
res.on('finish', () => {
// 结束时间
const end = Date.now();
// 计算时间差
const duration = end - start;
//组装日志信息:timestamp|method|HTTP/[httpVersion]|url|status code|[response time]ms|client IP|user-agent|request body
const logFormat = `${dayjs().format("YYYY-MM-DD HH:mm:ss")}|${method}|HTTP/${httpVersion}|${originalUrl}|${statusCode}|${duration}ms|${ip}|${headers['user-agent']}|${JSON.stringify(method === 'GET' ? req.query : req.body)}`
// 根据状态码,进行日志类型区分
statusCode >= 500 ? this.logger.error(logFormat) : this.logger.log(logFormat)
})
next();
}
}
//app.module.ts
import {Module, MiddlewareConsumer} from '@nestjs/common';
import {LoggerMiddleware} from './middleware/logger.middleware';
export class AppModule {
configure(consumer: MiddlewareConsumer) {
//应用日志中间件到所有路由
consumer.apply(LoggerMiddleware).forRoutes('*');
}
}
4、注册
//main.ts
import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
//日志服务
app.useLogger(app.get(WINSTON_MODULE_NEST_PROVIDER));
await app.listen(3000);
}
5、使用示例
//your.service.ts
import {Injectable, Logger} from '@nestjs/common';
@Injectable()
export class yourService {
private logger = new Logger();
exampleFn(){
this.logger.log("测试日志打印")
}
}