slf4j日志方法应直接传入异常对象作为最后一个参数,以自动打印完整堆栈;占位符格式中异常必须置于末尾,不可放入占位符;所有throwable子类(含嵌套、自定义异常)均适用;禁止手动处理堆栈。

直接将异常对象作为参数传给日志方法,SLF4J 会自动打印完整堆栈,而不是只输出 e.getMessage()。
正确写法:传入异常对象本身
SLF4J 的日志方法(如 error()、warn()、debug())都支持接收一个 Throwable 类型的最后一个参数。只要把异常对象放在这里,框架就会在日志中输出完整的堆栈跟踪。
- ✅ 正确(打印完整堆栈):
logger.error("数据库查询失败", e); - ❌ 错误(仅打印消息,无堆栈):
logger.error("数据库查询失败: " + e.getMessage()); - ❌ 错误(手动 toString,仍不完整):
logger.error("数据库查询失败", e.toString());
注意占位符与异常参数的位置关系
当使用带占位符的格式化字符串时,异常对象必须作为最后一个参数,且不能放在占位符里。
- ✅ 正确:
logger.error("用户 {} 操作超时,ID={}", username, userId, e); - ❌ 错误(e 被当成普通参数,堆栈不会被识别):
logger.error("用户 {} 操作超时,ID={},异常={}", username, userId, e);
嵌套异常或自定义异常也适用
无论异常是 NullPointerException、SQLException,还是你封装的 BusinessException,只要它继承自 Throwable,SLF4J 都能正确渲染其堆栈。如果重写了 printStackTrace() 或包含 cause,也会一并输出。
- 例如抛出
new BusinessException("余额不足", e),日志中会同时显示业务异常和原始异常的完整链路。
避免手动调用 getStackTrace() 或 printStackTrace()
不要在日志语句中自己处理堆栈,比如:
- ❌ logger.error("错误:" + Arrays.toString(e.getStackTrace()));
- ❌ e.printStackTrace(); // 不走日志系统,可能输出到控制台
这些方式既破坏日志结构,又丢失上下文(如时间、线程、类名),还可能因字符串拼接影响性能(即使日志级别关闭)。










