四、log4j2详解

0 阅读8分钟

一,Log4j2介绍

log4j2是log4j1.x的升级版,2015年5月,Apache宣布log4j1.x停止更新。最新版为1.2.17.

log4j2参考了logback的一些优秀的设计,并且修了一些问题,因此带来了一些重大的提升,主要有:

  1. 异常处理:在logback中,Appender中的异常不会被应用感知到,但是在log4j2中,提供了一些异常处理机制。
  2. 性能提升:log4j2相较于log4j1和logback都具有很明显的性能提升。
  3. 白动重载配置:参考了logback的设计,提供自动刷新参数配置,可以动态的修改日志的级别而不需要重启应用。
  4. 无垃圾机制:log4j2在大部分情况下,都可以使用其设计的一套无垃圾机制,避免频繁的日志收集导致的jvm gc。

log4j2.x版本不再支持像1.x中的**.properties后缀的文件配置方式,2.x版本常用.xml后缀的文件进行配置**,除此之外还包含**.json.jsn**配 置文件

log4j2虽然采用xml风格进行配置,依然包含三个组件,分别是

  • Logger(记录器)

  • Appender(输出目的地)

  • Layout(日志布局)。

配置文件的位置::log4j2默认会在classpath目录下寻找log4j2.xmllog4j.json、log4j.jsn等名称的文件。

二,XML配置详解

  1. 根节点Configuration

    有两个属性:

    • status:指定log4j本身的打印日志的级别
    • montiorinterval:log4j2新特点,自动重载配置,指定自动重新配置的监测时间间隔,单位是s,最小是5s

    有两个子节点:(都可定义多个)

    • Appenders
    • Loggers
  2. Appenders节点:常见有三种子节点:

    1. Console:输出到控制台
    2. File:输出到文件
    3. RollingFile:定义超过指定大小自动删除旧的创建新的文件

    在子节点中加入:

    <PatternLayout pattern="自定义信息格式"/>
    

    进行日志的布局

    image-20240615204140240

  3. Loggers节点:常见的有

    1. Root:用来指定项目的根日志,如果没有单独指定Logger,那么就会默认使用该Root日志输出
    2. Logger:用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。

三,Log4j2快速入门

  1. 导包

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-log4j2</artifactId>
    </dependency>
    

    在导包时注意如果导入了jdbc那么就需要排除其中logging依赖要不然会出现警告

  2. 添加yaml配置

    logging:
      config: classpath:logback.xml
    
  3. 创建配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration>
        <!--配置一些公共属性引用-->
        <properties>
        </properties>
        <!--配置所有的Appenders-->
        <Appenders>
        </Appenders>
        <!--配置Loggers-->
    </Configuration>
    
  4. 运行:

    package com.ruoyi.springbootdemo;
    
    import org.junit.jupiter.api.Test;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    
    @SpringBootTest
    class SpringBootDemoApplicationTests {
        public static final Logger LOGGER = LogManager.getLogger(SpringBootDemoApplicationTests.class);
        @Test
        void test() {
            // 日志消息输出
            LOGGER.fatal("fatal");
            LOGGER.error("error");
            LOGGER.warn("warn");
            LOGGER.info("inf");
            LOGGER.debug("debug");
            LOGGER.trace("trace");
        }
    
    }
    
  • 也可以通过搭配lombok使用

    @Slf4j
    @SpringBootTest
    class SpringBootDemoApplicationTests {
    
        @Test
        void test() {
            // 日志消息输出
            log.fatal("fatal");
            log.error("error");
            log.warn("warn");
            log.info("inf");
            log.debug("debug");
            log.trace("trace");
        }
    
    }
    

四,xml详解

4.1 Configuration标签

根节点Configuration中有两个常用的属性:statusmonitorterval。如:<Configuration status="WARN" monitorInterval="30">

属性:

  1. status:是用于指定log4j的级别;
  2. monitorterval:是用于指定log4j自动重新检测读取配置内容的间隔时间,单位为秒(s),最小值为5秒。

4.2 Properties标签

<properties>
    <property name="LOG_HOME">./service-logs</property>
</properties>

变量配置,如上述代码,配置了一个变量名为:LOG_HOME,变量值为:./service-logs的变量。

调用方法:**变量名,举例:{变量名}**,举例:`{LOG_HOME}`

4.3 Appenders标签

Appenders用来设置所有的appender子节点有:

  • Console:输出到控制台

  • File:输出到指定文件

  • RollingFile:基于指定策略实现日志文件滚动

4.3.1 Console

Console节点用于定义输出控制台的Appender。

属性:

  1. name:用于指定Appender的名称;
  2. target:用于指定输出目标,一般是SYSTEM_OUTSYSTEM_ERR,默认是SYSTEM_OUT

子节点:

  • PatternLayout:用于指定输出格式,不设置的话,默认为:%m%n

    • 属性:

      disableAnsi:这个参数控制是否禁用 ANSI 颜色代码。

      noConsoleNoAnsi:这个参数控制是否在没有控制台的情况下禁用 ANSI 颜色代码。

      一般都设置为false用来配合控制台输出自定义颜色的内容

 <Appenders>
    <Console name="STDOUT" target="SYSTEM_OUT">
        <PatternLayout disableAnsi="false" noConsoleNoAnsi="false">
            <Pattern>
                %style{%d{yyyy-MM-dd hh:mm:ss}}{bright,green} %highlight{%-5level} [%style{%t}{bright,blue}] %style{%C{}}{bright,yellow}:%L -%msg%n%style{%throwable}{red}
            </Pattern>
        </PatternLayout>
    </Console>
  </Appenders>

针对pattern解析:注意的是这个只针对控制台有效,对输出到文件的内容是无效的

%style{%d{yyyy-MM-dd hh:mm:ss}}{bright,green}

  • %d{yyyy-MM-dd hh:mm:ss}: 输出日志记录的时间戳,格式为 年-月-日 时:分:秒。
  • %style{...}{bright,green}: 将时间戳部分设置为亮绿色(bright, green)

%highlight{%-5level}

  • %-5level: 输出日志级别(例如:INFO, DEBUG),占5个字符宽度,左对齐。
  • %highlight{...}: 根据日志级别自动设置颜色。不同的日志级别(如 ERROR、WARN、INFO)会有不同的颜色,默认配置为 ERROR 红色, WARN 黄色, INFO 绿色。

4.3.2 File

File节点用于将日志输出到指定文件,一般不用该节点,而使用RollingFile节点

属性:

  1. name:用于指定Appender的名称;
  2. fileName:用于指定日志文件的全路径;

子节点:

  • PatternLayout:用于指定输出格式,不设置的话,默认为:%m%n
<File name="MyFile" fileName="logs/app.log">
      <PatternLayout>
        <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
      </PatternLayout>
</File>

4.3.3 RollingFile

RollingFile节点用于实现日志文件更动更新的Appender,当满足条件(日志大小、指定时间等)重命名或打包原日志文件进行归档,生成新日志文件用于日志写入。

属性:

  1. name:用于指定Appender的名称;
  2. fileName:用于指定日志文件的全路径
  3. filePattern:用于指定分割文件的日志全路径(命名规则)

子节点:

  • PatternLayout:用于指定输出格式,不设置的话,默认为:%m%n
  • Policies :设置日志文件切割参数;
    • SizeBasedTriggeringPolicy:Policies的子节点,用于设置基于日志文件大小触发的滚动策略size属性用来指定每个分割的日志文件大小。
    • TimeBasedTriggeringPolicy:Policies的子节点,用于设置基于时间间隔触发的滚动策略interval属性用于指定滚动时间间隔,默认是1小时,modulate属性是用于对interval进行偏移调节,默认为false。若为true,则第一次触发时是第一个小时触发,后续以interval间隔触发。
    • CronTriggeringPolicy:Policies的子节点,用于设置基于Cron表达式触发的滚动策略。
  • DefaultRolloverStrategy:设置默认策略设置。

滚动策略分为三种:

  • 基于大小的滚动策略

    <RollingFile name="RollingFile" fileName="logs/app.log"
                     filePattern="logs/$${date:yyyy-MM}/app-%d{yyyy-MM-dd}-%i.log.gz">
          <PatternLayout>
            <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
          </PatternLayout>
        
          <Policies>
            <SizeBasedTriggeringPolicy size="100 MB"/>
          </Policies>
        
          <DefaultRolloverStrategy max="10"/>
    </RollingFile>
    

    上述模板中,日志先写入logs/app.log中,每当文件大小达到100MB时,按照在logs/2020-09/目录下以app-2020-09-09-1.log.gz格式对该日志进行压缩重命名并归档,并生成新的文件app.log进行日志写入。

    其中,filePattern属性的文件格式中%i就类似于一个整数计数器,受到<DefaultRolloverStrategy max="10"/>控制,要特别注意的是:当文件个数达到10个的时候会循环覆盖前面已归档的1-10个文件。若不设置该参数,默认为7

  • 基于时间的滚动策略

    <RollingFile name="RollingFile" fileName="logs/app.log"
                 filePattern="logs/$${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}.log.gz">
        
        <PatternLayout>
            <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
        </PatternLayout>
        
        <Policies>
            <TimeBasedTriggeringPolicy interval="6" modulate="true"/>
        </Policies>
        
    </RollingFile>
    

    上述模板中,日志先写入logs/app.log中,每当文件的时间间隔到达6小时(由%d{yyyy-MM-dd-HH}决定,也可以设置成%d{yyyy-MM-dd-HH-mm},则间隔为分钟级别),触发滚动操作。

    如上配置设置好后,10点的日志开始重启服务,则从11点触发一次rollover操作,生成2020-09-09-10.log.gz对该日志进行压缩重命名并归档,并生成新的文件app.log进行日志写入;然后,每间隔6小时,则下一次是17点触发一次,生成2020-09-09-17.log.gz对该日志进行压缩重命名并归档,并生成新的文件app.log进行日志写入。

  • 基于时间和大小的滚动策略

    <RollingFile name="RollingFile" fileName="logs/app.log"
                 filePattern="logs/$${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}-%i.log.gz">
        <PatternLayout>
            <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
        </PatternLayout>
        
        <Policies>
            <TimeBasedTriggeringPolicy interval="6" modulate="true"/>
            <SizeBasedTriggeringPolicy size="100 MB"/>
        </Policies>
        
    </RollingFile>
    

    上述模板中,日志先写入logs/app.log中,每当文件大小达到100MB或者当时间间隔到达6小时(由%d{yyyy-MM-dd-HH}决定),触发rollover操作,按照在logs/2020-09/目录下以app-2020-09-09-1.log.gz格式对该日志进行压缩重命名并归档,并生成新的文件app.log进行日志写入。

4.4 过滤器

Filters过滤是用到上述三个标签中的子标签,用来过滤掉不需要的日志级别

log4j2存在两种过滤器:

  1. ThresholdFilter

    • level: 指定日志的最低输出级别。

    • onMatch: 指定当日志级别等于或高于 level 时的行为,通常是 ACCEPTDENY

    • onMismatch: 指定当日志级别低于 level 时的行为,通常是 NEUTRALDENY

    <Filters>
        <!-- 只保留低于 WARN 级别的日志 -->
        <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
    </Filters>
    
  2. LevelRangeFilter

    • minLevel: 指定日志的最低输出级别。
    • maxLevel: 指定日志的最高输出级别。
    • onMatch: 指定当日志级别在指定范围内时的行为,通常是 ACCEPT
    • onMismatch: 指定当日志级别不在指定范围内时的行为,通常是 DENY
    <Filters>
        <!-- 保留 TRACE 到 INFO 级别的日志 -->
        <LevelRangeFilter minLevel="trace" maxLevel="info" onMatch="ACCEPT" onMismatch="DENY"/>
    </Filters>
    

ACCEPT是接受,DENY是拒绝,NEUTRAL是不做过滤让后面的过滤器做决定

4.5 指定输出类型

在上述我们输出到文件中的内容都是使用的PatternLayout但还存在其他的,常用的有:

  • JSONLayout:格式化为json

    • compact: 如果设置为 true,则输出的 JSON 将不包含空格和缩进,输出会更紧凑。
    • eventEol: 如果设置为 true,每个事件将以换行符结束,便于日志分析工具逐行处理。
    <JSONLayout compact="true" eventEol="true"/>
    
  • XMLLayout:格式化为XML

    • complete: 如果设置为 true,日志文件会包含 XML 声明和根元素的结束标签
    • compact: 如果设置为 true,输出的 XML 将不包含空格和缩进,输出会更紧凑。
    <XMLLayout complete="false" compact="true"/>
    
  • HTMLLayout:格式化为HTML

    • title: HTML 页面的标题。
    • locationInfo: 如果设置为 true,则输出的日志消息将包含类和行号信息
    • charset: 指定字符集编码。
    <HTMLLayout title="Log4j Log Messages" locationInfo="true" charset="UTF-8"/>
    
  • CSVLayout:格式化为CSV

    • format: 指定 CSV 格式的预定义模式,例如 DefaultExcel.
    <CSVLayout format="Default"/>
    

4.4 Loggers标签

子节点:

  • Root:用于指定项目的根日志level属性表示日志输出级别,子节点AppenderRef用于指定输出到某个Appender,子节点的ref属性也就是前面的RollingFile中指定的name名称,子节点的level也是日志输出级别。
  • Logger :用于指定日志的形式,指定不同包的日志级别,level属性表示日志输出级别,name属性用来指定该Logger所适用的类或者类的全路径。子节点AppenderRef用于指定日志输出到哪个Appender,若没有指定,默认集成自Root。
  <Loggers>
    <Root level="error">
      <AppenderRef ref="RollingFile"/>
    </Root>
      <Logger level="info" name="com.ruoyi.admin.log">
          <AppenderRef ref="concoleFile"/>
      </Logger>
  </Loggers>

五,模板xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <!--<Configuration status="WARN" monitorInterval="30"> -->
    <properties>
        <property name="LOG_HOME">../logs</property>
    </properties>

    <Appenders>
        <!--*********************控制台日志***********************-->
        <Console name="consoleAppender" target="SYSTEM_OUT">
            <!--设置日志格式及颜色-->
            <PatternLayout
                    pattern="%style{%d{yyyy-MM-dd HH:mm:ss}}{bright,green} %highlight{%-5level} [%style{%t}{bright,blue}] %style{%C{}}{bright,yellow}: %msg%n%style{%throwable}{red}"
                    disableAnsi="false" noConsoleNoAnsi="false"/>
        </Console>
        <!--*********************文件日志***********************-->
        <!--all级别日志-->
        <RollingFile name="allFileAppender"
                     fileName="${LOG_HOME}/all.log"
                      filePattern="${LOG_HOME}/$${date:yyyy-MM}/all-%d{yyyy-MM-dd}-%i.log.gz">
            <!--设置日志格式-->
            <PatternLayout>
                <pattern>%d %p %C{} [%t] %m%n</pattern>
            </PatternLayout>
            <Policies>
                <!-- 设置日志文件切分参数 -->
                <!--<OnStartupTriggeringPolicy/>-->
                <!--设置日志基础文件大小,超过该大小就触发日志文件滚动更新-->
                <SizeBasedTriggeringPolicy size="100 MB"/>
                <!--设置日志文件滚动更新的时间,依赖于文件命名filePattern的设置-->
                <TimeBasedTriggeringPolicy/>
            </Policies>
            <!--设置日志的文件个数上限,不设置默认为7个,超过大小后会被覆盖;依赖于filePattern中的%i-->
            <DefaultRolloverStrategy max="100"/>
        </RollingFile>

        <!--debug级别日志-->
        <RollingFile name="debugFileAppender"
                     fileName="${LOG_HOME}/debug.log"
                     filePattern="${LOG_HOME}/$${date:yyyy-MM}/debug-%d{yyyy-MM-dd}-%i.log.gz">
            <Filters>
                <!--只保留debug级别的日志-->
                <LevelRangeFilter minLevel="debug" maxLevel="debug" onMatch="ACCEPT" onMismatch="DENY"/>
            </Filters>
            <!--设置日志格式-->
            <PatternLayout>
                <pattern>%d %p %C{} [%t] %m%n</pattern>
            </PatternLayout>
            <Policies>
                <!-- 设置日志文件切分参数 -->
                <!--<OnStartupTriggeringPolicy/>-->
                <!--设置日志基础文件大小,超过该大小就触发日志文件滚动更新-->
                <SizeBasedTriggeringPolicy size="100 MB"/>
                <!--设置日志文件滚动更新的时间,依赖于文件命名filePattern的设置-->
                <TimeBasedTriggeringPolicy/>
            </Policies>
            <!--设置日志的文件个数上限,不设置默认为7个,超过大小后会被覆盖;依赖于filePattern中的%i-->
            <DefaultRolloverStrategy max="100"/>
        </RollingFile>

        <!--info级别日志-->
        <RollingFile name="infoFileAppender"
                     fileName="${LOG_HOME}/info.log"
                     filePattern="${LOG_HOME}/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log.gz">
            <Filters>
                <!--只保留info级别的日志-->
                <LevelRangeFilter minLevel="info" maxLevel="info" onMatch="ACCEPT" onMismatch="DENY"/>
            </Filters>
            <!--设置日志格式-->
            <PatternLayout>
                <pattern>%d %p %C{} [%t] %m%n</pattern>
            </PatternLayout>
            <Policies>
                <!-- 设置日志文件切分参数 -->
                <!--<OnStartupTriggeringPolicy/>-->
                <!--设置日志基础文件大小,超过该大小就触发日志文件滚动更新-->
                <SizeBasedTriggeringPolicy size="100 MB"/>
                <!--设置日志文件滚动更新的时间,依赖于文件命名filePattern的设置-->
                <TimeBasedTriggeringPolicy interval="1" modulate="true" />
            </Policies>
            <!--设置日志的文件个数上限,不设置默认为7个,超过大小后会被覆盖;依赖于filePattern中的%i-->
            <!--<DefaultRolloverStrategy max="100"/>-->
        </RollingFile>

        <!--warn级别日志-->
        <RollingFile name="warnFileAppender"
                     fileName="${LOG_HOME}/warn.log"
                     filePattern="${LOG_HOME}/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log.gz">
            <Filters>
                <!--只保留warn级别的日志-->
                <LevelRangeFilter minLevel="warn" maxLevel="warn" onMatch="ACCEPT" onMismatch="DENY"/>
            </Filters>
            <!--设置日志格式-->
            <PatternLayout>
                <pattern>%d %p %C{} [%t] %m%n</pattern>
            </PatternLayout>
            <Policies>
                <!-- 设置日志文件切分参数 -->
                <!--<OnStartupTriggeringPolicy/>-->
                <!--设置日志基础文件大小,超过该大小就触发日志文件滚动更新-->
                <SizeBasedTriggeringPolicy size="100 MB"/>
                <!--设置日志文件滚动更新的时间,依赖于文件命名filePattern的设置-->
                <TimeBasedTriggeringPolicy/>
            </Policies>
            <!--设置日志的文件个数上限,不设置默认为7个,超过大小后会被覆盖;依赖于filePattern中的%i-->
            <DefaultRolloverStrategy max="100"/>
        </RollingFile>

        <!--error级别日志-->
        <RollingFile name="errorFileAppender"
                     fileName="${LOG_HOME}/error.log"
                     filePattern="${LOG_HOME}/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log.gz">
            <!--设置日志格式-->
            <PatternLayout>
                <pattern>%d %p %C{} [%t] %m%n</pattern>
            </PatternLayout>
            <Policies>
                <!-- 设置日志文件切分参数 -->
                <!--<OnStartupTriggeringPolicy/>-->
                <!--设置日志基础文件大小,超过该大小就触发日志文件滚动更新-->
                <SizeBasedTriggeringPolicy size="100 MB"/>
                <!--设置日志文件滚动更新的时间,依赖于文件命名filePattern的设置-->
                <TimeBasedTriggeringPolicy/>
            </Policies>
            <!--设置日志的文件个数上限,不设置默认为7个,超过大小后会被覆盖;依赖于filePattern中的%i-->
            <DefaultRolloverStrategy max="100"/>
        </RollingFile>

    </Appenders>

    <Loggers>
        <!-- 根日志设置 -->
        <Root level="debug">
            <AppenderRef ref="consoleAppender" level="info"/>
            <AppenderRef ref="allFileAppender" level="all"/>
            <AppenderRef ref="debugFileAppender" level="debug"/>
            <AppenderRef ref="infoFileAppender" level="info"/>
            <AppenderRef ref="warnFileAppender" level="warn"/>
            <AppenderRef ref="errorFileAppender" level="error"/>
        </Root>
    </Loggers>

</Configuration>