整合日志框架log4j2

其实我们之前就一直在用日志框架了,只不过spring boot为我们整合好了默认的日志框架的实现。我们通过Lombok框架提供的日志相关的注解再配合编辑器的插件,直接用的内置对象log进行日志api的调用。然后日志默认在控制台打印输出。

现在我们将对日志框架做进一步的定制,我们希望日志可以输出到文件中保存起来,方便我们日后排查问题。废话不多说,开干!

引入依赖

因为spring boot默认会包含spring-boot-starter-logging依赖,其中使用logback的日志实现,现在我们要用log4j2,则需要在它所有的依赖中,都将这个模块排除,一个最简单的排除方式:

groovy 复制代码
configurations {
    all*.exclude module: 'spring-boot-starter-logging'
    ...
}

同时还要引入如下依赖:

groovy 复制代码
dependencies {
    ...
    implementation 'org.springframework.boot:spring-boot-starter-log4j2'
}

日志配置

接下来我们需要在resources资源包下新建一个log4j2.xml文件,在其中配置日志:

日志级别

日志的级别优先级从高到低:

  • OFF

  • FATAL(导致应用退出的重大错误)

  • ERROR(不影响系统继续运行的错误)

  • WARN

  • INFO

  • DEBUG

    调试程序输出的信息

  • TRACE

    输出调用栈中每一步的详细的跟踪日志

  • ALL

    打印所有的日志

配置结构

现在我们写一个日志配置的基本结构:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!-- status记录的是log4j在抓取和输出日志过程中自身输出的日志级别,这里输出fatal以及以上优先级的级别的日志 -->
<configuration status="fatal">
    <Properties>
        <!-- 这里定义被下面配置引用的常量 -->
    </Properties>

    <Appenders>
        <!-- 用于向控制台输出日志 -->
        <Console name="consoleLog" target="SYSTEM_OUT">

        </Console>

        <!-- 向文件输出日志,这里可以配置不同的日志级别输出到不同的日志文件中 -->
        <RollingFile name="fileInfoLog">

        </RollingFile>

        <!-- error级别日志文件输出 -->
        <RollingFile name="fileErrorLog">

        </RollingFile>

        <!-- 异步日志记录器,在写文件时实现异步写入,提高程序执行性能 -->
        <Async name="myAsync">
            <AppenderRef ref="fileInfoLog"/>
            <AppenderRef ref="fileErrorLog"/>
        </Async>

    </Appenders>

    <loggers>
        <!-- 配置程序各个模块(包)所使用的日志记录器以及配置日志输出的级别 -->
        <!-- 所有模块继承的默认设置,子模块可以覆盖 -->
        <Root level="warn">
            <AppenderRef ref="consoleLog"/>
        </Root>
        <!-- 对我们的应用指定日志输出级别为info,并且从根设置继承,支持控制台输出,默认additivity为true -->
        <logger name="com.juan" level="info" additivity="true">
            <AppenderRef ref="myAsync"/>
        </logger>
    </loggers>
</configuration>

日志文件输出路径

这里我们把要输出的日志文件的路径设置为一个常量,值表示的是相对于项目根路径的路径,这里我们设置为本地开发运行、测试时和项目同一层级的logs目录下:

xml 复制代码
<Properties>
    <!-- 这里定义被下面配置引用的常量 -->
    <Property name="LOG_HOME" value="../logs"/>
</Properties>

日志Layout

对于输出到文件中的日志格式,我们也定义在常量中:

xml 复制代码
<Properties>
    ...
    <Property name="File_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %6p %5pid --- [%15.15t] %-40.40logger{39}: %m%n"/>
</Properties>

关于这里的格式可以参考logback的官方文档layout章节,因为格式方面日志框架基本相通的,且logback这方面文档写的更好。

控制台日志

现在我们div控制台日志的输出风格,这里下卷直接给出一个仿spring boot控制台默认的输出风格的布局:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="fatal">

    <Appenders>
        <!-- 用于向控制台输出日志 -->
        <Console name="consoleLog" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight{%6p} %style{%5pid}{bright,magenta} --- [%15.15t] %style{%-40.40logger{39}}{bright,cyan}: %highlight{%m%n}{INFO=BLACK, DEBUG=BLACK}" disableAnsi="false"/>
        </Console>

    </Appenders>

    <loggers>
        <Root level="info">
            <AppenderRef ref="consoleLog"/>
        </Root>
    </loggers>
</configuration>

按照以上配置后,小伙伴们可以自行运行一个单元测试来看看控制台的输出效果。

文件日志配置

接下来我们再来完善下文件的日志配置,这里我们将输出到文件中的日志分为两类:info日志和error日志。我们主要来看下info日志文件的配置,error的则类似。

xml 复制代码
<!-- 向文件输出日志,这里可以配置不同的日志级别输出到不同的日志文件中 -->
<RollingFile name="fileInfoLog" fileName="${LOG_HOME}/info.log" filePattern="${LOG_HOME}/$${date:yyyy-MM-dd}/info_%i.%d{yyyy-MM-dd-HH}.log" append="true">
    <!-- 过滤器 -->
    <Filters>
        <!--只接受info级别的日志,其它全部拒绝掉-->
        <ThresholdFilter level="INFO"/>
        <ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/>
    </Filters>
    <!-- 日志格式 -->
    <PatternLayout pattern="${File_LOG_PATTERN}"/>
    <!-- 策略 -->
    <Policies>
        <!-- 每隔一天转存 -->
        <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
        <!-- 文件大小 -->
        <SizeBasedTriggeringPolicy size="10 MB"/>
    </Policies>
    <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始自动清理-->
    <DefaultRolloverStrategy max="10">
        <Delete basePath="${LOG_HOME}/$${date:yyyy-MM-dd}/" maxDepth="2">
            <IfFileName glob="*/*.log" />
            <!--7天-->
            <IfLastModified age="168H" />
        </Delete>
    </DefaultRolloverStrategy>
</RollingFile>

这里的fileName指定的是当前日志的输出路径,filePattern则是被转储后的文件路径,这里我们会以日期来划分子目录,并且文件的写入形式为追加,而不是覆盖(append="true"控制,默认为true),当一个文件写满了(达到<SizeBasedTriggeringPolicy>配置的大小)后,再按照命名中的%i以索引自增的方式,生成新的文件,也就是我们说的日志滚动,这里我们指定了日志滚动的大小为10 MB。最后我们还指定了日志文件的清理策略。

error日志的配置类似,处理文件命名,还有过滤的规则不一样:

xml 复制代码
<Filters>
    <!-- 只考虑error级别 -->
    <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>

然后,我们为文件日志配置异步记录器:

xml 复制代码
<Async name="myAsync">
    <AppenderRef ref="fileInfoLog"/>
    <AppenderRef ref="fileErrorLog"/>
</Async>

并为我们的小卷生鲜应用模块(包)指定下要记录的日志级别和记录器:

xml 复制代码
<logger name="com.xiaojuan" level="info">
    <AppenderRef ref="myAsync"/>
</logger>

示例配置

最后为了方便小伙伴们练习,小卷给出完整的日志配置文件:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!-- status记录的是log4j在抓取和输出日志过程中自身输出的日志级别,这里输出fatal以及以上优先级的级别的日志 -->
<configuration status="fatal">
    <Properties>
        <!-- 这里定义被下面配置引用的常量 -->
        <Property name="LOG_HOME" value="../logs"/>
        <Property name="File_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %6p %5pid --- [%15.15t] %-40.40logger{39}: %m%n"/>
    </Properties>

    <Appenders>
        <!-- 用于向控制台输出日志 -->
        <Console name="consoleLog" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight{%6p} %style{%5pid}{bright,magenta} --- [%15.15t] %style{%-40.40logger{39}}{bright,cyan}: %highlight{%m%n}{INFO=BLACK, DEBUG=BLACK}" disableAnsi="false"/>
        </Console>

        <!-- 向文件输出日志,这里可以配置不同的日志级别输出到不同的日志文件中 -->
        <RollingFile name="fileInfoLog" fileName="${LOG_HOME}/info.log" filePattern="${LOG_HOME}/$${date:yyyy-MM-dd}/info_%i.%d{yyyy-MM-dd-HH}.log" append="true">
            <!-- 过滤器 -->
            <Filters>
                <!--只接受info级别的日志,其它全部拒绝掉-->
                <ThresholdFilter level="INFO"/>
                <ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <!-- 日志格式 -->
            <PatternLayout pattern="${File_LOG_PATTERN}"/>
            <!-- 策略 -->
            <Policies>
                <!-- 每隔一天转存 -->
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <!-- 文件大小 -->
                <SizeBasedTriggeringPolicy size="10 MB"/>
            </Policies>
            <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始自动清理-->
            <DefaultRolloverStrategy max="10">
                <Delete basePath="${LOG_HOME}/$${date:yyyy-MM-dd}/" maxDepth="2">
                    <IfFileName glob="*/*.log" />
                    <!--7天-->
                    <IfLastModified age="168H" />
                </Delete>
            </DefaultRolloverStrategy>
        </RollingFile>

        <!-- error级别日志文件输出 -->
        <RollingFile name="fileErrorLog" fileName="${LOG_HOME}/error.log" filePattern="${LOG_HOME}/$${date:yyyy-MM-dd}/error_%i.%d{yyyy-MM-dd-HH}.log" append="true">
            <!-- 过滤器 -->
            <Filters>
                <!-- 只考虑error级别 -->
                <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
            </Filters>
            <!-- 日志格式 -->
            <PatternLayout pattern="${File_LOG_PATTERN}"/>
            <Policies>
                <!-- 每隔一天转存 -->
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <!-- 文件大小 -->
                <SizeBasedTriggeringPolicy size="10 MB"/>
            </Policies>
            <DefaultRolloverStrategy max="10">
                <Delete basePath="${LOG_HOME}/$${date:yyyy-MM-dd}/" maxDepth="2">
                    <IfFileName glob="*/*.log" />
                    <!--7天-->
                    <IfLastModified age="168H" />
                </Delete>
            </DefaultRolloverStrategy>
        </RollingFile>

        <!-- 异步日志记录器,在写文件时实现异步写入,提高程序执行性能 -->
        <Async name="myAsync">
            <AppenderRef ref="fileInfoLog"/>
            <AppenderRef ref="fileErrorLog"/>
        </Async>

    </Appenders>

    <loggers>
        <!-- 配置程序各个模块(包)所使用的日志记录器以及配置日志输出的级别 -->
        <!-- 所有模块继承的默认设置,子模块可以覆盖 -->
        <Root level="debug">
            <AppenderRef ref="consoleLog"/>
        </Root>
        <logger name="org.springframework" level="info">

        </logger>
        <logger name="org.mybatis" level="info">

        </logger>
        <!-- 对我们的应用指定日志输出级别为info,并且从根设置继承,支持控制台输出,默认additivity为true -->
<!--        <logger name="com.xiaojuan" level="info" additivity="true">-->
        <logger name="com.xiaojuan" level="info">
            <AppenderRef ref="myAsync"/>
        </logger>
    </loggers>
</configuration>

注意

最后为了查看spring boot整合的框架启动的debug信息,我们可以将Root级别设置为debug,这样很多框架都会打印debug信息。我们可以将不要打印debug信息的框架(包)的日志级别设置为info

一般来说,我们开发不关心debug日志输出,推荐设置为下面的配置:

xml 复制代码
<loggers>
    <Root level="info">
        <AppenderRef ref="consoleLog"/>
    </Root>
    <logger name="com.xiaojuan">
        <AppenderRef ref="myAsync"/>
    </logger>
</loggers>
相关推荐
用户908324602731 小时前
Spring AI 1.1.2 + Neo4j:用知识图谱增强 RAG 检索(上篇:图谱构建)
java·spring boot
用户83071968408221 小时前
Spring Boot 集成 RabbitMQ :8 个最佳实践,杜绝消息丢失与队列阻塞
spring boot·后端·rabbitmq
Java水解1 天前
Spring Boot 视图层与模板引擎
spring boot·后端
Java水解1 天前
一文搞懂 Spring Boot 默认数据库连接池 HikariCP
spring boot·后端
洋洋技术笔记1 天前
Spring Boot Web MVC配置详解
spring boot·后端
初次攀爬者2 天前
Kafka 基础介绍
spring boot·kafka·消息队列
用户8307196840822 天前
spring ai alibaba + nacos +mcp 实现mcp服务负载均衡调用实战
spring boot·spring·mcp
Java水解2 天前
SpringBoot3全栈开发实战:从入门到精通的完整指南
spring boot·后端
初次攀爬者3 天前
RocketMQ在Spring Boot上的基础使用
java·spring boot·rocketmq
花花无缺3 天前
搞懂@Autowired 与@Resuorce
java·spring boot·后端