日志记录需聚焦问题定位而非制造噪音:记录完整上下文(如用户id、订单号)、使用mdc结构化日志、脱敏敏感信息、按场景分级(error/warn/info)、只在最外层记录一次、避免null异常和printstacktrace、提供可操作线索并正确传递异常对象。

捕获异常后,日志记录不是简单地调用 logger.error("出错了", e) 就完事。关键在于:**让日志能真正帮人快速定位问题根源,而不是制造噪音或掩盖线索**。
记录完整上下文,不只记录异常本身
堆栈跟踪只是“发生了什么”,但排查问题常需知道“在什么情况下发生的”。光有异常对象,往往无法复现或判断影响范围。
- 在
catch块中,显式记录关键业务变量(如用户ID、订单号、请求参数、当前状态等),避免日志里只有“null”或“unknown” - 使用结构化日志框架(如 Logback + SLF4J 的 MDC)提前注入上下文,例如:
MDC.put("userId", userId); MDC.put("orderId", orderId);,后续所有日志自动携带这些字段 - 避免在日志消息中拼接敏感信息(如密码、身份证号),应脱敏后再记录,或仅记录其存在性(如
"userToken present: true")
区分错误级别,避免全用 error
并非所有捕获的异常都代表系统故障。错误级别错用会导致告警疲劳或关键问题被淹没。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
error:用于不可恢复、影响主流程、需人工介入的问题(如数据库连接彻底中断、核心服务不可用) -
warn:用于可预期的异常场景,且已有降级/重试逻辑(如第三方接口超时后走缓存、用户提交了格式错误但已前端校验过的手机号) - 慎用
info记录异常——除非是明确设计的“预期异常流”(如基于异常的协议解析),否则容易掩盖真实问题
避免重复记录和空异常
同一异常在调用链中被多层捕获并多次打印,会污染日志、浪费磁盘、干扰追踪。
- 遵循“**只在最外层或真正处理异常的位置记录一次**”原则。中间层如仅做包装(
throw new ServiceException("业务异常", e)),不应再记日志 - 检查异常对象是否为
null再传给日志方法,防止logger.error("msg", null)导致 NPE 或日志框架静默失败 - 不要用
e.printStackTrace()替代日志记录——它输出到标准错误流,无法统一收集、检索和告警
提供可操作线索,而非仅描述现象
好的错误日志应该让人看到就能想到“下一步该查什么”。
- 在日志消息中说明可能原因或建议动作,例如:
"DB insert failed for order {orderId}: duplicate key. Check if order was already confirmed." - 对常见异常补充简明注释,如
"SocketTimeoutException: likely network instability or upstream slow response" - 确保异常对象被作为最后一个参数传入日志方法(如
logger.error(msg, e)),以保证堆栈完整输出;若用占位符,确认日志框架支持异常自动附加(SLF4J 支持,Log4j2 需注意版本)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










