Spaces:
Paused
Paused
| import winston from 'winston'; | |
| import path from 'path'; | |
| import { fileURLToPath } from 'url'; | |
| import fs from 'fs'; | |
| const __filename = fileURLToPath(import.meta.url); | |
| const __dirname = path.dirname(__filename); | |
| // 确保日志目录存在 | |
| const logDir = path.join(__dirname, '../../logs'); | |
| if (!fs.existsSync(logDir)) { | |
| fs.mkdirSync(logDir, { recursive: true }); | |
| } | |
| // 自定义日志格式 | |
| const logFormat = winston.format.combine( | |
| winston.format.timestamp({ | |
| format: 'YYYY-MM-DD HH:mm:ss' | |
| }), | |
| winston.format.errors({ stack: true }), | |
| winston.format.printf(({ level, message, timestamp, stack }) => { | |
| if (stack) { | |
| return `${timestamp} [${level.toUpperCase()}]: ${message}\n${stack}`; | |
| } | |
| return `${timestamp} [${level.toUpperCase()}]: ${message}`; | |
| }) | |
| ); | |
| // 创建logger实例 | |
| const logger = winston.createLogger({ | |
| level: process.env.LOG_LEVEL || 'info', | |
| format: logFormat, | |
| transports: [ | |
| // 控制台输出 | |
| new winston.transports.Console({ | |
| format: winston.format.combine( | |
| winston.format.colorize(), | |
| logFormat | |
| ) | |
| }), | |
| // 错误日志文件 | |
| new winston.transports.File({ | |
| filename: path.join(logDir, 'error.log'), | |
| level: 'error', | |
| maxsize: 5242880, // 5MB | |
| maxFiles: 5 | |
| }), | |
| // 综合日志文件 | |
| new winston.transports.File({ | |
| filename: path.join(logDir, 'combined.log'), | |
| maxsize: 5242880, // 5MB | |
| maxFiles: 5 | |
| }) | |
| ], | |
| // 处理未捕获的异常 | |
| exceptionHandlers: [ | |
| new winston.transports.File({ | |
| filename: path.join(logDir, 'exceptions.log') | |
| }) | |
| ], | |
| // 处理未处理的Promise拒绝 | |
| rejectionHandlers: [ | |
| new winston.transports.File({ | |
| filename: path.join(logDir, 'rejections.log') | |
| }) | |
| ] | |
| }); | |
| // 在生产环境中不输出到控制台 | |
| if (process.env.NODE_ENV === 'production') { | |
| logger.remove(logger.transports[0]); // 移除控制台传输 | |
| } | |
| // 添加请求日志中间件 | |
| export const requestLogger = (req, res, next) => { | |
| const start = Date.now(); | |
| res.on('finish', () => { | |
| const duration = Date.now() - start; | |
| const logData = { | |
| method: req.method, | |
| url: req.url, | |
| status: res.statusCode, | |
| duration: `${duration}ms`, | |
| ip: req.ip || req.connection.remoteAddress, | |
| userAgent: req.get('User-Agent') | |
| }; | |
| if (res.statusCode >= 400) { | |
| logger.warn(`HTTP ${res.statusCode} - ${JSON.stringify(logData)}`); | |
| } else { | |
| logger.info(`HTTP ${res.statusCode} - ${JSON.stringify(logData)}`); | |
| } | |
| }); | |
| next(); | |
| }; | |
| export default logger; |