最牛逼的 Java 日志框架,性能无敌,横扫所有对手…

Logback 算是JAVA 里一个老牌的日志框架,从06年开始第一个版本,迭代至今也十几年了。不过logback最近一个稳定版本还停留在 2017 年,好几年都没有更新;logback的兄弟 slf4j 最近一个稳定版也是2017年,有点凉凉的意思。

而且 logback的异步性能实在拉跨,功能简陋,配置又繁琐,远不及Apache 的新一代日志框架 - Log4j

目前来看,Log4j2 就是王者,其他日志框架都不是对手

Log4j2简介
Apache Log4j 2是 Log4j(1) 的升级版,比它的祖先 Log4j 1. x 有了很大的改进,和logback对比有很大的改进。除了内部设计的调整外,主要有以下几点的大升级:

更简化的配置
更强大的参数格式化
最夸张的异步性能

Log4j 2中,分为 API(log4j-api)和实现(log4j-core) 两个模块。API 和slf4j 是一个类型,属于日志抽象/门面,而实现部分,才是Log4j 2的核心。

org.apache.logging.log4j » log4j-api
org.apache.logging.log4j » log4j-core

最强的异步性能
这个特性,算是Log4j2最强之处了。log4j2 在目前JAVA中的日志框架里,异步日志的性能是最高的,没有之一。

先来看一下,几种日志框架benchmark对比结果(log4j2官方测试结果):

从图上可以看出,log4j2的异步(全异步,非混合模式)下的性能,远超log4j1和logback,简直吊打。压力越大的情况下,吞吐上的差距就越大。在64线程测试下,log4j2的吞吐达到了180w+/s,而logback/log4j1只有不到20w,相差近十倍

零GC(Garbage-free)
从2.6版本开始(2016年),log4j2 默认就以零GC模式运行了。什么叫零GC呢?就是不会由于log4j2而导致GC。

log4j2 中各种Message对象,字符串数组,字节数组等全部复用,不重复创建,大大减少了无用对象的创建,从而做到“零GC”。

更高性能 I/O 写入的支持
log4j 还提供了一个MemoryMappedFileAppender,I/O 部分使用MemoryMappedFile来实现,可以得到极高的I/O性能。不过在使用MemoryMappedFileAppender之前,得确定你足够了解MemoryMappedFile的相关知识,否则不要轻易使用呦。

更强大的参数格式化
API模块和slf4j相比,提供了更丰富的参数格式化功能。

使用{}占位符格式化参数

在slf4j里,我们可以用{}的方式来实现“format”的功能(参数会直接toString替换占位符),像下面这样:

logger.debug(“Logging in user {} with birthday {}”, user.getName(), user.getBirthdayCalendar());
使用String.format的形式格式化参数
log4j2 中除了支持{}的参数占位符,还支持String.format的形式:

public static Logger logger = LogManager.getFormatterLogger("Foo");logger.debug("Logging in user %s with birthday %s", user.getName(), user.getBirthdayCalendar());
logger.debug("Logging in user %1$s with birthday %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, "Logging in user %1$s with birthday %2$tm %2$te,%2$tY", user.getName(), user.getBirthdayCalendar());logger.debug("Opening connection to {}...", someDataSource);

“惰性”打日志(lazy logging)
这个功能虽然小,但非常实用。

在某些业务流程里,为了留根或追溯问题,需要完整的打印入参,一般是把入参给用JSON/XML序列化后用debug级别打印:

logger.debug("入参报文:{}",JSON.toJSONString(policyDTO));

如果需要追溯问题时,会将系统的日志级别调到debug/trace,这样就可以打印。但是这里有个问题,虽然在info级别下debug不会输出内容,但JSON.toJSONString()这个序列化的代码一定会执行,严重影响正常流程下的执行效率。

我们期望的结果是info级别下,连序列化都不执行。这里可以通过isDebugEnable来判断当前配置下debug级别是否可以输出:

if(logger.isDebugEnabled()){logger.debug("入参报文:{}",JSON.toJSONString(policyDTO));
}

这样虽然可以避免不必要的序列化,但每个地方都这么写还是有点难受的,一行变成了三行。

log4j2 的 logger 对象,提供了一系列lambda的支持,通过这些接口可以实现“惰性”打日志:

void debug(String message, Supplier<?>... paramSuppliers);
void info(String message, Supplier<?>... paramSuppliers);
void trace(String message, Supplier<?>... paramSuppliers);
void error(String message, Supplier<?>... paramSuppliers);//等同于下面的先判断,后打印
logger.debug("入参报文:{}",() -> JSON.toJSONString(policyDTO));if(logger.isDebugEnabled()){logger.debug("入参报文:{}",JSON.toJSONString(policyDTO));
}

这种 Supplier + Lambda 的形式,等同于上面的先判断 isDebugEnable 然后打印,三行的代码变成了一行。嗯,真香。

更简化的配置
Log4j 2 同时支持XML/JSON/YML/Properties 四种形式的配置文件,不过最主流的还是XML的方式,最直观。

来看一下logback和log4j2的配置文件对比,同样功能的配置下:

logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration><appender name = "File" class= "ch.qos.logback.core.rolling.RollingFileAppender"><file>logs/app.log</file><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>logs/archives/app-%d{yyyy-MM-dd}.log.gz</fileNamePattern><!--一天内大于size就单独分隔--><maxFileSize>1 GB</maxFileSize></rollingPolicy></appender><root level="info"><appender-ref ref="File"/></root>
</configuration>

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration xmlns:xi="http://www.w3.org/2001/XInclude"status="warn" name="XInclude"><Appenders><RollingFile name="File" fileName="logs/app.log" filePattern="logs/archives/app-%d{yyyy-MM-dd}-%i.log.gz"><PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %5p [%t] %-40.40c{1.} : %m%n"/><Policies><TimeBasedTriggeringPolicy /><!--一天内大于size就单独分隔--><SizeBasedTriggeringPolicy size="1 GB"/></Policies></RollingFile></Appenders><Loggers><Root level="INFO"><AppenderRef ref="File"/></Root></Loggers>
</Configuration>

在log4j2中,appender的配置从使用 Appender 实现名即标签名的形式,语法上更简洁一些:

<RollingFile name="File"><!-- 等同于logback中的 -->
<appender name = "File" class= "ch.qos.logback.core.rolling.RollingFileAppender">

与其他日志抽象/门面适配
log4j2 由于拆分为 API 和 实现两部分,所以可能也需要和其他日志框架进行适配

其他的特点
异步队列使用高性能队列 - LMAX Disruptor
Appender丰富,有JMS/JPA/KAFKA/Http/MONGODB/CouchDB/Socket/Script等各种Appender的支持
支持自定义日志级别 ……
基本用法
终于介绍完了Log4j2的强大,现在来介绍下Log4j2的基本使用。

引用log4j2的maven依赖
log4j-api在log4j-core中已经有依赖了,直接依赖core即可

<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.14.1</version>
</dependency>

注意,引用log4j2时,需要注意项目中是否有多套日志框架共存/冲突,需要适配的问题。细节请参考上面的与其他日志抽象/门面适配

配置文件示例
首先是配置文件,默认的配置文件路径为:classpath:log4j2.xml(推荐使用xml)

<?xml version="1.0" encoding="UTF-8"?>
<Configuration xmlns:xi="http://www.w3.org/2001/XInclude"status="warn" name="XInclude"><Properties><Property name="PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %5p [%t] %-40.40c{1.} : %m%n"/></Properties><Appenders><!-- 输出到控制台,仅在本地开发环境使用 --><Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="${PATTERN}"/></Console><!--输出到日志文件,滚动分割日志文件,自动打包gz--><RollingFile name="File" fileName="logs/app.log" filePattern="logs/archives/app-%d{yyyy-MM-dd}-%i.log.gz"><PatternLayout pattern="${PATTERN}"/><Policies><!--默认一天一个文件--><TimeBasedTriggeringPolicy /><!--一天内大于size就单独分隔--><SizeBasedTriggeringPolicy size="1 GB"/></Policies></RollingFile></Appenders><Loggers><!-- 添加你的自定义logger,一般用于区分包名的日志,不同包名不同的级别/appender --><!-- additivity 意思是,调用完当前appender,是否继续调用parent logger appender,默认true--><Logger name="your logger/package name" level="debug" additivity="false"/><!--默认的Root Logger 级别--><Root level="INFO"><!--这里需要区分下环境(配合maven profile之类的)--><!-- 开发环境使用Console Appender,生产环境使用File Appender --><AppenderRef ref="Console"/><AppenderRef ref="File"/></Root></Loggers>
</Configuration>

XML配置文件语法

<?xml version="1.0" encoding="UTF-8"?>;
<Configuration><Properties><Property name="name1">value</property><Property name="name2" value="value2"/></Properties><filter  ... /><Appenders><appender ... ><filter  ... /></appender>...</Appenders><Loggers><Logger name="name1"><filter  ... /></Logger>...<Root level="level"><AppenderRef ref="name"/></Root></Loggers>
</Configuration>

创建Logger
直接使用log4j2的api:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;Logger logger = LogManager.getLogger(Log4j2Test.class);
logger.error(...);
logger.warn(...);
logger.info(...);
logger.debug(...);
logger.trace(...);

如果是配合slf4j使用也是可以的,只需要按照前面说的,提前做好适配,然后使用slf4j的api即可。不过如果是新系统的话,建议直接上log4j2的api吧,可以享受所有log4j2的功能,使用slf4j之类的api时,上面说的参数格式化之类的功能就无法使用了。

全异步配置(重要!!
推荐配置log4j2 全异步(all async),在你的启动脚本中增加一个系统变量的配置:

-Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector

总结
Log4j2 如今性能最强,功能最强,而且持续更新维护。还在等什么?是时候替换你的logback/log4j1了!

最牛逼的 Java 日志框架,还不学习。。。相关推荐

  1. 最牛逼的 Java 日志框架

    Logback 算是JAVA 里一个老牌的日志框架,从06年开始第一个版本,迭代至今也十几年了.不过logback最近一个稳定版本还停留在 2017 年,好几年都没有更新:logback的兄弟 slf ...

  2. 最牛逼的 Java 日志框架,性能无敌,横扫所有对手

    Logback 算是JAVA 里一个老牌的日志框架,从06年开始第一个版本,迭代至今也十几年了.不过logback最近一个稳定版本还停留在 2017 年,好几年都没有更新:logback的兄弟 slf ...

  3. 最牛逼的 Java 日志框架,性能无敌,横扫所有对手.....

    欢迎关注方志朋的博客,回复"666"获面试宝典 来源:juejin.cn/post/6945753017878577165 Logback 算是JAVA 里一个老牌的日志框架,从0 ...

  4. 最牛逼的 Java 日志框架,性能无敌,横扫所有对手。。

    点击关注公众号,Java干货及时送达 作者:空无 链接:https://juejin.cn/post/6945753017878577165 Logback 算是JAVA 里一个老牌的日志框架,从06 ...

  5. 最牛逼的 Java 日志框架,性能无敌!

    点击上方☝码猿技术专栏 轻松关注,设为星标! 及时获取有趣有料的技术 Logback 算是JAVA 里一个老牌的日志框架,从06年开始第一个版本,迭代至今也十几年了.不过logback最近一个稳定版本 ...

  6. java日志框架(一)JUL 学习 ,这个是什么,他在代码中如何使用,一篇文章讲清楚

    这里写目录标题 JUL 是什么 JUL组件介绍 代码中如何使用(控制台输出) 日志级别 自定义输出级别 输出日志到文件(磁盘文件中) 日志对象父子关系 配置文件 使用方法总结 JUL 是什么 JUL全 ...

  7. 一款非常牛逼的Java爬虫框架(高度灵活可配置)

    点击关注公众号,利用碎片时间学习 介绍 平台以流程图的方式定义爬虫,是一个高度灵活可配置的爬虫平台 特性 支持Xpath/JsonPath/css选择器/正则提取/混搭提取 支持JSON/XML/二进 ...

  8. 多种java 日志框架【超详细图文】

    一.目标 日志的作用和目的 日志的框架 JUL的使用 LOG4J的使用 JCL的使用 二.日志的概念 2.1 日志文件 日志文件是用于记录系统操作事件的文件集合,可分为事件日志和消息日志.具有处理历史 ...

  9. 最牛逼的开源机器学习框架,你知道几个

    最牛逼的开源机器学习框架,你知道几个 作者 大白鲸团队 关注 2015.12.29 20:16 字数 1829 阅读 3689评论 0喜欢 7 机器学习毫无疑问是当今最热的话题,它已经渗透到生活的方方 ...

最新文章

  1. JavaScript中的+0与-0
  2. 华为设备ENSP静态路由的配置实战
  3. linux 串口 dma,STM32 USART串口DMA 接收和发送流程详解
  4. 【React Native 安卓开发】----(Picker)【第四篇】
  5. VS2012配置FreeImage
  6. ppt(office365)之表格使用说明
  7. 新唐(Nuvoton)8051单片机开发指南
  8. html实现视频录制,保存和回放
  9. Linux使用技巧5--格式化U盘
  10. android libbinder – Binder的Native实现
  11. 易语言文本比较特征码
  12. 美国大学生足球联赛数据集football——node2vec
  13. Linux各发行版的前世今生
  14. 技术分享 | mimikatz的常见使用方法
  15. python简单数字游戏大全_python数字游戏,让你欲罢不能!
  16. 数据结构与算法(九)—— 二叉树结构及其实现和应用
  17. 黑客零基础入门教程:「黑客攻防实战从入门到精通(第二版)」堪称黑客入门天花板
  18. 社群运营5招激活杀手锏、5个沟通技巧、5大目的
  19. 前端歌谣的刷题之路-第六题-加粗文字
  20. 基于Simulink 与TI DSP的模型设计的环境搭建(一)

热门文章

  1. windows 7的SYSTEM权限
  2. @InitBinder的使用
  3. mingw 配置 opencv与vscode
  4. mysql设置索引长度_修改Mysql索引长度限制
  5. 如何轻松应对述职专题四之问答篇
  6. '小兔子'的感情人生
  7. 小程序源码:和平精英吃鸡捏脸数据助手
  8. 计算机编程薪资真有那么高?真实,有的一毕业就失业,有的一毕业就进大厂
  9. 突然在网上看到看到一首诗...跟我网名一样...转载过来保存下...
  10. VUE3.X——父组件调用子组件方法