ai-chat-ui/server/logger.js

96 lines
2.4 KiB
JavaScript

const fs = require('fs');
const path = require('path');
// 日志级别枚举
const LOG_LEVELS = {
ERROR: 0,
WARN: 1,
INFO: 2,
DEBUG: 3,
};
// 创建logs目录
const logsDir = path.join(__dirname, 'logs');
if (!fs.existsSync(logsDir)) {
fs.mkdirSync(logsDir);
}
// 日志记录器类
class Logger {
constructor(level = 'INFO') {
this.level = LOG_LEVELS[level.toUpperCase()] || LOG_LEVELS.INFO;
this.logFilePath = path.join(logsDir, `server-${new Date().toISOString().split('T')[0]}.log`);
}
_shouldLog(level) {
return LOG_LEVELS[level.toUpperCase()] <= this.level;
}
_writeLog(level, message, meta = {}) {
if (!this._shouldLog(level)) return;
const timestamp = new Date().toISOString();
const logEntry = {
timestamp,
level,
message,
...meta,
};
// 控制台输出
console.log(`[${timestamp}] [${level}] ${message}`, meta);
// 文件输出
try {
const logLine = JSON.stringify(logEntry) + '\n';
fs.appendFileSync(this.logFilePath, logLine);
} catch (err) {
console.error('Failed to write to log file:', err);
}
}
error(message, meta = {}) {
this._writeLog('ERROR', message, meta);
}
warn(message, meta = {}) {
this._writeLog('WARN', message, meta);
}
info(message, meta = {}) {
this._writeLog('INFO', message, meta);
}
debug(message, meta = {}) {
this._writeLog('DEBUG', message, meta);
}
// HTTP请求日志专用方法
http(req, res, startTime, error = null) {
const duration = Date.now() - startTime;
const logMeta = {
method: req.method,
url: req.url,
statusCode: res.statusCode,
duration: `${duration}ms`,
userAgent: req.headers['user-agent'],
ip: req.ip || req.connection.remoteAddress,
...(error ? { error: error.message || error } : {})
};
const statusCategory = Math.floor(res.statusCode / 100);
let level = 'INFO';
if (error || statusCategory >= 5) {
level = 'ERROR';
} else if (statusCategory >= 4) {
level = 'WARN';
}
this._writeLog(level, `HTTP ${req.method} ${req.url} ${res.statusCode} ${duration}ms`, logMeta);
}
}
// 创建全局日志实例
const logger = new Logger(process.env.LOG_LEVEL || 'INFO');
module.exports = { logger, LOG_LEVELS };