1. 概述

本文将演示如何在 Java 中使用 SLF4J 日志门面 API 来记录异常。我们将采用 slf4j-simple 作为底层日志实现。

如果你对更多日志技术感兴趣,可以参考我们之前的日志专题文章。

⚠️ 注意:本文重点在于异常的正确记录方式,而不是日志框架的配置或选型。踩坑最多的往往不是技术本身,而是怎么用。


2. Maven 依赖

要使用 SLF4J,首先需要引入以下两个核心依赖:

<dependency>                             
    <groupId>org.slf4j</groupId>         
    <artifactId>slf4j-api</artifactId>   
    <version>1.7.30</version>  
</dependency> 
                       
<dependency>                             
    <groupId>org.slf4j</groupId>         
    <artifactId>slf4j-simple</artifactId>
    <version>1.7.30</version>  
</dependency>

✅ 推荐:始终在 Maven Central 上检查最新版本,避免使用过时依赖。

✅ 提示:生产环境通常不会用 slf4j-simple,而是桥接到 Logback 或 Log4j2。这里只是为了演示简洁。


3. 异常记录示例

SLF4J 的 Logger 接口提供了多个 error() 方法重载,用于处理不同场景下的异常记录。最常用的有以下三种形式:

void error(String msg);
void error(String format, Object... arguments);
void error(String msg, Throwable t);

3.1 初始化 Logger

标准写法,每个类都应有自己的 Logger 实例:

Logger logger = LoggerFactory.getLogger(ExceptionLoggingExample.class);

3.2 只记录错误信息 ❌(不推荐)

logger.error("An exception occurred!");

输出结果:

ERROR com.example.ExceptionLoggingExample - An exception occurred!

⚠️ 问题:没有堆栈信息!这种写法等于白记,出了问题根本没法定位。

3.3 正确记录异常 ✅(推荐)

必须把异常对象作为第二个参数传入:

logger.error("An exception occurred!", new Exception("Custom exception"));

输出结果:

ERROR com.example.ExceptionLoggingExample - An exception occurred!
java.lang.Exception: Custom exception
  at com.example.ExceptionLoggingExample.main(ExceptionLoggingExample.java:15)

✅ 关键点:

  • 异常的完整堆栈被打印
  • 错误上下文清晰(消息 + 异常)
  • 调试时可以直接定位到出错行

3.4 带参数的格式化日志 + 异常 ✅

当需要动态拼接日志内容时,使用占位符 {}

logger.error("{}, {}! An exception occurred!", 
  "Hello", 
  "World", 
  new Exception("Custom exception"));

输出结果:

ERROR com.example.ExceptionLoggingExample - Hello, World! An exception occurred!
java.lang.Exception: Custom exception 
  at com.example.ExceptionLoggingExample.main(ExceptionLoggingExample.java:20)

⚠️ 重要机制:

  • SLF4J 会自动识别:如果最后一个参数是 Throwable 类型,就把它当作异常处理
  • 前面的 {} 会被前面的 Object... 参数依次替换
  • 不要手动调用 e.toString() 或拼接字符串,否则堆栈丢失!

❌ 常见错误写法(千万别这么干)

// 错误 1:把异常转成字符串
logger.error("Error: " + new Exception("msg")); 

// 错误 2:异常放在中间参数
logger.error("Error: {}, exception: {}", "test", new Exception("msg"));

// 错误 3:用 String.format
logger.error(String.format("Error: %s", "test"), new Exception("msg"));

以上三种写法都会导致:

  • 堆栈信息无法正常输出
  • 或者异常被当成普通参数打印
  • 日志可读性极差

4. 总结

使用 SLF4J 记录异常的关键点总结如下:

正确姿势

  • 使用 error(String msg, Throwable t) 形式
  • 格式化日志时,异常必须是最后一个参数
  • 使用 {} 占位符,避免字符串拼接

避坑指南

  • 不要手动 .toString() 异常
  • 不要把异常放在中间参数位置
  • 不要用 String.format 预处理日志消息

简单粗暴一句话:只要有异常,就把它传给 error 方法的最后一个参数,SLF4J 自动帮你搞定格式和堆栈。

掌握这一点,你的日志才真正具备可调试价值。否则,线上出问题时,日志就是一堆废纸。


原始标题:Logging Exceptions Using SLF4J | Baeldung