ES6 class配合装饰器可无侵入实现日志切面——@log声明意图,wrapper捕获参数、返回值与异常,记录traceId、类名、方法名及脱敏后上下文,并需Babel或TS编译支持。

用ES6 class配合装饰器,能干净地把日志逻辑从业务方法里剥离开——不改一行原有代码,就能在方法执行前后自动打日志。关键不是“加功能”,而是“声明意图”:@log 这个标记本身就在说“这个方法需要被追踪”。
装饰器函数要能捕获方法调用全过程
一个实用的日志装饰器,得覆盖前置、执行、后置三个环节,并能拿到参数、返回值和异常信息:
- 用 descriptor.value 保存原始方法,避免丢失上下文
- 在 wrapper 中 try/catch 捕获异常,确保出错时也能记录失败日志
- 记录开始时间,再计算耗时,比单纯打时间戳更有诊断价值
- 对参数做浅拷贝或 JSON 序列化(避免引用污染或循环引用报错)
给类方法加 @log 装饰器,写法要简洁明确
装饰器放在方法前,语义清晰,且只影响目标方法,不影响类其他行为:
- 支持单个方法装饰:
@log async fetchUser(id) { ... } - 也支持批量装饰:用
Object.getOwnPropertyDescriptors遍历原型,统一为所有 public 方法添加 - 避免装饰构造函数或私有字段(#开头),它们不参与方法调用链
日志内容需包含可追溯的上下文标识
全链路日志的核心是“能串起来”,光记时间不够,得有唯一线索:
- 每个请求生成唯一 traceId,通过闭包或全局 context 透传到装饰器内部
- 记录 className 和 methodName,方便快速定位来源(例如
UserService.fetchUser) - 区分日志级别:进入用 info,异常用 error,耗时过长用 warn(比如 >500ms)
- 敏感字段如密码、token 要自动脱敏,不依赖业务代码手动处理
实际运行前必须配好 Babel 或 TypeScript 支持
ES6 装饰器目前仍是提案阶段,浏览器原生不支持,必须编译转换:
- Babel 需启用
@babel/plugin-proposal-decorators,并设legacy: true兼容旧版语义 - TypeScript 中打开
"experimentalDecorators": true和"emitDecoratorMetadata": true - 装饰器函数本身要导出,确保能被其他模块 import 使用,不要写成内联匿名函数


















