清晰的异常日志规范要求每条ERROR日志必须包含时间戳、错误级别、错误码、简明错误信息和完整堆栈五要素,并通过MDC增强上下文,区分业务/系统/参数异常的日志粒度,严禁堆栈丢失、敏感信息泄露及级别错用。

清晰的异常日志规范不是记下“出错了”,而是让看到日志的人三秒内知道:谁在什么时间、什么上下文、调用了什么接口、因为哪类问题、触发了哪个错误码、堆栈关键在哪。核心是结构化、可追溯、不冗余。
必须包含的5个基础字段
每条ERROR级别日志至少携带以下信息,缺一不可:
-
时间戳:精确到毫秒,格式如
2026-09-24 12:38:05.123 -
错误级别:统一用
ERROR(业务异常可用WARN,但需明确区分) -
错误码:5位字符串,如
B0027(B=本系统,0027=编号),不拼接业务参数 -
简明错误信息:一句话说明问题本质,例如
"库存扣减失败:商品ID=10023,当前剩余0",不含堆栈 -
完整堆栈:必须以
log.error("msg", e)形式传入 Throwable 对象,否则堆栈丢失
上下文增强:让日志自带“现场感”
单靠异常本身无法定位问题,需绑定请求或任务上下文:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- Web请求场景:通过 MDC 注入
traceId、requestId、userId、uri、method - 定时任务/异步线程:注入
jobName、taskId、threadName - 日志格式示例:
[2026-09-24 12:38:05.123][traceId=abc123][uri=/api/order/pay][B0027] 库存扣减失败:商品ID=10023,当前剩余0
分层记录策略:避免日志污染又不丢关键信息
不同异常类型日志粒度要差异化:
-
业务异常(如 BusinessException、ValidationException):用
WARN级别,只记录错误码 + 简明信息 + 上下文,不打印堆栈 -
系统异常(如 NullPointerException、SQLException、ConnectException):用
ERROR级别,必须带完整堆栈,并额外记录环境标识(如env=prod) -
参数校验异常(MethodArgumentNotValidException 等):提取首个字段错误提示,格式统一为
"参数校验失败:[手机号]不能为空",不暴露内部字段名
禁止行为清单
这些写法看似省事,实则让日志失去价值:
- 只写
log.error(e.toString())—— 堆栈全丢,等于没记 - 在 catch 块里写
e.printStackTrace()—— 不走日志框架,无法集中收集和告警 - 把用户敏感信息(身份证、手机号明文、token)直接拼进日志消息
- 用
log.info("发生异常")代替log.error—— 级别错,监控告警失效 - 错误码硬编码在日志字符串里(如
"B0027: 库存不足"),而非作为独立字段结构化输出

















