0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Java日志框架中的王者是谁

Android编程精选 来源:掘金 作者:空无 2021-10-13 09:12 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

来源丨juejin.cn/post/6945753017878577165

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中的日志框架里,异步日志的性能是最高的,没有之一。

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("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("Logginginuser%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);

“惰性”打日志(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的支持,通过这些接口可以实现“惰性”打日志:

voiddebug(Stringmessage,Supplier...paramSuppliers);
voidinfo(Stringmessage,Supplier...paramSuppliers);
voidtrace(Stringmessage,Supplier...paramSuppliers);
voiderror(Stringmessage,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


<configuration>
<appendername="File"class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/app.logfile>
<rollingPolicyclass="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/archives/app-%d{yyyy-MM-dd}.log.gzfileNamePattern>

<maxFileSize>1GBmaxFileSize>
rollingPolicy>
appender>
<rootlevel="info">
<appender-refref="File"/>
root>
configuration>

log4j2.xml


<Configurationxmlns:xi="http://www.w3.org/2001/XInclude"
status="warn"name="XInclude">
<Appenders>
<RollingFilename="File"fileName="logs/app.log"filePattern="logs/archives/app-%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayoutpattern="%d{yyyy-MM-ddHHss.SSS}%5p[%t]%-40.40c{1.}:%m%n"/>
<Policies>
<TimeBasedTriggeringPolicy/>

<SizeBasedTriggeringPolicysize="1GB"/>
Policies>
RollingFile>
Appenders>
<Loggers>
<Rootlevel="INFO">
<AppenderRefref="File"/>
Root>
Loggers>
Configuration>

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

<RollingFilename="File">

<appendername="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.log4jgroupId>
<artifactId>log4j-coreartifactId>
<version>2.14.1version>
dependency>

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

配置文件示例

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


<Configurationxmlns:xi="http://www.w3.org/2001/XInclude"
status="warn"name="XInclude">
<Properties>
<Propertyname="PATTERN"value="%d{yyyy-MM-ddHHss.SSS}%5p[%t]%-40.40c{1.}:%m%n"/>
Properties>
<Appenders>

<Consolename="Console"target="SYSTEM_OUT">
<PatternLayoutpattern="${PATTERN}"/>
Console>

<RollingFilename="File"fileName="logs/app.log"filePattern="logs/archives/app-%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayoutpattern="${PATTERN}"/>
<Policies>

<TimeBasedTriggeringPolicy/>

<SizeBasedTriggeringPolicysize="1GB"/>
Policies>
RollingFile>
Appenders>
<Loggers>


<Loggername="yourlogger/packagename"level="debug"additivity="false"/>

<Rootlevel="INFO">


<AppenderRefref="Console"/>
<AppenderRefref="File"/>
Root>
Loggers>
Configuration>

XML配置文件语法

;
<Configuration>
<Properties>
<Propertyname="name1">valueproperty>
<Propertyname="name2"value="value2"/>
Properties>
<filter.../>
<Appenders>
<appender...>
<filter.../>
appender>
...
Appenders>
<Loggers>
<Loggername="name1">
<filter.../>
Logger>
...
<Rootlevel="level">
<AppenderRefref="name"/>
Root>
Loggers>
Configuration>

创建Logger

直接使用log4j2的api:

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即可。不过如果是新系统的话,建议直接上log4j2的api吧,可以享受所有log4j2的功能,使用slf4j之类的api时,上面说的参数格式化之类的功能就无法使用了。

全异步配置(重要!!)

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

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

总结

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

责任编辑:haq
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • JAVA
    +关注

    关注

    20

    文章

    3006

    浏览量

    116835
  • 框架
    +关注

    关注

    0

    文章

    404

    浏览量

    18497
  • 日志
    +关注

    关注

    0

    文章

    149

    浏览量

    11097

原文标题:最牛逼的 Java 日志框架,性能无敌,横扫所有对手.....

文章出处:【微信号:AndroidPush,微信公众号:Android编程精选】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    Java并发编程的“基石”——多线程概念初识

    (GC)调优手段,使得工程师可以在复杂的长周期任务调度,精准控制内存起伏,避免因内存泄漏导致的集群停摆。 三、 跨界融合:Java 调度框架与 AI 生态的深度耦合 在当下的主流 AI 算力调度平台(如
    发表于 04-16 18:50

    码神之路Netty-从零实现RPC框架课分享

    ——RPC(远程过程调用)框架。它像人体的神经系统一样,连接着各个服务器官,确保指令的准确传达。Netty,作为 Java 领域当之无愧的网络通信王者,其高性能、高并发的设计理念,使其成为构建现代 RPC
    的头像 发表于 02-13 11:38 148次阅读

    模组日志功能技术概览

    本文是对 4G 模组, 以及 4G+GNSS 模组的日志功能的总体介绍。 通过日志,可以对研发过程,以及模组运行过程的各种故障进行分析。 二、4G 模组
    的头像 发表于 01-14 15:32 243次阅读
    模组<b class='flag-5'>日志</b>功能技术概览

    RT-Thread ULOG: 创建多个文件后端并保存不同日志方法 | 技术集结

    目录前言使用场景实现功能具体操作1前言在项目开发需要使用到日志功能来调试和查看问题。有些问题并不会在我们实时查看的时候发生,而是在你上个厕所的功夫可能就发生了。如果上位机的缓冲区不够大,可能错误
    的头像 发表于 12-15 19:22 5198次阅读
    RT-Thread ULOG: 创建多个文件后端并保存不同<b class='flag-5'>日志</b>方法 | 技术集结

    电能质量在线监测装置数据日志能加密存储吗?

    电能质量在线监测装置的数据日志 可以加密存储 ,且已成为工业级与电力系统合规应用的标准配置。加密机制通常采用 分级加密策略 ,并结合硬件安全模块保障密钥安全,确保日志数据的完整性与保密性。 一、日志
    的头像 发表于 12-05 10:16 757次阅读
    电能质量在线监测装置数据<b class='flag-5'>日志</b>能加密存储吗?

    医院随访管理系统源码,三级随访系统源码,Java+Springboot,Vue,Ant-Design+MySQL5

    Java版随访系统源码,医院随访管理系统源码,三级随访系统源码,B/S前后端分离架构,自主版权,落地案例。 技术框架Java+Springboot,Vue,Ant-Design+MySQL5 开发
    的头像 发表于 11-08 14:48 729次阅读
    医院随访管理系统源码,三级随访系统源码,<b class='flag-5'>Java</b>+Springboot,Vue,Ant-Design+MySQL5

    使用littlefs存储ulog日志,然后读日志文件会出错,为什么?

    使用littlefs存储ulog日志,然后通过命令读取日志文件,或者通过API接口读取或拷贝日志文件,都会导致线程卡死,尝试了多种方法都不行,有没有大佬有遇到或者处理过类似问题? 改成fatfs来存
    发表于 09-29 06:14

    Perforce JRebel 简介:即时加载代码变更,加速Java应用开发

    Perforce JRebel 专为Java开发提速而生!支持跳过构建与重新部署,实时加载代码变更,支持100+框架,无缝集成主流IDE与应用服务器。
    的头像 发表于 08-14 14:35 987次阅读
    Perforce JRebel 简介:即时加载代码变更,加速<b class='flag-5'>Java</b>应用开发

    电商API日志分析的实用工具

      在当今数字化电商时代,API(应用程序编程接口)已成为平台与外部系统交互的核心通道。电商API日志记录了每一次请求的详细信息,包括用户行为、交易状态、错误响应等。分析这些日志能帮助企业监控性能
    的头像 发表于 07-23 15:50 789次阅读
    电商API<b class='flag-5'>日志</b>分析的实用工具

    淘宝 vs 京东电商 API 接口,才是数据王者

    API进行客观比较,帮助您判断才是真正的“数据王者”。 1.API功能覆盖范围 API的功能范围决定了开发者能获取的数据类型。淘宝API通过阿里巴巴开放平台提供,覆盖商品、订单、用户、物流等多个模块。例如,商品API支持搜索、详情、评价等,数据
    的头像 发表于 07-08 15:51 1106次阅读
    淘宝 vs 京东电商 API 接口,<b class='flag-5'>谁</b>才是数据<b class='flag-5'>王者</b>?

    ArkUI-X框架LogInterface使用指南

    ) { } } 设置ArkUI-X框架LogInterface以及日志拦截等级 在需要控制ArkUI-X框架日志及TypeScript日志
    发表于 06-15 23:20

    远程日志errDump调试功能实战教程:案例驱动的故障排查!

    通过真实案例场景,本教程将展示如何利用远程日志errDump调试功能定位系统崩溃、性能瓶颈等问题,从日志捕获到原因分析,手把手带您体验实战的调试流程。 本文特别分享errDump功能
    的头像 发表于 06-09 16:51 862次阅读
    远程<b class='flag-5'>日志</b>errDump调试功能实战教程:案例驱动的故障排查!

    请问stm32cubeide如何查看版本日志

    stm32cubeide如何查看版本日志?看能支持哪些芯片型号?
    发表于 06-09 07:44

    详解journalctl日志管理

    systemd 提供了自己的日志系统(logging system),称为 journal。使用 systemd 日志,无需额外安装日志服务(syslog)。
    的头像 发表于 06-05 17:22 1932次阅读
    详解journalctl<b class='flag-5'>日志</b>管理

    DevEcoStudio 中使用模拟器时如何过滤日志

    设置 Log message: A03d00/JSAPP 当你看到不断更新的日志时,你会不会崩溃 因为 No-filters 模式下模拟器会输出系统所有日志信息,这个模式在开发并不使用,可用
    发表于 05-23 10:46