SSM 日志框架集成:Logback/Log4j2 与 SLF4J 在 SSM 中的配置

SSM 日志框架集成:Logback/Log4j2 与 SLF4J 的完美协奏曲

各位观众老爷们,今天咱们不聊风花雪月,专攻技术,聊聊Java Web开发中不可或缺的好伙伴——日志框架。想象一下,没有日志,线上出了问题就像盲人摸象,两眼一抹黑,debug全靠猜。所以,选对、用好日志框架,绝对是程序员进阶的必修课。

今天的主角是SSM框架(Spring + SpringMVC + MyBatis),以及两位日志界的大佬:Logback 和 Log4j2,当然,还有一位隐藏的指挥家:SLF4J。咱们要做的,就是把这三位完美地融合在一起,奏响一曲优美的日志协奏曲。

为什么要用SLF4J?

在深入Logback和Log4j2之前,我们先来聊聊SLF4J(Simple Logging Facade for Java)。它就像一个接口,一个门面,允许你随意切换底层的日志实现,而无需修改大量的代码。 想象一下,你一开始用的是Log4j,后来发现Logback更适合你,如果直接使用Log4j的API,那就得把所有用到org.apache.log4j.*的地方都改成ch.qos.logback.*,想想就头大。

而SLF4J的出现,就解决了这个问题。你只需要面向SLF4J的接口编程,然后在配置文件中指定使用Logback或者Log4j2,切换起来就像换了个皮肤一样简单。

Logback:优雅的后起之秀

Logback是Log4j的作者Ceki Gülcü的另一个作品,它号称是Log4j的继任者,拥有更快的速度、更灵活的配置和更简洁的架构。Logback原生支持SLF4J,集成起来非常方便。

Log4j2:性能怪兽的逆袭

Log4j2是Apache基金会的作品,它重写了Log4j,在性能上有了质的飞跃。它使用了异步日志记录,可以显著降低对应用程序性能的影响。Log4j2也支持SLF4J,但需要一些额外的配置。

好了,理论知识就到这里,接下来咱们进入实战环节!

一、Logback + SLF4J 的集成

  1. 添加依赖:

首先,在你的pom.xml文件中添加以下依赖:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.36</version> <!-- 确保使用最新的稳定版本 -->
</dependency>

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.11</version> <!-- 确保使用最新的稳定版本 -->
    <scope>runtime</scope>
</dependency>

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version> <!-- 你的Servlet版本 -->
    <scope>provided</scope>
</dependency>
  • slf4j-api: SLF4J 的 API 接口,所有日志调用都面向这个接口。
  • logback-classic: Logback 的核心实现,包含了 Logback 的核心类和 SLF4J 的绑定。
  • javax.servlet-api: 这个依赖是用于Web项目的,如果你不是Web项目,可以忽略。
  1. 配置 Logback:

src/main/resources目录下创建一个名为logback.xml的文件。这是Logback的配置文件,你可以在其中定义日志的级别、输出格式、输出目的地等等。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 定义日志存放路径 -->
    <property name="LOG_HOME" value="logs" />

    <!-- 控制台输出 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 文件输出 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME}/myapp.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_HOME}/myapp.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory> <!-- 保留30天的日志 -->
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 异步文件输出 -->
    <appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="FILE" />
    </appender>

    <!-- 设置日志级别和Appender -->
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="ASYNC_FILE" />
    </root>

    <!-- 特定包的日志级别 -->
    <logger name="com.example.myapp" level="DEBUG" additivity="false">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="ASYNC_FILE" />
    </logger>
</configuration>
  • <configuration>: 根元素,所有配置都放在这里面。
  • <property>: 定义变量,方便在配置文件中使用。比如,这里定义了日志存放的路径LOG_HOME
  • <appender>: 定义日志的输出目的地。
    • CONSOLE: 输出到控制台。
    • FILE: 输出到文件。使用RollingFileAppender可以按时间滚动日志文件。
    • ASYNC_FILE: 异步输出到文件,可以提高性能。
  • <encoder>: 定义日志的输出格式。
    • %d{yyyy-MM-dd HH:mm:ss.SSS}: 日期和时间。
    • [%thread]: 线程名。
    • %-5level: 日志级别。
    • %logger{36}: Logger 的名字,最多显示36个字符。
    • %msg%n: 日志消息和换行符。
  • <root>: 定义根 Logger 的级别和 Appender。
  • <logger>: 定义特定包的 Logger 的级别和 Appender。additivity="false"表示这个 Logger 不会把日志传递给根 Logger。
  1. 使用 SLF4J 记录日志:

在你的Java代码中,使用SLF4J的API来记录日志。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MyService {

    private static final Logger logger = LoggerFactory.getLogger(MyService.class);

    public void doSomething() {
        logger.debug("This is a debug message.");
        logger.info("This is an info message.");
        logger.warn("This is a warning message.");
        logger.error("This is an error message.");

        try {
            int result = 10 / 0; // 模拟异常
        } catch (Exception e) {
            logger.error("An exception occurred:", e);
        }
    }
}
  • 首先,通过LoggerFactory.getLogger(MyService.class)获取一个Logger实例。
  • 然后,就可以使用logger.debug(), logger.info(), logger.warn(), logger.error()等方法来记录不同级别的日志。

二、Log4j2 + SLF4J 的集成

  1. 添加依赖:

在你的pom.xml文件中添加以下依赖:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.36</version> <!-- 确保使用最新的稳定版本 -->
</dependency>

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.17.2</version> <!-- 确保使用最新的稳定版本 -->
</dependency>

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.17.2</version> <!-- 确保使用最新的稳定版本 -->
</dependency>

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.17.2</version> <!-- 确保使用最新的稳定版本 -->
</dependency>

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version> <!-- 你的Servlet版本 -->
    <scope>provided</scope>
</dependency>
  • slf4j-api: 还是 SLF4J 的 API 接口。
  • log4j-slf4j-impl: Log4j2 对 SLF4J 的实现绑定。
  • log4j-api: Log4j2 的 API 接口。
  • log4j-core: Log4j2 的核心实现。
  • javax.servlet-api: 同上。

重要提示:

  • 排除Logback依赖: 如果你的项目中之前已经引入了 Logback 的依赖,一定要排除掉,否则会导致冲突。 可以在pom.xml中添加以下配置:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-log4j2</artifactId>
    </dependency>
  • 添加配置文件:src/main/resources目录下创建一个名为log4j2.xml的文件。
  1. 配置 Log4j2:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Properties>
        <Property name="LOG_HOME">logs</Property>
        <Property name="PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</Property>
    </Properties>
    <Appenders>
        <Console name="ConsoleAppender" target="SYSTEM_OUT">
            <PatternLayout pattern="${PATTERN}"/>
        </Console>
        <RollingFile name="FileAppender" fileName="${LOG_HOME}/myapp.log"
                     filePattern="${LOG_HOME}/myapp.%d{yyyy-MM-dd}.log">
            <PatternLayout pattern="${PATTERN}"/>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
            </Policies>
            <DefaultRolloverStrategy max="30"/>
        </RollingFile>
        <Async name="AsyncFileAppender">
            <AppenderRef ref="FileAppender"/>
        </Async>
    </Appenders>
    <Loggers>
        <Root level="INFO">
            <AppenderRef ref="ConsoleAppender"/>
            <AppenderRef ref="AsyncFileAppender"/>
        </Root>
        <Logger name="com.example.myapp" level="DEBUG" additivity="false">
            <AppenderRef ref="ConsoleAppender"/>
            <AppenderRef ref="AsyncFileAppender"/>
        </Logger>
    </Loggers>
</Configuration>
  • <Configuration>: 根元素,status="WARN"表示 Log4j2 在启动时如果遇到问题,会输出 WARN 级别的日志。
  • <Properties>: 定义变量,和 Logback 类似。
  • <Appenders>: 定义日志的输出目的地。
    • Console: 输出到控制台。
    • RollingFile: 输出到文件,并按时间滚动日志文件。
    • Async: 异步输出,提高性能。
  • <PatternLayout>: 定义日志的输出格式,和 Logback 类似。
  • <Policies>: 定义滚动策略。
    • TimeBasedTriggeringPolicy: 按时间滚动。
  • <DefaultRolloverStrategy>: 定义滚动策略。
    • max: 保留的最大日志文件数量。
  • <Loggers>: 定义 Logger。
    • Root: 根 Logger。
    • Logger: 特定包的 Logger。
  1. 使用 SLF4J 记录日志:

代码和 Logback 一样,无需修改。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MyService {

    private static final Logger logger = LoggerFactory.getLogger(MyService.class);

    public void doSomething() {
        logger.debug("This is a debug message.");
        logger.info("This is an info message.");
        logger.warn("This is a warning message.");
        logger.error("This is an error message.");

        try {
            int result = 10 / 0; // 模拟异常
        } catch (Exception e) {
            logger.error("An exception occurred:", e);
        }
    }
}

三、SSM 框架中的集成

在 SSM 框架中集成日志框架,只需要完成以上步骤即可。Spring 会自动加载src/main/resources目录下的logback.xml或者log4j2.xml文件,并初始化日志框架。

一些最佳实践:

  • 日志级别:
    • TRACE: 最详细的日志,一般用于开发调试。
    • DEBUG: 调试信息,比 TRACE 级别稍微少一些。
    • INFO: 重要信息,比如程序的启动、关闭等。
    • WARN: 警告信息,表示可能存在问题,但不影响程序的正常运行。
    • ERROR: 错误信息,表示程序出现了错误,可能会影响程序的正常运行。
  • 异步日志: 尽可能使用异步日志,可以减少对应用程序性能的影响。
  • 日志格式: 定义清晰的日志格式,方便阅读和分析。
  • 日志文件大小: 合理设置日志文件的大小和数量,避免占用过多的磁盘空间。
  • 敏感信息: 避免在日志中记录敏感信息,比如密码、身份证号等。

总结:

今天我们一起学习了如何在 SSM 框架中集成 Logback 和 Log4j2,并使用 SLF4J 作为统一的日志接口。希望这篇文章能够帮助你更好地使用日志框架,让你的程序更加健壮和易于维护。

记住,日志是程序员的好朋友,善用日志,可以让你在排查问题时事半功倍。 祝各位观众老爷们编码愉快,bug 远离!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注