const isElectron = () => typeof window !== 'undefined' && window.electronAPI && typeof window.electronAPI.writeLog === 'function'; // 检测是否在 Cordova 环境中 const isCordova = () => typeof window !== 'undefined' && !!window.cordova; // 检测是否在 Cypress 测试环境中 const isTestEnvironment = () => typeof window !== 'undefined' && window.Cypress; // 检测是否在浏览器环境中 const isBrowser = () => typeof window !== 'undefined' && !isElectron() && !isCordova() && !isTestEnvironment(); //避免obj是递归引用导致崩溃 function safeStringify(obj) { const cache = new Set(); return JSON.stringify(obj, (key, value) => { if (typeof value === 'object' && value !== null) { if (cache.has(value)) { return '[Circular]'; } cache.add(value); } return value; }); } function proxyLog(level) { const original = console[level]; return (...args) => { const msg = args.map(v => typeof v === 'object' ? safeStringify(v) : String(v)).join(' '); let finalMsg = msg; if (isBrowser()) { const timestamp = new Date().toISOString(); finalMsg = `[${timestamp}] [${level}] ${msg}`; original(finalMsg); // ① 浏览器环境:控制台打印带时间戳的格式化消息 } else { original(...args); // ① Electron/其他环境:控制台打印原始参数 } // 如果在测试环境中,直接返回,不发送任何网络请求 if (isTestEnvironment()) { return; } if (isElectron()) { // ② Electron 环境 window.electronAPI.writeLog(level, msg).catch(() => {}); } else if (isCordova()) { // ③ Cordova 环境 // 动态导入Cordova日志写入器,避免在非Cordova环境下加载 import('./cordova-log-writer.js').then(({ getCordovaLogWriter }) => { const writer = getCordovaLogWriter(); writer.writeLog(level, msg).catch(() => {}); }).catch(() => {}); } else if (typeof fetch !== 'undefined') { // // ④ 纯 Web 或 pkg-static:发一条异步 POST /log,不阻塞、不报错 // fetch('/log', { // method: 'POST', // headers: { 'Content-Type': 'application/json' }, // body: safeStringify({ level, msg }) // }).catch(() => {}); // 404 也不抛错 } }; } export const logger = { log: proxyLog('log'), warn: proxyLog('warn'), error: proxyLog('error'), debug: proxyLog('debug'), fatal: proxyLog('fatal'), };