10 KiB
10 KiB
name, overview, todos
| name | overview | todos | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 全项目日志补全 + debug/info/warn 分级 | 新建 utils/logger.ts 实现 DEBUG/INFO/WARN/ERROR/SILENT 分级(按 envVersion 自动判定 + config 手动覆盖 + 双输出 console 与 wx.getRealtimeLogManager),然后把 19 个页面、utils、组件、custom-tab-bar 的静默 catch 全部补上分级日志。 |
|
产品概述
为微信小程序「知途衣橱」全项目接入统一的分级日志系统,使开发、体验、生产三种环境下的可观测性可控可调。
核心功能
- 分级日志模块:提供 debug / info / warn / error 四级(外加 SILENT 静默),统一输出格式
[级别][模块名] 消息 - 配置化级别控制:在配置文件中定义日志级别,支持「按环境自动」与「手动写死覆盖」两种模式
- 环境自动映射:develop(开发版)= DEBUG,trial(体验版)= INFO,release(正式版)= WARN
- 双通道输出:console 输出(开发者工具可见)+ 微信实时日志(真机后台「实时日志」可查线上问题)
- 全项目覆盖:17 个页面、请求内核、token 模块、自定义 tab-bar、3 个公共组件,覆盖生命周期、请求成败、用户操作、跳转失败
- 消除静默失败:全部 13 处
.catch(() => {})改为.catch((e) => logger.warn(...))
技术栈
- 微信小程序原生框架 + TypeScript(
miniprogram-api-typings) - 现有工具层:
utils/config.ts(纯常量)、utils/request.ts(请求内核)、utils/auth.ts(token) - 无构建脚本、无本地 TS 编译器,仅依赖 IDE lint 校验
实现方案
核心策略
新建单一日志模块 utils/logger.ts 作为全项目唯一日志出口,所有页面通过 logger.xxx('模块名', ...) 调用;级别策略通过 config.ts 中的 LOG_LEVEL 常量控制。
关键技术决策
决策 1:LogLevel 枚举定义在 config.ts 而非 logger.ts
- 原因:
logger.ts需要 importconfig.ts读取LOG_LEVEL,若枚举定义在 logger 而 config 又要引用它,会形成config → logger → config循环依赖。 - 方案:枚举与配置常量都放
config.ts(本身零依赖的纯常量文件),依赖方向保持单向logger → config。 - 收益:既满足「在配置里分级」的要求,又彻底避免循环依赖。
决策 2:级别用 LogLevel | null 表示,null 代表自动
LOG_LEVEL = null(默认)→ 运行时调wx.getAccountInfoSync().miniProgram.envVersion判定环境- 需要临时调级时改写为
LogLevel.DEBUG等具体值即可,不改代码逻辑
决策 3:实时日志用 wx.getRealtimeLogManager()
- 相比
wx.getLogManager(),实时日志可在小程序后台「实时日志」秒级查询,更适合线上排障 - 单例惰性初始化,取不到时(低版本基础库/开发者工具)降级为仅 console,不抛错
- 实时日志有单条长度限制,参数序列化时截断保护
决策 4:实时日志写入范围限制在 WARN 及以上
- 实时日志有频率与体积配额,DEBUG/INFO 全量上报会击穿配额并产生噪声
- 故:console 输出按级别过滤;实时日志仅 WARN/ERROR 写入
性能与可靠性
- 热路径控制:
request.ts的请求日志放到 debug 级,生产环境(WARN)自动零开销——级别判断前置,不做字符串拼接 - 参数序列化成本:日志消息用
...args原样透传,不主动JSON.stringify大对象;仅在实时日志通道对超长内容截断 - 无额外依赖:不引入任何第三方库,包体积影响可忽略
- 降级安全:
getRealtimeLogManager不可用时静默降级,绝不因日志抛错影响业务
架构设计
graph TD
A[config.ts<br/>LogLevel 枚举 + LOG_LEVEL 配置] --> B[logger.ts<br/>级别过滤 / 格式化 / 双通道输出]
B --> C[console 输出<br/>DEBUG 及以上]
B --> D[wx.getRealtimeLogManager<br/>仅 WARN 及以上]
E[request.ts 请求内核] --> B
F[auth.ts token 模块] --> B
G[17 个页面] --> B
H[custom-tab-bar] --> B
I[3 个公共组件] --> B
依赖方向严格单向:所有业务模块 → logger → config,无反向依赖、无循环依赖。
日志级别语义约定
| 级别 | 用途 | 典型场景 |
|---|---|---|
| DEBUG | 开发期流程细节 | 页面 onLoad/onShow 及入参、请求发起、请求成功、数据条数 |
| INFO | 关键流程节点 | 登录成功、token 刷新成功、下单/支付发起、上传成功、分享创建成功 |
| WARN | 可恢复异常 / 静默降级 | 静默 catch、跳转失败、额度查询失败、非关键请求失败 |
| ERROR | 真正的错误 | 网络异常、业务错误码、账号禁用、登录态失效跳转 |
目录结构
miniprogram/
├── utils/
│ ├── config.ts # [MODIFY] 末尾追加日志配置区块:LogLevel 枚举(DEBUG/INFO/WARN/ERROR/SILENT)、
│ │ # LOG_LEVEL 主开关(null=按环境自动)、LOG_TO_REALTIME 实时日志开关、
│ │ # LOG_MODULE_MAX_LEN 等常量。注意此文件零依赖,不得 import 任何模块。
│ ├── logger.ts # [NEW] 全项目唯一日志出口。实现级别过滤、模块名格式化、双通道输出。
│ │ # 导出 logger.debug/info/warn/error 与 setLevel 运行时调级接口。
│ ├── request.ts # [MODIFY] 迁移现有 10 处 console.log;补全 request/uploadFile 生命周期日志:
│ │ # 请求发起(debug)/成功(debug)/业务错误(warn)/网络异常(error)/
│ │ # 401 刷新(info)/刷新失败(warn)/登录态失效跳转(error)。
│ └── auth.ts # [MODIFY] token 存取关键节点补 debug/warn 日志。
├── pages/ # [MODIFY] 17 个页面全部接入,详见下方任务拆分
├── custom-tab-bar/
│ └── index.ts # [MODIFY] 未读红点轮询、switchTab 跳转、节流命中补日志
└── components/ # [MODIFY] navigation-bar / clothes-card / empty-state 关键回调补日志
关键代码结构
utils/config.ts 追加(零依赖,供 logger 单向引用):
// ===== 日志配置 =====
// 日志级别:数值越大越严重,低于当前级别的日志不输出
export enum LogLevel {
DEBUG = 0,
INFO = 1,
WARN = 2,
ERROR = 3,
SILENT = 4, // 全部关闭
}
// 全局日志级别。null = 按运行环境自动判定(develop=DEBUG / trial=INFO / release=WARN)
// 需要临时调级时直接改写为具体值,例如 LogLevel.DEBUG
export const LOG_LEVEL: LogLevel | null = null
// 是否写入微信实时日志(真机可在后台「实时日志」查看)
export const LOG_TO_REALTIME = true
utils/logger.ts 对外接口(实现体不含):
import { LogLevel, LOG_LEVEL, LOG_TO_REALTIME } from './config'
// 运行时生效级别(LOG_LEVEL 为 null 时按 envVersion 自动推导)
export function getLevel(): LogLevel
export function setLevel(level: LogLevel | null): void
export const logger: {
debug(module: string, ...args: any[]): void
info(module: string, ...args: any[]): void
warn(module: string, ...args: any[]): void
error(module: string, ...args: any[]): void
}
实施注意事项
- 循环依赖红线:
config.ts必须保持零 import,任何需要LogLevel的地方统一从config.ts引入 - 迁移而非新增:现有 24 处
console.log全部改为logger.*,不得遗留裸console.log(保持项目可 grep 性) - 静默 catch 全清:13 处
.catch(() => {})逐个补logger.warn,保留原有降级行为不变,只加观测 - 不动业务逻辑:本次只加观测点与级别控制,不修改任何请求/跳转/状态逻辑,控制变更半径
- 模块名规范:统一用页面目录名或文件名,如
wardrobe、request、custom-tab-bar - 不打印敏感信息:token、code 等只打长度或存在性,不打印完整值
工作量分布
- 基础模块(config + logger):2 个文件
- 内核层(request + auth):2 个文件,约 20+ 个日志点
- 页面层:17 个页面,每页 4-10 个日志点(含 13 处静默 catch)
- 组件与 tab-bar:4 个文件
SubAgent
- code-explorer
- 用途:批量梳理 17 个页面的生命周期方法、请求调用点、跳转 fail 回调与静默 catch 的精确行号,避免逐文件全量读取造成的上下文浪费
- 预期结果:产出各页面待加日志的精确位置清单,作为批量改造的执行依据