妈妈再也不用担心我搞不懂——log4j/logback/log4j2原理了

本文详细介绍了常见的日志框架,包括slf4j、j.u.l、log4j、logback和log4j2,重点解析了log4j2的原理,涉及四大组件:Logger、Appender、Layout和Filter。讨论了同步与异步日志处理,特别是log4j2中的Disruptor技术,以及如何自定义Appender。
摘要由CSDN通过智能技术生成

一、常见日志框架

日志框架简单比较(slf4j、j.u.l、log4j、logback、log4j2 )

  • slf4j:slf4j是对所有日志框架制定的一种规范、标准、接口,并不是一个框架的具体的实现,因为接口并不能独立使用,需要和具体的日志框架实现配合使用(如log4j、logback、log4j2)。

  • j.u.l:j.u.l是java.util.logging包的简称,是JDK在1.4版本中引入的Java原生日志框架。

  • log4j:log4j是apache实现的一个开源日志组件。

  • logback:logback也是由log4j的作者设计完成的,拥有更好的特性,用来取代log4j的一个日志框架,是slf4j的原生实现。

  • log4j2:log4j2是log4j和logback的改进版,采用了一些新技术(无锁异步、Disruptor等),使得日志的吞吐量、性能比log4j提高了10倍,并解决了一些死锁的bug,而且配置更加简单灵活。

二、log4j/logback/log4j2四大件:Logger、Appender、Layout、Filter

2.1 简介

  • Logger:日志记录器,负责收集处理日志记录 (谁+如何处理日志)

  • Appender:日志输出目的地,负责日志的输出  (输出到什么地方)

  • Layout:日志格式化,负责对输出的日志格式化(以什么格式输出)

  • Filter:日志过滤,负责过滤掉不需要输出的日志(满足条件才输出)

即logger负责收集日志,交给对应的appender,然后appender利用filter对日志进行过滤,并利用layout将日志按照一定的格式进行输出。

log4j2的logger可以分为两类:一类是所有logger的父类,叫root;另外一类就是自定义logger。后者的appender根据logger的参数additivity(默认为true)决定是否要叠加root的appender,即默认情况下,一条日志既会输出到logger对应的所有appender中,也会输出到root对应的所有appender中。logger的级别是其自身定义的级别,和root的级别没关系。

三、同步Logger、异步AsyncLogger

logger收到业务层打印的日志后,会将日志封装成一个LogEvent对象(增加时间戳等信息),最终交给logger对应的所有Appender来进行输出。这里的同步异步是指logger将LogEvent交给Appender的方式:同步是指logger自身一个个地遍历appenders,将LogEvent传递给每个appenders(appender可能会有一个BlockingQueue来存储LogEvent,当然也可以像ConsoleAppender那样啥都没有):

//同步logger遍历将LogEvent传递给appenders:LoggerConfig.java类
protected void callAppenders(final LogEvent event) {
        final AppenderControl[] controls = appenders.get();
        //noinspection ForLoopReplaceableByForEach
        for (int i = 0; i < controls.length; i++) {
            controls[i].callAppender(event);
        }
    }

异步logger是指logger不需要遍历appenders,而是将LogEvent放到一个统一的“地方”,然后再由一个独立的分发器将LogEvent取出来并分发给对应的appenders。以log4j2为例,这个独立的分发器叫Disruptor,而这个统一的“地方”就是位于Disruptor里的RingBuffer:

//AsyncLoggerDisruptor将LogEvent放到RingBuffer,无阻塞:AsyncLoggerDisruptor.java
boolean tryPublish(final RingBufferLogEventTranslator translator) {
        try {
            return disruptor.getRingBuffer().tryPublishEvent(translator);
        } catch (final NullPointerException npe) {
            // LOG4J2-639: catch NPE if disruptor field was set to null in stop()
            logWarningOnNpeFromDisruptorPublish(translator);
            return false;
        }
    }

关于Disruptor的介绍,详见:Disruptor核心原理、源码解析_邋遢的流浪剑客的博客-CSDN博客_disruptor源码

这里的同步Appender和异步Appender是指Appender在将LogEvent输出的时候,是同步还是异步。比如ConsoleAppender就是同步的,而logback和log4j2的XMDFileAppender就是异步的。


@Plugin(name = "XMDFile", category = "Core", elementType = "appender", printObject = true)
public final class XMDFileAppender extends AbstractAppender {
  private final BlockingQueue<Serializable> queue;
    //异步线程,从queue中曲LogEvent来消费
	private AsyncThread thread;
	//略
}

回顾下前面一小节,logger的同步异步是指将logEvent交接给appender的方式,而appender的同步异步是指logEvent输出的方式。由此我们得到以下四种组合:

Logger类型

Appender类型

性能

log4j2默认选型

推荐指数

Logger

Appender

性能最差

默认使用的是同步Logger;

Appender取决于用户在log4j2.xml中的配置

⭐️

AsyncLogger

Appender

性能一般

⭐️ ⭐️

Logger

AsyncAppender

性能较好;占用宿主机资源少一些

⭐️ ⭐️ ⭐️ ⭐️ ⭐️

AsyncLogger

AsyncAppender

性能最好;占用宿主机资源多一些,可能存在消息丢失

⭐️ ⭐️ ⭐️ ⭐️

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值