import { LogLevel, LOG_LEVEL, LOG_TO_REALTIME } from './config' /** * 全项目统一日志出口。 * * 用法:logger.debug('模块名', '消息', 任意参数) * 级别:DEBUG < INFO < WARN < ERROR < SILENT,低于当前生效级别的调用直接返回, * 且级别判断前置,不做任何字符串拼接,热路径(如每次请求)零开销。 * * 输出: * 1. console —— 按级别选用 log / warn / error,开发者工具与真机调试可见 * 2. 微信实时日志 —— 仅 WARN 及以上写入,可在小程序后台「实时日志」查询线上问题 */ // 手动覆盖的级别(LOG_LEVEL 为 null 时按环境自动推导) let manualLevel: LogLevel | null = LOG_LEVEL // 解析后的生效级别缓存,避免每次调用都读环境信息 let resolvedLevel: LogLevel | null = null const LEVEL_NAMES: Record = { [LogLevel.DEBUG]: 'DEBUG', [LogLevel.INFO]: 'INFO', [LogLevel.WARN]: 'WARN', [LogLevel.ERROR]: 'ERROR', } // 按运行环境推导默认级别:开发版最详细,正式版只看异常 function resolveByEnv(): LogLevel { try { const info = wx.getAccountInfoSync() const env = info.miniProgram && info.miniProgram.envVersion if (env === 'develop') return LogLevel.DEBUG if (env === 'trial') return LogLevel.INFO return LogLevel.WARN } catch (e) { // 取不到环境信息时(低版本基础库等)退化为 DEBUG,保证开发期可见 return LogLevel.DEBUG } } // 当前生效级别 export function getLevel(): LogLevel { if (resolvedLevel === null) { resolvedLevel = manualLevel === null ? resolveByEnv() : manualLevel } return resolvedLevel } /** * 运行时调整日志级别(调级后对全局生效)。 * 传 null 恢复为「按环境自动」。 */ export function setLevel(level: LogLevel | null): void { manualLevel = level resolvedLevel = null } // 实时日志单例(惰性初始化,取不到时降级为仅 console,绝不因日志抛错影响业务) let realtimeManager: any = null let realtimeInited = false function getRealtimeManager(): any { if (realtimeInited) return realtimeManager realtimeInited = true try { if (typeof wx.getRealtimeLogManager === 'function') { realtimeManager = wx.getRealtimeLogManager() } } catch (e) { realtimeManager = null } return realtimeManager } // 序列化日志参数:实时日志有单条长度限制,做截断保护 function stringify(args: any[]): string { try { return args .map((a) => { if (typeof a === 'string') return a try { return JSON.stringify(a) } catch (e) { return String(a) } }) .join(' ') .slice(0, 1000) } catch (e) { return '' } } function emit(level: LogLevel, module: string, args: any[]): void { if (level < getLevel()) return const prefix = `[${LEVEL_NAMES[level]}][${module}]` // console 通道 if (level === LogLevel.ERROR) { console.error(prefix, ...args) } else if (level === LogLevel.WARN) { console.warn(prefix, ...args) } else { console.log(prefix, ...args) } // 实时日志通道:仅 WARN 及以上,避免击穿配额 if (!LOG_TO_REALTIME || level < LogLevel.WARN) return const manager = getRealtimeManager() if (!manager) return const text = `${prefix} ${stringify(args)}` try { if (level === LogLevel.ERROR && typeof manager.error === 'function') manager.error(text) else if (typeof manager.warn === 'function') manager.warn(text) } catch (e) { // 日志写入失败不影响业务 } } export const logger = { /** 开发期流程细节:页面入参、请求发起/成功、数据条数 */ debug(module: string, ...args: any[]): void { emit(LogLevel.DEBUG, module, args) }, /** 关键流程节点:登录成功、刷新成功、下单/上传/分享成功 */ info(module: string, ...args: any[]): void { emit(LogLevel.INFO, module, args) }, /** 可恢复异常与静默降级:静默 catch、跳转失败、非关键请求失败 */ warn(module: string, ...args: any[]): void { emit(LogLevel.WARN, module, args) }, /** 真正的错误:网络异常、业务错误码、账号禁用、登录态失效 */ error(module: string, ...args: any[]): void { emit(LogLevel.ERROR, module, args) }, } export default logger