Java基础 - 日志

日志

日志级别:

  1. TRACE: log.trace() 最详细的日志(几乎每一行代码都记录),不常用,只在本地调试
  2. DEBUG: log.debug() 调试用的信息,比如变量值、函数调用,但一般只在开发环境用
  3. INFO: log.info() 一般性的信息,比如“服务启动成功”、“任务完成”,生产环境常用
  4. WARN: log.warn() 警告,程序还能运行,但可能有问题,一定要看
  5. ERROR: log.error() 严重错误,比如连接失败、抛异常,非常重要
  6. FATAL: log.fatal() 致命错误,程序无法继续,较少用,一般跟 error 同级别处理

在配置文件里可以设置希望打印的日志级别,比如log4j.rootLogger=INFO, console(只打印 INFO 及以上级别的日志,DEBUG 就不打印)。

log4j

Log4j 是一个流行的 Java 日志框架。Log4j 1.x 已经停止维护,不推荐使用。以下介绍 log4j 2.x。

如何使用

配置文件 src/main/resources/log4j2.xml,用于定义日志的配置。主要包含两大部分:

  1. <Appenders>:用于定义输出目的地,以及其对应的输出格式等。
  2. <Loggers>:用于配置不同类/包的日志级别和使用哪些 Appenders。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?xml version="1.0" encoding="UTF-8"?>
<!-- status 是 Log4j 自身的内部日志输出等级,用于调试 Log4j 配置是否生效。Log4j 会用这个等级输出警告信息到控制台 -->
<Configuration status="WARN">
<Properties>
<Property name="logPath" value="/home/logs"/>
</Properties>

<Appenders>
<!-- 控制台输出,name 用于下面 AppendRef 引用 -->
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="[%d{HH:mm:ss}] [%t] %-5level %c - %msg%n" />
</Console>

<!-- 文件输出 -->
<RollingFile name="FileLogger" fileName="${logPath}/app.log" filePattern="logs/app-%d{yyyy-MM-dd}.log">
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss}] [%t] %-5level: %msg%n" />
<!-- 定义触发日志滚动的策略 -->
<Policies>
<!-- 表示每隔 1 天滚动一次, -->
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies>
</RollingFile>
</Appenders>

<!-- Loggers 用于配置不同类/包的日志级别和使用哪些 Appenders。 -->
<Loggers>
<!-- 设置某个包或类的日志级别 -->
<!-- 仅对 com.example 包下的类生效 -->
<Logger name="com.example.main" level="debug" additivity="false">
<AppenderRef ref="Console" />
</Logger>

<!-- 这个Logger没有定义AppendRef,但是定义了level,这里用于限制该包的DEBUG日志不输出 -->
<!-- 虽然没绑定AppendRef,但是由于Additivity,会交给上级(Root)处理 -->
<Logger name="com.example.util" level="info"></Logger>

<!-- 设置根日志输出,所有没有单独定义 Logger 的类,都会使用这个根 Logger。 -->
<Root level="debug">
<!-- 引用上面定义的 Appender -->
<AppenderRef ref="Console" />
<AppenderRef ref="FileLogger" />
</Root>
</Loggers>
</Configuration>

语法解释:

  • <Properties>:用于在配置文件中定义变量,这些变量可以在后续的配置元素中被引用。

  • <RollingFile>:用于配置 日志文件滚动,即当日志文件达到一定条件时,自动进行日志切割(例如:按大小、按日期等)。

  • <Policies>:定义触发日志滚动的策略

    • TimeBasedTriggeringPolicy:按时间滚动
    • SizeBasedTriggeringPolicy:按日志文件大小滚动
  • <PatternLayout>:用于设置日志输出格式,比如<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%t] %-5p [%c{2}] [%X{requestId}] - %m%n" />的输出示例为:[2025-07-20 13:47:15.324] [main] INFO [MyService] [abc123] - 用户登录成功。

    • %d{HH:mm:ss}:时:分:秒
    • %t:当前线程名字
    • %–5p:等价于%-5level,以5个字符宽度,左对齐的格式来输出日志级别,比如INFO,ERROR等。
    • %m:日志消息内容,就是代码中写的那段文字
    • %c{2}%c是日志记录器的名称,通常是当前类的全限定名,{2}表示只输出“类名的最后两级”(包名 + 类名),比如:com.example.app.MyService,那么{2}代表app.MyService{1}代表MyService
    • %X{requestId}:输出MDC(Mapped Diagnostic Context)中的键值对,MDC由ThreadContext定义。这里输出ThreadContext中的requestId。
  • <Loggers>:标签用于定义特定包、类或者模块的日志设置。它可以用来调整日志级别和指定该日志使用的输出目标。

    • name:指定要配置的日志器的名称,通常是包名或类名。
    • additivity:表示日志是否向上传递到上级 Logger(通常是 Root Logger)继续输出。additivity="true",向上传递,会输出多次。additivity="false":不向上传递,只在当前 Logger 配置的 Appender 中输出一次。
    • AppenderRef:指定日志的输出目的地。一个 <Logger> 下可能有多个 AppenderRef,说明该包/类的日志会输出到多个目的地。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;

public class MyService {
private static final Logger logger = LogManager.getLogger(MyService.class);

public void login(String userId) {
ThreadContext.put("requestId", userId); // 设置上下文变量
logger.info("用户登录成功");
ThreadContext.clearAll(); // 清理
}
}

Commons Logging

Commons Logging 是 Apache 提供的一个轻量级日志抽象层,它并不实际提供日志实现,而是提供了一个统一的接口来调用不同的日志框架。在大型项目或类库中,如果直接使用 Log4j、JUL、SLF4J 等具体实现,会导致项目之间耦合太强、灵活性差。而使用 Commons Logging 可以做到代码不依赖具体的日志实现,可以切换日志底层实现。Commons Logging 会自动绑定到 Log4j,当它在 classpath 中找到 log4j.jar 时,Commons Logging 会选择 Log4j 作为底层日志实现。

1
2
3
4
5
6
7
8
9
10
11
12
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class MyApp {
private static final Log log = LogFactory.getLog(MyApp.class);

public static void main(String[] args) {
log.info("程序开始运行");
log.warn("这是一个警告");
log.error("发生了错误");
}
}

SLF4J

类似 Commons Logging,但更加现代、稳定。它提供的是一组统一的日志接口(API),本身不处理日志的输出,而是将日志调用委托给具体的日志实现(如 Logback、Log4j2、JUL 等)来完成。

1
2
3
4
5
6
7
8
9
10
11
12
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HelloSLF4J {
private static final Logger logger = LoggerFactory.getLogger(HelloSLF4J.class);

public static void main(String[] args) {
String name = "Eric";
logger.info("My name is {}", name);
logger.info("Hello, SLF4J!");
}
}

绑定器

在一个项目中只使用一个日志实现库,避免多个日志框架共同参与日志处理。

slf4j-log4j12

slf4j-log4j12 是 SLF4J 提供的一个绑定器,它的作用是把 SLF4J 的日志调用转发给 Log4j 1.x 实现。只要这个绑定器在你的 classpath 中,所有使用 SLF4J 打的日志(包括你和你引入的库)就都会被转发到 Log4j,并使用你项目里的 log4j.properties 或 log4j.xml 配置输出。

由于Logback 是 SLF4J 的原生实现,如果想要使用 SLF4J 作为日志门面,并使用 Log4j 作为底层日志实现,必须需要这个绑定器。

log4j-slf4j-impl

Log4j 2 提供的官方 SLF4J 绑定器,用于将所有 SLF4J API 的日志调用转发到 Log4j2 实现。


Java基础 - 日志
https://thiefcat.github.io/2025/07/16/JAVA/java-log/
Author
小贼猫
Posted on
July 16, 2025
Licensed under