const fs = require('fs') const path = require('path') /** * 日志级别 */ const LOG_LEVELS = { debug: 0, info: 1, warn: 2, error: 3 } /** * 日志器 */ class Logger { constructor(level = 'info', logDir = './logs') { this.level = LOG_LEVELS[level] || LOG_LEVELS.info this.logDir = logDir // 确保日志目录存在 if (!fs.existsSync(logDir)) { fs.mkdirSync(logDir, { recursive: true }) } } /** * 格式化日志消息 */ formatMessage(level, message, meta = {}) { const timestamp = new Date().toISOString() const metaStr = Object.keys(meta).length > 0 ? JSON.stringify(meta) : '' return `[${timestamp}] [${level.toUpperCase()}] ${message} ${metaStr}\n` } /** * 写入日志文件 */ writeToFile(level, message, meta) { const date = new Date().toISOString().split('T')[0] const logFile = path.join(this.logDir, `${date}.log`) const logMessage = this.formatMessage(level, message, meta) fs.appendFile(logFile, logMessage, (err) => { if (err) console.error('写入日志失败:', err) }) } /** * 记录日志 */ log(level, message, meta = {}) { if (LOG_LEVELS[level] < this.level) return const formattedMessage = this.formatMessage(level, message, meta) // 控制台输出 switch (level) { case 'error': console.error(formattedMessage.trim()) break case 'warn': console.warn(formattedMessage.trim()) break default: console.log(formattedMessage.trim()) } // 文件输出(生产环境) if (process.env.NODE_ENV === 'production') { this.writeToFile(level, message, meta) } } debug(message, meta) { this.log('debug', message, meta) } info(message, meta) { this.log('info', message, meta) } warn(message, meta) { this.log('warn', message, meta) } error(message, meta) { this.log('error', message, meta) } } // 导出单例 const logger = new Logger(process.env.LOG_LEVEL || 'info') module.exports = logger