【三方件】日志Log4j

阿里技术针对Java日志的专题系列: https://new.qq.com/rain/a/20240522A010GS00

 

Log4j2中RollingFile的文件滚动更新机制:https://www.cnblogs.com/yeyang/p/7944899.html

https://www.cnblogs.com/yeyang/p/7944899.html

https://open.alipay.com/portal/forum/post/137701054?ant_source=opendoc_recommend

 

日志绕接RollingFileAppender

RollingFileAppender是Log4j2中的一种能够实现日志文件滚动更新(rollover)的Appender。

rollover的意思是当满足一定条件(如文件达到了指定的大小,达到了指定的时间)后,就重命名原日志文件进行归档,并生成新的日志文件用于log写入。如果还设置了一定时间内允许归档的日志文件的最大数量,将对过旧的日志文件进行删除操作。

 RollingFile实现日志文件滚动更新,依赖于TriggeringPolicy和RolloverStrategy。
  • TriggeringPolicy为触发策略,其决定了何时触发日志文件的rollover,即When。
  • RolloverStrategy为滚动更新策略,其决定了当触发了日志文件的rollover时,如何进行文件的rollover,即How。

1.1 TriggeringPolicy  

定义:<Policies></Policies>

RollingFile的触发rollover的策略有:

  • CronTriggeringPolicy(Cron表达式触发)
  • OnStartupTriggeringPolicy(JVM启动时触发)
  • SizeBasedTriggeringPolicy(基于文件大小):size参数可以用KB、MB、GB等做后缀来指定具体的字节数,如20MB。
    <SizeBasedTriggeringPolicy size="250MB"/>
  • TimeBasedTriggeringPolicy规定了当日志文件名中的date/time pattern不再符合filePattern中的date/time pattern时,触发rollover操作。

    比如,filePattern指定文件重命名规则为app-%d{yyyy-MM-dd HH}.log,文件名为app-2017-08-25 11.log,当时间达到2017年8月25日中午12点(2017-08-25 12),将触发rollover操作。

参数1:interval
integer型,指定两次封存动作之间的时间间隔。这个配置需要和filePattern结合使用,filePattern日期格式精确到哪一位,interval也精确到哪一个单位。注意filePattern中配置的文件重命名规则是%d{yyyy-MM-dd HH-mm-ss}-%i,最小的时间粒度是ss,即秒钟。
TimeBasedTriggeringPolicy默认的size是1,结合起来就是每1秒钟生成一个新文件。如果改成%d{yyyy-MM-dd HH},最小粒度为小时,则每一个小时生成一个文件

参数2:modulate
boolean型,说明是否对封存时间进行调制。若modulate=true, 则封存时间将以0点为边界进行偏移计算。比如,modulate=true,interval=4hours, 那么假设上次封存日志的时间为03:00,则下次封存日志的时间为04:00, 之后的封存时间依次为08:00,12:00,16:00
  • CompositeTriggeringPolicy(多个触发策略的混合,如同时基于文件大小和时间):将多个TriggeringPolicy放到Policies中表示使用复合策略,有一个条件满足即可

1.2 DefaultRolloverStrategy

DefaultRolloverStrategy指定了当触发rollover时的默认策略。

DefaultRolloverStrategy是Log4j2提供的默认的rollover策略,即使在log4j2.xml中没有显式指明,也相当于为RollingFile配置下添加了如下语句。DefaultRolloverStrategy默认的max为7

1.2.1 DeleteAction

DefaultRolloverStrategy制定了默认的rollover策略,通过max参数可控制一定时间范围内归档的日志文件的最大个数。

Log4j 2.5 引入了DeleteAction,使用户可以自己控制删除哪些文件,而不仅仅是通过DefaultRolloverStrategy的默认策略。


 

<Loggers>

常见2种:Root 和具体Logger

2.1 Root:

指定项目的根日志,如果没有单独指定logger,则默认使用Root输出;每个日志比如配置一个根Root,没有name属性,不需配置additivity属性

2.2 Logger

单独指定日志的形式,属性:

name: 指定该Logger所适用的类或所在包路径,继承自Root节点

level:   日志输出级别,未指定默认ERROR

AppenderRef: 指定该日志输出到哪个Appender,如果没指定,默认继承自Root。如果指定则会在指定Appender和Root的Appender都输出。

可以配置1个或多个AppenderRef属性。可以设置 additivity = "false"(默认true) 只在自定义的Appender进行输出

 


 Log4j2异步日志背后的数字  https://blog.csdn.net/ok449a6x1i6qq0g660fV/article/details/106066059?spm=1001.2014.3001.5502

  //  对比三种打印日志方式,分别是同步方式、AsyncAppender异步及AsyncLogger异步方式

  同步记录日志是指当输出日志时,必须等待日志输出语句执行完毕后,才能执行后面的业务逻辑语句。在输出日志时,会将日志信息转换为日志事件LogEvent对象,然后将LogEvent对象传入对应的Appender中,由对应的Appender调用appender()方法将日志信息写入文件。

  AsyncAppender的异步打印做了两件事,先把日志事件放到ArrayBlockingQueue队列,然后单独的线程读取队列中的日志事件将其传递给其他引用的Appender,由这些Appender将日志写入文件。

  AsyncLogger的异步记录器是Log4j2的一个新特性,可以通过在单独的线程中执行I/O操作来提高应用程序的性能。其内部使用了disruptor框架,其底层数据结构为无锁环形队列,每次日志信息保存在队列中,另一个线程将队列中日志写入文件;需要在classpath路径下需要额外添  加disruptor的jar包


 slf4j中的MDC工具类使用

  MDC: Mapped Diagnostic Context,可以粗略的理解成是一个线程安全的存放诊断日志的容器。内部通过ThreadLocal实现了不同线程的隔离。

  参考:https://www.jianshu.com/p/8b01d62e2431 https://juejin.cn/post/6844904132478763022

       内部实现:依赖MDCAdapter接口,不同的日志组件都实现如Log4jMDCAdapter

  应用场景:

    a)WEB应用,如果想在日志中输出请求用户IP 地址、请求 URL、统计耗时等等;
    b)在WEB应用中,借助MDC来保存用户请求时产生的reqId,当请求完成后,再将reqId进行移除,这么通过grep reqId就能轻松get整个请求流程的日志轨迹;
    c)在微服务盛行的当下,链路跟踪是个难题,而借助MDC去埋点

  Seata代码

     

  MDC API:

    

  代码样例:需代码和log*.xml配合使用

     

  效果:

    

        多线程场景验证:

    


 

ThresholdFilter配置:onMatch表示匹配设定的日志级别后是DENY还是ACCEPT,onMismatch表示不匹配设定的日志级别是DENY还是ACCEPT还是NEUTRAL

match/misMatch指的是高于或等于设定的日志级别。所以,要先定义日志级别高的Filter。

onMatch和onMismatch都有三个属性值,分别为Accept、DENY和NEUTRAL

介绍一下这两个配置项的三个属性值:

    • onMatch="ACCEPT" 表示匹配该级别及以上
    • onMatch="DENY" 表示不匹配该级别及以上
    • onMatch="NEUTRAL" 表示该级别及以上的,由下一个filter处理,如果当前是最后一个,则表示匹配该级别及以上
    • onMismatch="ACCEPT" 表示匹配该级别以下
    • onMismatch="NEUTRAL" 表示该级别及以下的,由下一个filter处理,如果当前是最后一个,则不匹配该级别以下的
    • onMismatch="DENY" 表示不匹配该级别以下的

<ThresholdFilter level="FATAL" onMatch="DENY" onMismatch="NEUTRAL"/>
<ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
<ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/>
只打印INFO和ERROR

 

posted @ 2023-01-20 14:51  飞翔在天  阅读(89)  评论(0编辑  收藏  举报