当前位置: 首页 > 科技观察

我没有使用Java的旧日志记录框架Logback,而是使用Log4j2!

时间:2023-03-18 19:07:41 科技观察

Logback是Java中的老式日志记录框架。它的第一个版本从2006年开始,至今已经迭代了十多年。图片来自Pexels,不过Logback最新的稳定版还是2017年的,好几年没更新了;Logback的兄弟slf4j最新的稳定版也是2017年的,有点爽。而且Logback的异步性能实在捉襟见肘,功能简单,配置繁琐,远不如Apache的新一代日志框架:Log4j2。目前Log4j2为王,其他日志框架不是对手!Log4j2简介ApacheLog4j2是Log4j(1)的升级版,相对于它的祖先Log4j1.x有很大的改进,与Logback相比有很大的改进。除了内部设计的调整外,主要升级有以下几点:简化的配置更强大的参数格式化最夸张的异步性能在Log4j2中,分为API(log4j-api)和实现(log4j-core)**两个模块。API和slf4j是一个类型,属于loggingabstraction/facade。实现部分是Log4j2的核心:org.apache.logging.log4j?log4j-apiorg.apache.logging.log4j?log4j-core最强大的性能①最强的异步性能这个特性是Log4j2最强的地方。在java中log4j2目前的日志框架中,异步日志的性能是最高的,没有之一。再来看看几款日志框架的benchmark对比结果(log4j2官方测试结果):从图中可以看出,Log4j2的异步(全异步,非混合模式)性能远超Log4j1和Logback。.压力越大,吞吐量的差距就越大。64线程测试下,Log4j2的吞吐量达到了180w+/s,而Logback/Log4j1不到20w,相差近十倍。②ZeroGC(Garbage-free)从2.6(2016)版本开始,Log4j2默认运行在zeroGC模式。什么是零GC?这意味着不会有GC由于Log4j2。Log4j2中的各种Message对象、字符串数组、字节数组等都是多路复用的,不重复创建,大大减少了无用对象的创建,从而实现“零GC”。③支持更高性能的I/O编写Log4j还提供了MemoryMappedFileAppender,I/O部分使用MemoryMappedFile实现,可以获得极高的I/O性能。但是在使用MemoryMappedFileAppender之前,请确保您对MemoryMappedFile有足够的了解,否则不要轻易使用它。更强大的参数格式化API模块,提供了比slf4j更丰富的参数格式化功能。①使用{}占位符格式化参数在slf4j中,我们可以使用{}来实现“格式化”功能(参数会直接将占位符替换为toString)。像下面这样:logger.debug("Logginginuser{}withbirthday{}",user.getName(),user.getBirthdayCalendar());②String.format形式的格式化参数在Log4j2中,除了支持{}字符的参数占位符外,还支持String.format形式:publicstaticLoggerlogger=LogManager.getFormatterLogger("Foo");logger.debug("Logginginuser%swithbirthday%s",user.getName(),user.getBirthdayCalendar());logger.debug("登录用户%1$swithbirthday%2$tm%2$te,%2$tY",user.getName(),user.getBirthdayCalendar());logger.debug("Integer.MAX_VALUE=%,d",Integer.MAX_VALUE);logger.debug("Long.MAX_VALUE=%,d",Long.MAX_VALUE);注意:如果要使用String.format,需要使用LogManager.getFormatterLogger,而不是LogManager.getLogger。③使用logger.printf格式化参数在Log4j2的Logger接口中,还有一个printf方法,可以在不创建LogManager.getFormatterLogger的情况下以String.format的形式使用:logger.printf(Level.INFO,"Logginginuser%1$swithbirthday%2$tm%2$te,%2$tY",user.getName(),user.getBirthdayCalendar());logger.debug("Openingconnectionto{}...",someDataSource);④“惰性”日志记录(lazylogging)这个功能虽然小,但是非常好用。在一些业务流程中,为了留根或跟踪问题,需要将输入的参数完整打印出来。通常,输入参数用JSON/XML序列化,然后在debug级别打印:logger.debug("Inputparametermessage:{}",JSON.toJSONString(policyDTO));如果问题需要跟踪,系统会将日志级别调整为debug/trace,以便打印。但是这里有一个问题。debug虽然不会输出info级别的内容,但是序列化代码JSON.toJSONString()肯定会被执行,严重影响正常流程下的执行效率。我们期望的结果是,在info层面,连序列化都不做。这里可以通过isDebugEnable判断当前配置下是否可以输出debug级别:if(logger.isDebugEnabled()){logger.debug("Inputparametermessage:{}",JSON.toJSONString(policyDTO));}虽然这样可以避免不必要的序列化,但是到处这样写还是有点不爽,一行变成三行。Log4j2的logger对象提供了一系列的Lambda支持。通过这些接口,可以实现“惰性”日志记录:.paramSuppliers);voiderror(Stringmessage,Supplier...paramSuppliers);//相当于下面先判断,然后打印logger.debug("Inputparametermessage:{}",()->JSON.toJSONString(policyDTO));if(logger.isDebugEnabled()){logger.debug("Inputmessage:{}",JSON.toJSONString(policyDTO));}这种Supplier+Lambda的形式相当于上面的方法先判断isDebugEnable再打印,三行代码变成一行。嗯,很好吃。简化配置Log4j2也支持四种形式的配置文件:XML/JSON/YML/Properties,但最主流和直观的方式是XML。下面看一下Logback和Log4j2的配置文件对比,在相同功能的配置下。logback.xml:logs/app.loglogs/archives/app-%d{yyyy-MM-dd}.log.gz1GBlog4j2.xml:<政策>在log4j2中,appender的配置来自于使用Appender实现名即标签名的形式,语法更简洁:等日志抽象/门面适配Log4j2由于拆分成API和实现部分,所以可能还需要适配其他日志框架详细的日志框架适配方案可以参考我的另一篇文章《【可能是全网最全的】JAVA日志框架适配/冲突解决方案》:https://juejin.cn/post/6945220055399399455其他特点如下:异步队列使用高性能队列-**LMAXDisruptor**Appender丰富,还有JMS/JPA/KAFKA/Http/MONGODB/CouchDB/Socket/Script等支持自定义日志级别的Appenders……基本用法终于介绍了Log4j2的强大。下面介绍一下Log4j2的基本用法。①引用Log4j2的Maven依赖log4j-api,在log4j-core中已经有了依赖,可以直接依赖core:org.apache.logging.log4jlog4j-core2.14.1注意在引用Log4j2时需要注意项目中是否存在多套日志框架共存/冲突,需要适配。有关详细信息,请参阅上面的与其他日志抽象/门面的适配。②配置文件示例首先是配置文件,默认配置文件路径为:classpath:log4j2.xml(推荐使用xml):③XML配置文件语法如下:;value>/appender>......④直接使用Log4j2API创建Logger:importorg.apache.logging.log4j.LogManager;importorg.apache.logging.log4j.Logger;Loggerlogger=LogManager.getLogger(Log4j2Test.class);logger.error(...);logger.warn(...);logger.info(...);logger.debug(...);logger.trace(...);和slf4j一起使用也是可以的,按照上面的,提前适配一下,再使用slf4j的API就可以了。但是如果是新系统,建议直接使用Log4j2API,这样可以享受Log4j2的所有功能。在使用slf4j等API时,上面提到的参数都是这样的格式化函数,是不可用的。⑤全异步配置(重要!!)建议配置Log4j2全异步(allasync),在你的启动脚本中添加一个系统变量配置:-Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector总结Log4j2是目前功能最强大的,而且还在不断的更新维护中。你在等什么?是时候更换您的Logback/Log4j1了!作者:孔武编辑:陶家龙