answer-book-mcp
Version:
智能问答和决策辅助的 MCP (Model Context Protocol) 服务器
253 lines (222 loc) • 5.34 kB
JavaScript
/**
* 日志管理工具
* 提供统一的日志记录功能
*/
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
}