| |
| |
| |
| |
| class Logger { |
| constructor() { |
| this.requestCounter = 0 |
| this.activeRequests = new Map() |
|
|
| |
| this.LOG_LEVELS = { |
| ERROR: 0, |
| WARN: 1, |
| INFO: 2, |
| DEBUG: 3 |
| } |
|
|
| |
| this.currentLevel = this.LOG_LEVELS[process.env.LOG_LEVEL?.toUpperCase()] || this.LOG_LEVELS.INFO |
| } |
|
|
| |
| |
| |
| |
| generateRequestId() { |
| this.requestCounter++ |
| return `req_${Date.now()}_${this.requestCounter.toString().padStart(4, '0')}` |
| } |
|
|
| |
| |
| |
| |
| getTimestamp() { |
| const now = new Date() |
| |
| const beijingTime = new Date(now.getTime() + (8 * 60 * 60 * 1000)) |
| return beijingTime.toISOString().replace('T', ' ').replace('Z', '').substring(0, 19) |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| log(level, category, event, message, data = {}) { |
| const levelValue = this.LOG_LEVELS[level.toUpperCase()] |
| if (levelValue > this.currentLevel) { |
| return |
| } |
|
|
| |
| const logEntry = { |
| 时间: this.getTimestamp(), |
| 级别: this.translateLevel(level.toUpperCase()), |
| 分类: this.translateCategory(category), |
| 事件: event, |
| 消息: message, |
| ...data |
| } |
|
|
| const logString = JSON.stringify(logEntry) |
|
|
| switch (level.toUpperCase()) { |
| case 'ERROR': |
| console.error(logString) |
| break |
| case 'WARN': |
| console.warn(logString) |
| break |
| case 'DEBUG': |
| console.debug(logString) |
| break |
| default: |
| console.log(logString) |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| translateLevel(level) { |
| const levelMap = { |
| 'ERROR': '错误', |
| 'WARN': '警告', |
| 'INFO': '信息', |
| 'DEBUG': '调试' |
| } |
| return levelMap[level] || level |
| } |
|
|
| |
| |
| |
| |
| |
| translateCategory(category) { |
| const categoryMap = { |
| 'APPLICATION': '应用', |
| 'REQUEST': '请求', |
| 'SYSTEM': '系统', |
| 'MODEL': '模型', |
| 'IMAGE': '图片' |
| } |
| return categoryMap[category] || category |
| } |
|
|
| |
| |
| |
| |
| |
| |
| logInfo(event, message, data = {}) { |
| this.log('INFO', 'APPLICATION', event, message, data) |
| } |
|
|
| |
| |
| |
| |
| |
| |
| logWarn(event, message, data = {}) { |
| this.log('WARN', 'APPLICATION', event, message, data) |
| } |
|
|
| |
| |
| |
| |
| |
| |
| logDebug(event, message, data = {}) { |
| this.log('DEBUG', 'APPLICATION', event, message, data) |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| logRequestStart(method, url, headers = {}, body = {}) { |
| const requestId = this.generateRequestId() |
|
|
| |
| this.activeRequests.set(requestId, { |
| startTime: Date.now(), |
| requestId, |
| method, |
| url, |
| userAgent: headers['user-agent'] || 'unknown', |
| contentType: headers['content-type'] || 'unknown', |
| contentLength: headers['content-length'] || 'unknown', |
| model: body.model || 'unknown', |
| messageCount: Array.isArray(body.messages) ? body.messages.length : 0, |
| hasImages: this.detectImages(body.messages), |
| isStream: body.stream === true |
| }) |
|
|
| |
| this.log('INFO', 'REQUEST', '请求开始', '收到新的API请求', { |
| 请求ID: requestId, |
| 方法: method, |
| 路径: url, |
| 用户代理: headers['user-agent'] || '未知', |
| 内容类型: headers['content-type'] || '未知', |
| 内容长度: headers['content-length'] || '未知', |
| 模型: body.model || '未知', |
| 消息数量: Array.isArray(body.messages) ? body.messages.length : 0, |
| 包含图片: this.detectImages(body.messages), |
| 流式请求: body.stream === true |
| }) |
|
|
| return requestId |
| } |
|
|
| |
| |
| |
| |
| |
| |
| logRequestEnd(requestId, statusCode, responseInfo = {}) { |
| const activeRequest = this.activeRequests.get(requestId) |
|
|
| if (!activeRequest) { |
| this.logWarn('请求结束', `未找到请求ID: ${requestId}`) |
| return |
| } |
|
|
| const duration = Date.now() - activeRequest.startTime |
| const isSuccess = statusCode >= 200 && statusCode < 300 |
|
|
| |
| this.log('INFO', 'REQUEST', '请求结束', '请求处理完成', { |
| 请求ID: requestId, |
| 耗时毫秒: duration, |
| 状态码: statusCode, |
| 处理成功: isSuccess, |
| 模型: activeRequest.model, |
| 流式请求: activeRequest.isStream, |
| ...responseInfo |
| }) |
|
|
| |
| this.activeRequests.delete(requestId) |
| } |
|
|
| |
| |
| |
| |
| |
| logImageProcessingStart(requestId, imageCount) { |
| this.log('INFO', 'IMAGE', '图片处理开始', '开始处理上传的图片', { |
| 请求ID: requestId, |
| 图片数量: imageCount |
| }) |
| } |
|
|
| |
| |
| |
| |
| |
| |
| logLongImageDetection(requestId, imageIndex, detection) { |
| this.log('INFO', 'IMAGE', '长图检测', '完成图片长度检测', { |
| 请求ID: requestId, |
| 图片索引: imageIndex, |
| 是否长图: detection.isLongImage ? '是' : '否', |
| 图片尺寸: `${detection.width}x${detection.height}`, |
| 高宽比: detection.ratio?.toFixed(2), |
| 检测阈值: detection.threshold |
| }) |
| } |
|
|
| |
| |
| |
| |
| |
| |
| logImageCropping(requestId, imageIndex, cropResult) { |
| const timestamp = this.getTimestamp() |
| const stats = cropResult.stats || {} |
|
|
| const logData = { |
| 请求ID: requestId, |
| 时间: timestamp, |
| 事件: '图片切割', |
| 图片索引: imageIndex, |
| 切割片段数: stats.totalSegments || 0, |
| 原始尺寸: stats.originalDimensions, |
| 实际片段数: cropResult.segments?.length || 0 |
| } |
|
|
| console.log(`[图片处理] ${JSON.stringify(logData)}`) |
| } |
|
|
| |
| |
| |
| |
| |
| |
| logMessageSegmentation(requestId, imageIndex, segmentCount) { |
| const timestamp = this.getTimestamp() |
| const logData = { |
| 请求ID: requestId, |
| 时间: timestamp, |
| 事件: '消息分割', |
| 图片索引: imageIndex, |
| 分割消息数: segmentCount |
| } |
|
|
| console.log(`[消息处理] ${JSON.stringify(logData)}`) |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| logImageUpload(requestId, imageIndex, segmentIndex, success, url = null, error = null) { |
| const timestamp = this.getTimestamp() |
| const logData = { |
| 请求ID: requestId, |
| 时间: timestamp, |
| 事件: '图片上传', |
| 图片索引: imageIndex, |
| 片段索引: segmentIndex, |
| 成功: success ? '是' : '否', |
| 上传地址: success ? url : null, |
| 错误信息: success ? null : error |
| } |
|
|
| console.log(`[图片处理] ${JSON.stringify(logData)}`) |
| } |
|
|
| |
| |
| |
| |
| |
| |
| logModelCallStart(requestId, model, mammouthModel) { |
| this.log('INFO', 'MODEL', '模型调用开始', '开始调用AI模型', { |
| 请求ID: requestId, |
| 请求模型: model, |
| 实际模型: mammouthModel |
| }) |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| logModelCallEnd(requestId, success, error = null, duration = null) { |
| this.log(success ? 'INFO' : 'ERROR', 'MODEL', '模型调用结束', |
| success ? '模型调用成功' : '模型调用失败', { |
| 请求ID: requestId, |
| 调用成功: success ? '是' : '否', |
| 错误信息: success ? null : error, |
| 耗时毫秒: duration |
| }) |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| logError(requestId, errorType, errorMessage, errorDetails = {}) { |
| this.log('ERROR', 'APPLICATION', errorType, errorMessage, { |
| requestId, |
| ...errorDetails |
| }) |
| } |
|
|
| |
| |
| |
| |
| |
| |
| logGlobalError(errorType, errorMessage, errorDetails = {}) { |
| this.log('ERROR', 'SYSTEM', errorType, errorMessage, errorDetails) |
| } |
|
|
| |
| |
| |
| |
| |
| logPerformanceMetrics(requestId, metrics) { |
| const timestamp = this.getTimestamp() |
| const logData = { |
| requestId, |
| timestamp, |
| event: 'PERFORMANCE_METRICS', |
| ...metrics |
| } |
| |
| console.log(`[PERFORMANCE] ${JSON.stringify(logData)}`) |
| } |
|
|
| |
| |
| |
| |
| |
| detectImages(messages) { |
| if (!Array.isArray(messages)) { |
| console.log(`[图片检测] 消息不是数组: ${typeof messages}`) |
| return false |
| } |
|
|
| let hasImages = false |
| let imageCount = 0 |
|
|
| messages.forEach((message, index) => { |
| if (Array.isArray(message.content)) { |
| const imagePartsCount = message.content.filter(part => part.type === 'image_url').length |
| if (imagePartsCount > 0) { |
| hasImages = true |
| imageCount += imagePartsCount |
| console.log(`[图片检测] 消息${index}包含${imagePartsCount}张图片`) |
| } |
| } else if (typeof message.content === 'string') { |
| console.log(`[图片检测] 消息${index}是纯文本`) |
| } else { |
| console.log(`[图片检测] 消息${index}内容类型: ${typeof message.content}`) |
| } |
| }) |
|
|
| console.log(`[图片检测] 总计检测到${imageCount}张图片`) |
| return hasImages |
| } |
|
|
| |
| |
| |
| |
| getActiveRequestsStats() { |
| return { |
| count: this.activeRequests.size, |
| requests: Array.from(this.activeRequests.entries()).map(([id, req]) => ({ |
| requestId: id, |
| duration: Date.now() - req.startTime, |
| model: req.model, |
| isStream: req.isStream |
| })) |
| } |
| } |
| } |
|
|
| module.exports = new Logger() |
|
|