日志搞不定?手把手教你如何使用Log4j2

今天我们讲解一个最年轻的日志插件,即Log4j2。Log4j2目前应用非常广泛,各方面较之前辈Log4j 都有不小的提升,不过要想利用好他,还得经过一定的学习,尤其是搞清楚它的种种配置,下面就让我们开始今天的进阶之旅。

一、引入依赖

我们可以使用以下依赖为我们项目引入Log4j2框架

<!--Log4j2自带的日志门面-->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.13.3</version>
</dependency>
<!--Log4j2具体的日志实现-->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.13.3</version>
</dependency>

当然,像上期所说,我更建议直接使用以下log4j-slf4j-impl包

<dependency>
       <groupId>org.apache.logging.log4j</groupId>
       <artifactId>log4j-slf4j-impl</artifactId>
       <version>2.13.3</version>
</dependency>

该包包含Log4j2的实现,也能对接SLF4J,更适合在项目中应用。

04c010b20c6461246661945e309d02a1.png

二、配置文件示例

我们看如下一份配置文件:log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG" monitorInterval="30">
    <!-- 输出格式 -->
    <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} - [%t] %-5level %logger{36} - %msg%n"/>

    <Appenders>
        <!-- 控制台输出 -->
        <Console name="Console" target="SYSTEM_OUT">
            <!-- 过滤器 -->
            <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
            <!-- 缓冲bufferSize,默认值为256,可调整至1-256之间 -->
            <Buffered mode="ONCE" bufferSize="256"/>
        </Console>

        <!-- 文件输出 -->
        <RollingFile name="RollingFile" fileName="/path/to/logs/test.log" filePattern="/path/to/logs/$${date:yyyy-MM}/test-%d{yyyy-MM-dd}-%i.log">
            <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
            <!-- 输出格式 -->
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
            <!-- 触发策略 -->
            <Policies>
                <!-- 按时间滚动 -->
                <TimeBasedTriggeringPolicy/>
                <!-- 按文件大小滚动,这里设置10MB -->
                <SizeBasedTriggeringPolicy size="10MB"/>
            </Policies>
            <!-- 滚动策略 -->
            <DefaultRolloverStrategy max="10"/>
        </RollingFile>
    </Appenders>

    <Loggers>
        <!-- 默认日志 -->
        <Root level="INFO">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="RollingFile"/>
        </Root>

        <!-- 指定包名的日志 -->
        <Logger name="com.example" level="DEBUG" additivity="false">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="RollingFile"/>
        </Logger>
    </Loggers>
</Configuration>

三、PatternLayout

PatternLayout是一种日志输出格式,用于设置日志输出的布局格式。该格式使用一系列特定的占位符,每个占位符都代表一种日志信息,例如输出日志事件的时间、线程名、日志级别、日志内容等

  • %d:输出日志事件的时间戳

  • %t:输出线程名

  • %-5level:输出日志级别,包括5个字符位置(例如,DEBUG、INFO、WARN、ERROR、FATAL),将小于5个字符的级别左对齐

  • *%logger{36}*:输出日志记录器的名称,最多36个字符

  • %msg:输出日志内容

  • %n:输出平台相关的行分隔符

  • %M:输出产生日志事件的方法名

  • %L:输出语句在源文件中出现的行号

  • %l:输出语句的精确位置,包含类、方法和行号

  • %c:输出日志事件相关的类名

我们举两个例子,假如我们配置文件这么写

<PatternLayout pattern="%d{ISO8601} [%t] %-5level %logger{36} - %msg%n" />

输出的结果就为

2023-08-23T19:34:26,068 [main] INFO  com.zhanfu.Main - This is a Main info message.

如果配置文件如下

<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} |-%-5level [%t] %c{1.} %M [%L] -| %msg%n"/>

输出的结果就为

2023-08-23 20:18:06.833 |-INFO  [main] c.z.Main main [11] -| This is a Main info message.

其中,%c{1.} 表示输出日志事件相关的类名,只取最右边的类名,前面的层级,只输出一个字母;如果配置文件如下

<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} |-%-5level [%t] %c{2.} [%l] -| %msg%n"/>

输出的结果就为

2023-08-23 20:21:00.753 |-INFO  [main] co.zh.Main [com.zhanfu.Main.main(Main.java:11)] -| This is a Main info message.

四、Appenders

Appenders是指日志输出的目的地。它定义了日志事件要被输出到哪些地方,例如控制台、文件、数据库等,其下可以配置不同类型的Appender,我们罗列其中常见的一些:

  • Console:向控制台输出日志。

  • File:将日志记录到文件中。

  • RollingFile:将日志记录到指定大小的文件中,并支持文件滚动。

  • Socket:将日志发送到远程 Socket 服务器

  • Kafka:将日志发送到 Kafka 消息队列。

  • Redis:将日志发送到 Redis 服务器。

  • Jdbc:将日志记录到数据库中

对于单机应用来说,Console 与 File 是最为常用的,但对于集群,通常需要进行日志采集,此时也会通过Socket或Kafka等将日志发送至其他位置

五、Console

Console标签是用于将日志输出到控制台的标签,其有以下可配置的属性:

  • name:配置Console标签的名称。

  • target:配置Console标签输出的目标,可以是System.out或System.err,默认为System.out。

  • follow:配置Console标签,控制台是否跟随日志进行滚动,默认为false。

  • immediateFlush:配置Console标签的输出是否立即刷新,默认为true

Console标签可以包含以下子标签

  • PatternLayout:上文已经介绍过,可以自定义输出的格式。此标签有以下可配置的属性:pattern。

  • ThresholdFilter:指定哪些日志级别应该被输出或被拒绝。此标签有以下可配置的属性:

    • level - 匹配的可用的日志级别。

    • onMatch - 当匹配或高于指定日志等级时的动作,可以为 ACCEPT、DENY、NEUTRAL 之一,默认为 NEUTRAL

    • onMismatch - 当低于指定日志等级时的动作,可以为 ACCEPT、DENY、NEUTRAL ,默认为 DENY

  • RegexFilter:使用正则表达式来计算哪些日志消息应该被过滤。

1. Filter 过滤器

比如我们可以做出如下配置

<Console name="console" target="SYSTEM_OUT">
    <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    <ThresholdFilter level="WARN" onMatch="NEUTRAL " onMismatch="DENY"/>
    <RegexFilter regex=".*\[(main|AsyncLogger)\].*"/>
</Console>

我们可以发现 ThresholdFilter 的设置为 level=“WARN” onMatch="NEUTRAL " onMismatch=“DENY”,这种设置的意思就是当日志等级高于或等于 WARN 时,就通过了级别过滤器,但还需要经过后续过滤器如的进一步筛选。而低于 WARN 则直接拒绝打印。

比如我们有这样的过滤设置

<ThresholdFilter level="error" onMatch="DENY" onMismatch="NEUTRAL"/>
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
<ThresholdFilter level="warn" onMatch="DENY" onMismatch="DENY"/>

第一个过滤器否决打印error级别,第二个过滤器接收大于info级别,并且否决低于info级别的,那最终只能打印info 和 warn 级别了。此处的第三个过滤器实际上没被用到

01e72cd478397114531e51de059daa4f.png

六、RollingFile

RollingFile标签用于配置滚动日志输出到文件的方式,什么叫滚动日志,就是日志输出在一个文件中,当某个事件发生时(如文件达到一定大小),会把这个文件进行归档封存,然后新建一个文件,再向新建的文件中输出日志,有点像现代的饮料生产线,灌满一瓶立即灌下一瓶

e4e7b3a2d5e535651a08e0432e08ea6c.png

以下是RollingFile标签的常用属性:

  • name:指定RollingFile的名称,用于标识该Appender。

  • fileName:指定日志文件的路径和名称。

  • filePattern:指定日志文件备份的命名模式,使用%符号指定日期、数字等占位符。

RollingFile 可以包含下列子标签

  • policies:指定日志滚动策略,包括时间、大小等,可以使用TimeBasedTriggeringPolicy、SizeBasedTriggeringPolicy等标签。

  • PatternLayout:指定日志输出格式,上面已经说过。

我们可以以下面的配置为例子进行进一步解释

<Appenders>
    <RollingFile name="RollingFile"
            fileName="/logs/app.log"
            filePattern="logs/app-%d{yyyy-MM-dd-HH}-%i.log">
        <PatternLayout>
            <pattern>%d %p %c{1.} [%t] %m%n</pattern>
        </PatternLayout>
        <Policies>
            <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
            <SizeBasedTriggeringPolicy size="10 MB"/>
        </Policies>
        <DefaultRolloverStrategy max="5"/>
    </RollingFile>
</Appenders>

该示例配置了一个名为“RollingFile”的RollingFile Appender,将日志记录到“/logs/app.log”文件中。文件名模式为“/logs/$${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}-%i.log.gz”

1. filePattern 文件样板

filePattern是RollingFile Appender的一个属性,用于指定根据何种模式生成归档滚动日志文件的名称。filePattern可以使用一些特定的占位符,以便在滚动时自动生成新的日志文件名

filePattern占位符:

  • %d - 日期格式化器的格式化日期。例如:2018-09-19

  • %i - 滚动文件的索引编号,从1开始。

  • %n - 系统的行分隔符

  • %m - 文件名

比如我们设置的

filePattern="logs/app-%d{yyyy-MM-dd-HH}-%i.log"

filePattern中的时间占位符%d在滚动时会自动更新为当前时间,索引号%i也会自动递增以避免覆盖先前的日志,所以最终会生成以下的归档文件名

app-2021-08-30-15-1.log

app-2021-08-30-15-2.log

app-2021-08-30-15-3.log

2. Policies 文件原则

Policies用于定义何时触发滚动动作以生成新的日志文件,可以定义TimeBased和SizeBased两种类型的触发策略。

TimeBasedTriggeringPolicy

TimeBasedTriggeringPolicy是基于时间的触发策略,当指定的时间间隔过去时,将会触发滚动动作。 属性:

  • interval:时间间隔,单位为filePattern中的最小时间单位,如%d{yyyy-MM-dd-HH}代表最小时间为小时,默认数值为1。

  • modulate:是否调节,即使用0时0分作为起点,当开启时,下一次生成日志文件的时间为0时0分 + n 个interval

SizeBasedTriggeringPolicy

SizeBasedTriggeringPolicy是基于日志文件大小的触发策略,当日志文件大小达到指定的大小时,将会触发滚动动作 属性:

  • size:指定的日志文件大小,单位为字节,默认值为10MB

需要注意的是

1.若modulate=true, 则封存时间将以0点为边界进行偏移计算。比如,modulate=true,interval=4hours,那么假设上次封存日志的时间为03:00,则下次封存日志的时间为04:00,之后的封存时间依次为08:00,12:00,16:00…如果modulate=false,则代表不调整,封存时间严格遵循离上次间隔4小时,则封存时间依次为07:00,11:00,15:00…

2.Policies可以同时指定多个触发策略,从而满足多种情况下的滚动需求,例如

<RollingFile name="example"
        fileName="logs/logfile.log"
        filePattern="logs/logfile-%d{yyyy-MM-dd_HH}.log">
 <Policies>
     <TimeBasedTriggeringPolicy interval="5" modulate="true"/>
     <SizeBasedTriggeringPolicy size="100 MB"/>
   </Policies>
    <DefaultRolloverStrategy max="5"/>
</RollingFile>

以上配置将在每隔五小时或100M时将生成一个新的日志文件,文件名会包含时间戳

3. DefaultRolloverStrategy

DefaultRolloverStrategy是一个滚动策略,可以设置滚动文件数量以及删除策略,它有以下几个属性:

  • max:最大日志文件数量,默认为7。

  • min:最小日志文件数量,默认为1。

  • fileIndex:日志文件序号的格式,默认为%s。

  • compressionLevel:压缩级别,默认为6

同时,它也支持以下子标签:

  • Delete:用于配置何时删除过期的日志文件。

  • CustomDelete:用于自定义删除过期日志文件的行为。

比如以下设置

<DefaultRolloverStrategy max="10" min="2" fileIndex="max">
    <Delete basePath="logs" maxDepth="2">
        <IfFileName glob="*.log" />
        <IfLastModified age="14d" />
    </Delete>
</DefaultRolloverStrategy>

这代表日志文件最多保留10个,最少保留2个,日志文件序号格式为max,同时配置了Delete子标签,用于删除14天前的logs文件夹下,两层路径以内的所有.log文件。其中,Delete子标签中的IfFileName和IfLastModified子标签用于指定删除条件,只有同时满足两个条件才进行删除操作

需要注意的是,文件的多少与我们设置的 filePattern 也有关系,其限制的其实是%i的最大数值:

比如

filePattern="logs/app-%d{yyyy-MM-dd-HH}-%i.log

这代表文件归档最小单位为小时,如果我们的 DefaultRolloverStrategy max="10" ,那么一个小时内最多保留10个文件,当产生第11个文件时,将会删除本小时最早的日志文件

七、Loggers

Loggers和Logger标签是用来配置日志记录器的。Loggers标签是定义所有Logger的容器标签,而Logger标签则是具体的记录器配置,Logger 标签有以下属性:

  • name:指定Logger的名称,名称可以是类名、包名或自定义的名称。例如,如果设置为com.example.MyLogger,则日志内容将包含该名称。

  • level:指定Logger的日志级别,如果不指定则将继承Loggers标签中的默认级别。例如,如果设置为INFO,则只会记录INFO及以上级别的日志。

  • additivity:指定Logger是否继承它的父Logger的Appender。如果不指定,则将继承Loggers标签中的默认值。

  • includeLocation:指定是否包含日志输出的调用位置信息。如果设置为true,则输出的日志将包括文件名、方法名和行号等信息。

  • suppressExceptions:指定是否屏蔽日志输出中的异常信息。如果设置为false,则将在日志输出中包含异常信息

Logger标签还包括AppenderRef子标签,用于指定Logger所要使用的Appender。可以在Logger标签中指定多个AppenderRef,这样就可以将同一个Logger的日志输出到多个Appender中

下面是一个典型的Loggers与Logger的例子:

<Appenders>
    <RollingFile name="MyAppender"
            fileName="/logs/app.log"
            filePattern="logs/app-%d{yyyy-MM-dd-HH}-%i.log">
        <PatternLayout>
            <pattern>%d %p %c{1.} [%t] %m%n</pattern>
        </PatternLayout>
        <Policies>
            <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
            <SizeBasedTriggeringPolicy size="10 MB"/>
        </Policies>
        <DefaultRolloverStrategy max="5"/>
    </RollingFile>
    <Console name="Console" target="SYSTEM_OUT">
            <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
            <Buffered mode="ONCE" bufferSize="256"/>
    </Console>
</Appenders>
<Loggers>
    <Logger name="com.example.MyLogger" level="info">
        <AppenderRef ref="MyAppender"/>
    </Logger>
    <Root level="error">
        <AppenderRef ref="Console"/>
    </Root>
</Loggers>

这个例子中定义了两个Logger:com.example.MyLogger和Root。com.example.MyLogger的级别是INFO,只会记录INFO及以上级别的日志,并且使用MyAppender作为输出目的地;Root的级别是ERROR,将所有ERROR及以上级别的日志输出到Console中

八、异步日志

1. 基础使用

我们上面讲解的其实都是同步输出的日志,而Log4j2 的一大特性就是其异步输出能力,我们可以参考如下配置

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <File name="File" fileName="logs/app.log">
            <PatternLayout>
                <Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
            </PatternLayout>
        </File>
        <Async name="Async">
            <AppenderRef ref="File"/>
        </Async>
    </Appenders>
    <Loggers>
        <Logger name="com.example" level="debug"/>
        <Root level="info">
            <AppenderRef ref="Async"/>
        </Root>
    </Loggers>
</Configuration>
  • 首先,定义了一个文件输出的Appender,文件名为logs/app.log,并且在PatternLayout中指定了日志输出的格式。

  • 接着,定义了一个异步的Appender,它的AppenderRef指向了文件输出的Appender。

  • 最后,将Root Logger的级别设为info,并让它的AppenderRef指向了异步的Appender。

这个配置可以实现将日志异步输出到logs/app.log文件中,并且可以指定日志输出的格式

我们可以做一个测试,分别用同步和异步的方式进行运行:

public static void main(String[] args) {
    long startTime = System.currentTimeMillis();
    for (int i = 0; i < 1000000; i++) {
        log.info("This is a debug message. Count is "+i);
    }
    long endTime = System.currentTimeMillis();
    log.info("Total time: "+(endTime - startTime)+"ms");
}

567d7e956fc93131d76a121738478cac.png588fd4e904407de85eadc82395c95370.png

可以看到,异步确实能节约很多时间。

2. 详细配置
070bcacef0ac1b1516c60f0d5c57ed18.png

我们注意到最后一个阻塞队列的信息,其实不难想象,这里的日志异步依赖的就是高性能队列,不仅log4j2,像Netty等对性能有极高要求的框架,在队列的选择上都是精益求精的。log4j2支持四种阻塞队列,如下:

2f7496e975f475c2af2f5f1edf615e5f.png

比如我们如果想指定一种阻塞队列,可以这么设置:

<Configuration name="LinkedTransferQueueExample">
  <Appenders>
    <List name="List"/>
    <Async name="Async" bufferSize="262144">
      <AppenderRef ref="List"/>
      <AsyncQueueFullPolicy type="Discard"/>
      <!-- 指定阻塞队列 -->
      <LinkedTransferQueue/>
    </Async>
  </Appenders>
  <Loggers>
    <Root>
      <AppenderRef ref="Async"/>
    </Root>
  </Loggers>
</Configuration>

当然,如果你想使用 DisruptorBlockingQueue,那还需要引入 disruptor 包,注意版本兼容,log4j-2.17.1 对应了disruptor-3.4.0

<dependency>
    <groupId>com.lmax</groupId>
    <artifactId>disruptor</artifactId>
    <version>3.4.0</version>
</dependency>

总结

本次我们比较详细的介绍了Log4j2框架的种种配置,虽然没有讲原理,但解释了不少配置并给出示例,相信即便是新手,阅读完也能应对大部分使用场景了。希望大家能够举一反三,灵活运用。当然,有问题也可以直接去官方文档进行查阅和学习。

log4j2 手册

  • https://logging.apache.org/log4j/2.x/manual/

来源:blog.csdn.net/u011709538/

article/details/132459143

1caa09cce200b00f88cfa0d02c54b8cd.gif

回复干货】获取精选干货视频教程

回复加群】加入疑难问题攻坚交流群

回复mat】获取内存溢出问题分析详细文档教程

回复赚钱】获取用java写一个能赚钱的微信机器人

回复副业】获取程序员副业攻略一份

8738b4dae65fc43aedf38bb26e3d69c9.jpeg

好文请点赞+分享

a288ff9a01d052d00d3d2f97ef33d162.gif

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
[ 2021年,将Spring全家桶的课程进行Review,确保不再有顺序错乱等问题导致学员看不懂内容,进入2022年,将Spring的课程进行整理,整理为案例精讲的系列课程,并开始逐步增加高阶的Spring Security等内容,课件将逐步进行上传,敬请期待! ]本课程是Spring全家桶案例精讲课程的第二部分Spring MVC,Spring案例精讲课程以真实场景、项目实战为导向,循序渐进,深入浅出的讲解Java网络编程,助力您在技术工作中更进一步。 本课程聚焦Java Spring的Web知识点,主要是关于Spring MVC的应用,包含:表单的增删改查、国际化、过滤器、拦截器、日志Log4j2及slf4j的使用、主题更改网站皮肤及样式、文件上传等的案例讲解,并且最后以一个SSM(Spring+Spring MVC+Mybatis)贯穿前后台的案例作为Spring MVC课程的终奖, 从而使大家快速掌握Spring的基础核心知识,快速上手,为面试、工作等做好充足准备。 由于本课程聚焦于案例,即直接上手操作,对于Spring的原理等不会做过多介绍,希望了解原理等内容的需要通过其他视频或者书籍去了解,建议按照该案例课程一步步做下来,之后再去进一步回顾原理,这样能够促进大家对原理有更好的理解。 【通过Spring全家桶,我们保证你能收获到以下几点】 1、掌握Spring全家桶主要部分的开发、实现2、可以使用Spring MVC、Spring Boot、Spring Cloud及Spring Data进行大部分的Spring开发3、初步了解使用微服务、了解使用Spring进行微服务的设计实现4、奠定扎实的Spring技术,具备了一定的独立开发的能力  【实力讲师】 毕业于清华大学软件学院软件工程专业,曾在Accenture、IBM等知名外企任管理及架构职位,近15年的JavaEE经验,近8年的Spring经验,一直致力于架构、设计、开发及管理工作,在电商、零售、制造业等有丰富的项目实施经验 【本课程适用人群】如果你是一定不要错过!  适合于有JavaEE基础的,如:JSP、JSTL、Java基础等的学习者没有基础的学习者跟着课程可以学习,但是需要补充相关基础知识后,才能很好的参与到相关的工作中。 【Spring全家桶课程共包含如下几门】 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值