UNPKG

answer-book-mcp

Version:

智能问答和决策辅助的 MCP (Model Context Protocol) 服务器

253 lines (222 loc) 5.34 kB
/** * 日志管理工具 * 提供统一的日志记录功能 */ import winston from 'winston' import path from 'path' import fs from 'fs-extra' /** * 创建日志目录 */ async function ensureLogDirectory () { const logDir = path.join(process.cwd(), 'logs') await fs.ensureDir(logDir) return logDir } /** * 自定义日志格式 */ const customFormat = winston.format.combine( winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.errors({ stack: true }), winston.format.json(), winston.format.printf(({ timestamp, level, message, ...meta }) => { let logMessage = `${timestamp} [${level.toUpperCase()}] ${message}` if (Object.keys(meta).length > 0) { logMessage += ` ${JSON.stringify(meta)}` } return logMessage }) ) /** * 控制台格式 */ const consoleFormat = winston.format.combine( winston.format.colorize(), winston.format.timestamp({ format: 'HH:mm:ss' }), winston.format.printf(({ timestamp, level, message, ...meta }) => { let logMessage = `${timestamp} ${level} ${message}` if (Object.keys(meta).length > 0) { logMessage += ` ${JSON.stringify(meta, null, 2)}` } return logMessage }) ) /** * 创建 Winston 日志器 */ async function createLogger () { const logDir = await ensureLogDirectory() const logger = winston.createLogger({ level: process.env.LOG_LEVEL || 'info', format: customFormat, defaultMeta: { service: 'answer-book-mcp' }, transports: [ // 错误日志文件 new winston.transports.File({ filename: path.join(logDir, 'error.log'), level: 'error', maxsize: 10 * 1024 * 1024, // 10MB maxFiles: 5, tailable: true }), // 组合日志文件 new winston.transports.File({ filename: path.join(logDir, 'combined.log'), maxsize: 10 * 1024 * 1024, // 10MB maxFiles: 5, tailable: true }) ], // 异常处理 exceptionHandlers: [ new winston.transports.File({ filename: path.join(logDir, 'exceptions.log') }) ], // 拒绝处理 rejectionHandlers: [ new winston.transports.File({ filename: path.join(logDir, 'rejections.log') }) ] }) // 开发环境添加控制台输出 if (process.env.NODE_ENV !== 'production') { logger.add(new winston.transports.Console({ format: consoleFormat })) } return logger } /** * 日志器实例 */ const logger = await createLogger() /** * 性能监控日志 */ function logPerformance (operation, startTime, metadata = {}) { const duration = Date.now() - startTime logger.info(`性能监控: ${operation}`, { duration: `${duration}ms`, ...metadata }) return duration } /** * 请求日志中间件 */ function logRequest (toolName, args) { const requestId = generateRequestId() const startTime = Date.now() logger.info('工具调用开始', { requestId, toolName, args: sanitizeArgs(args) }) return { requestId, startTime, end: (result, error = null) => { const duration = Date.now() - startTime if (error) { logger.error('工具调用失败', { requestId, toolName, duration: `${duration}ms`, error: error.message, stack: error.stack }) } else { logger.info('工具调用成功', { requestId, toolName, duration: `${duration}ms`, resultType: typeof result }) } } } } /** * 生成请求ID */ function generateRequestId () { return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}` } /** * 清理敏感参数 */ function sanitizeArgs (args) { if (!args || typeof args !== 'object') { return args } const sanitized = { ...args } const sensitiveKeys = ['password', 'token', 'secret', 'key', 'auth'] for (const key of Object.keys(sanitized)) { if (sensitiveKeys.some(sensitive => key.toLowerCase().includes(sensitive))) { sanitized[key] = '[REDACTED]' } } return sanitized } /** * 结构化错误日志 */ function logError (error, context = {}) { logger.error('应用错误', { message: error.message, stack: error.stack, name: error.name, code: error.code, ...context }) } /** * 业务指标日志 */ function logMetrics (metrics) { logger.info('业务指标', { type: 'metrics', timestamp: new Date().toISOString(), ...metrics }) } /** * 安全事件日志 */ function logSecurityEvent (event, details = {}) { logger.warn('安全事件', { type: 'security', event, timestamp: new Date().toISOString(), ...details }) } /** * 调试工具 */ function createDebugLogger (namespace) { return { debug: (message, meta = {}) => logger.debug(`[${namespace}] ${message}`, meta), info: (message, meta = {}) => logger.info(`[${namespace}] ${message}`, meta), warn: (message, meta = {}) => logger.warn(`[${namespace}] ${message}`, meta), error: (message, meta = {}) => logger.error(`[${namespace}] ${message}`, meta) } } export { logger, logPerformance, logRequest, logError, logMetrics, logSecurityEvent, createDebugLogger }