import * as winston from 'winston'; import * as DailyRotateFile from 'winston-daily-rotate-file'; import { WinstonModule } from 'nest-winston'; import * as path from 'path'; // 日志目录 const LOG_DIR = path.join(process.cwd(), 'logs'); // 日志格式 const logFormat = winston.format.combine( winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss', }), winston.format.errors({ stack: true }), winston.format.printf((info) => { const { timestamp, level, message, context, stack, ...meta } = info; const contextStr = context ? `[${context}] ` : ''; const stackStr = stack ? `\n${stack}` : ''; // 如果有额外的元数据,将其格式化为JSON字符串 const metaStr = Object.keys(meta).length > 0 ? ` ${JSON.stringify(meta, null, 2)}` : ''; return `${timestamp} [${level.toUpperCase()}] ${contextStr}${message}${metaStr}${stackStr}`; }), ); // 控制台格式(带颜色) const consoleFormat = winston.format.combine( winston.format.colorize(), winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss', }), winston.format.printf((info) => { const { timestamp, level, message, context, stack, ...meta } = info; const contextStr = context ? `[${context}] ` : ''; const stackStr = stack ? `\n${stack}` : ''; // 如果有额外的元数据,将其格式化为JSON字符串 const metaStr = Object.keys(meta).length > 0 ? ` ${JSON.stringify(meta, null, 2)}` : ''; return `${timestamp} ${level} ${contextStr}${message}${metaStr}${stackStr}`; }), ); // 创建日志传输器 const createTransports = () => { const transports: winston.transport[] = []; // 控制台输出 transports.push( new winston.transports.Console({ format: consoleFormat, level: process.env.NODE_ENV === 'production' ? 'info' : 'debug', }), ); // 错误日志文件(按日期滚动,保留7天) transports.push( new DailyRotateFile({ filename: path.join(LOG_DIR, 'error-%DATE%.log'), datePattern: 'YYYY-MM-DD', level: 'error', format: logFormat, maxFiles: '7d', // 保留7天 maxSize: '20m', // 单个文件最大20MB auditFile: path.join(LOG_DIR, '.audit-error.json'), }), ); // 应用日志文件(按日期滚动,保留7天) transports.push( new DailyRotateFile({ filename: path.join(LOG_DIR, 'app-%DATE%.log'), datePattern: 'YYYY-MM-DD', level: 'info', format: logFormat, maxFiles: '7d', // 保留7天 maxSize: '20m', // 单个文件最大20MB auditFile: path.join(LOG_DIR, '.audit-app.json'), }), ); // 调试日志文件(仅在开发环境) if (process.env.NODE_ENV !== 'production') { transports.push( new DailyRotateFile({ filename: path.join(LOG_DIR, 'debug-%DATE%.log'), datePattern: 'YYYY-MM-DD', level: 'debug', format: logFormat, maxFiles: '7d', // 保留7天 maxSize: '20m', // 单个文件最大20MB auditFile: path.join(LOG_DIR, '.audit-debug.json'), }), ); } return transports; }; // Winston配置 export const winstonConfig = { level: process.env.NODE_ENV === 'production' ? 'info' : 'debug', format: logFormat, transports: createTransports(), // 处理未捕获的异常 exceptionHandlers: [ new DailyRotateFile({ filename: path.join(LOG_DIR, 'exceptions-%DATE%.log'), datePattern: 'YYYY-MM-DD', format: logFormat, maxFiles: '7d', maxSize: '20m', auditFile: path.join(LOG_DIR, '.audit-exceptions.json'), }), ], // 处理未处理的Promise拒绝 rejectionHandlers: [ new DailyRotateFile({ filename: path.join(LOG_DIR, 'rejections-%DATE%.log'), datePattern: 'YYYY-MM-DD', format: logFormat, maxFiles: '7d', maxSize: '20m', auditFile: path.join(LOG_DIR, '.audit-rejections.json'), }), ], }; // 创建Winston Logger实例 export const createWinstonLogger = () => { return WinstonModule.createLogger(winstonConfig); }; // 导出winston实例供直接使用 export const logger = winston.createLogger(winstonConfig);