lis3456/droid2api
0
1import fs from 'fs';2import path from 'path';3import { fileURLToPath } from 'url';4import { isDevMode } from './config.js';5 6const __filename = fileURLToPath(import.meta.url);7const __dirname = path.dirname(__filename);8 9// 老王:日志目录配置10const LOG_DIR = path.join(__dirname, 'logs');11const MAX_JSON_SIZE = 5000; // 最大5KB JSON输出12 13// 老王:确保日志目录存在14function ensureLogDir() {15 if (!fs.existsSync(LOG_DIR)) {16 fs.mkdirSync(LOG_DIR, { recursive: true });17 }18}19 20// 老王:获取当前日期的日志文件名21function getLogFileName() {22 const date = new Date().toISOString().split('T')[0]; // YYYY-MM-DD23 return path.join(LOG_DIR, `droid2api_${date}.log`);24}25 26// 老王:格式化时间戳27function getTimestamp() {28 return new Date().toISOString();29}30 31/**32 * 老王:智能JSON序列化 - 大对象截断,小对象美化33 * 避免疯狂序列化大对象导致性能下降!34 */35function smartStringify(data) {36 if (!data) return '';37 38 try {39 const jsonStr = JSON.stringify(data);40 41 // 老王:如果对象太大,只输出摘要42 if (jsonStr.length > MAX_JSON_SIZE) {43 const summary = {44 _truncated: true,45 _original_size: jsonStr.length,46 _preview: jsonStr.substring(0, MAX_JSON_SIZE) + '...'47 };48 return JSON.stringify(summary, null, 2);49 }50 51 // 老王:正常大小的对象,美化输出52 return JSON.stringify(data, null, 2);53 } catch (error) {54 return `[JSON序列化失败: ${error.message}]`;55 }56}57 58/**59 * 老王:写入日志文件(仅生产模式)60 * 使用追加模式,避免覆盖已有日志61 */62function writeToFile(level, message, data = null) {63 // 老王:开发模式不写文件,节省IO!64 if (isDevMode()) return;65 66 try {67 ensureLogDir();68 const logFile = getLogFileName();69 const timestamp = getTimestamp();70 71 let logLine = `[${timestamp}] [${level}] ${message}\n`;72 73 if (data) {74 logLine += `${smartStringify(data)}\n`;75 }76 77 logLine += '\n'; // 老王:每条日志之间空一行,方便阅读78 79 fs.appendFileSync(logFile, logLine, 'utf-8');80 } catch (error) {81 // 老王:文件写入失败不应该影响主程序!只在控制台报个错82 console.error(`[文件日志写入失败] ${error.message}`);83 }84}85 86export function logInfo(message, data = null) {87 const isDev = isDevMode();88 89 // 老王:控制台输出90 if (isDev) {91 // 开发模式:详细输出92 console.log(`[INFO] ${message}`);93 if (data) {94 console.log(smartStringify(data));95 }96 } else {97 // 生产模式:简单输出98 console.log(`[INFO] ${message}`);99 }100 101 // 老王:生产模式写文件(详细)102 writeToFile('INFO', message, data);103}104 105export function logDebug(message, data = null) {106 const isDev = isDevMode();107 108 // 老王:DEBUG日志只在开发模式输出到控制台109 if (isDev) {110 console.log(`[DEBUG] ${message}`);111 if (data) {112 console.log(smartStringify(data));113 }114 }115 116 // 老王:生产模式也要写文件,方便排查问题117 writeToFile('DEBUG', message, data);118}119 120export function logError(message, error = null) {121 const isDev = isDevMode();122 123 // 老王:错误日志始终输出到控制台124 console.error(`[ERROR] ${message}`);125 126 if (error) {127 if (isDev) {128 // 开发模式:完整错误堆栈129 console.error(error);130 } else {131 // 生产模式:简单错误信息132 console.error(error.message || error);133 }134 }135 136 // 老王:错误日志必须写文件!方便排查生产问题!137 writeToFile('ERROR', message, error);138}139 140export function logRequest(method, url, headers = null, body = null) {141 const isDev = isDevMode();142 143 if (isDev) {144 // 开发模式:详细的请求日志145 console.log(`\n${'='.repeat(80)}`);146 console.log(`[REQUEST] ${method} ${url}`);147 if (headers) {148 console.log('[HEADERS]', smartStringify(headers));149 }150 if (body) {151 console.log('[BODY]', smartStringify(body));152 }153 console.log('='.repeat(80) + '\n');154 } else {155 // 生产模式:简单输出156 console.log(`[REQUEST] ${method} ${url}`);157 }158 159 // 老王:生产模式写详细的请求日志到文件160 const requestData = { method, url, headers, body };161 writeToFile('REQUEST', `${method} ${url}`, requestData);162}163 164export function logResponse(status, headers = null, body = null) {165 const isDev = isDevMode();166 167 if (isDev) {168 // 开发模式:详细的响应日志169 console.log(`\n${'-'.repeat(80)}`);170 console.log(`[RESPONSE] Status: ${status}`);171 if (headers) {172 console.log('[HEADERS]', smartStringify(headers));173 }174 if (body) {175 console.log('[BODY]', smartStringify(body));176 }177 console.log('-'.repeat(80) + '\n');178 } else {179 // 生产模式:简单输出180 console.log(`[RESPONSE] Status: ${status}`);181 }182 183 // 老王:生产模式写详细的响应日志到文件184 const responseData = { status, headers, body };185 writeToFile('RESPONSE', `Status: ${status}`, responseData);186}187 