「来源: |GitHub大本营 ID:githubcode」关注「Github大本营」,选择“设为星标”回复「资源」,赠送 价值12800元 编程资料一份~Logback算是<em>JAVA</em> 里一个老牌的日志框架,从06年开始第一个版本,迭代至今也十几年了。
2021-05-31 10:00:59
「來源: |GitHub大本營 ID:githubcode」
關注「Github大本營」,選擇「設為星標」
回覆「資源」,贈送 價值12800元 程式設計資料一份~
Logback算是JAVA 裡一個老牌的日誌框架,從06年開始第一個版本,迭代至今也十幾年了。不過logback最近一個穩定版本還停留在 2017 年,好幾年都沒有更新;logback的兄弟 slf4j 最近一個穩定版也是2017年,有點涼涼的意思。
而且 logback的非同步效能實在拉跨,功能簡陋,配置又繁瑣,遠不及Apache 的新一代日誌框架 - Log4j2
目前來看,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-apiorg.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的形式:
publicstatic 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的支援,通過這些介面可以實現「惰性」打日誌:
voiddebug(String message, Supplier<?>... paramSuppliers);voidinfo(String message, Supplier<?>... paramSuppliers);voidtrace(String message, Supplier<?>... paramSuppliers);voiderror(String message, Supplier<?>... paramSuppliers);//等同於下面的先判斷,後列印logger.debug("入參報文:{}",() -> JSON.toJSONString(policyDTO));if(logger.isDebugEnabled()){logger.debug("入參報文:{}",JSON.toJSONString(policyDTO));}這種 Supplier + Lambda 的形式,等同於上面的先判斷 isDebugEnable 然後列印,三行的程式碼變成了一行。嗯,真香。不會 Lambda?可以關注公眾號Java技術棧,在後臺回覆:java,可以獲取我整理的 Java 8+ 系列教程,非常齊全。
更簡化的配置
Log4j 2 同時支援XML/JSON/YML/Properties 四種形式的配置檔案,不過最主流的還是XML的方式,最直觀。Spring Boot 日誌整合,推薦看下。
來看一下logback和log4j2的配置檔案對比,同樣功能的配置下:
logback.xml
<?xml version="1.0" encoding="UTF-8"?><configuration><appendername = "File"class= "ch.qos.logback.core.rolling.RollingFileAppender"><file>logs/app.log</file><rollingPolicyclass="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>logs/archives/app-%d{yyyy-MM-dd}.log.gz</fileNamePattern><!--一天內大於size就單獨分隔--><maxFileSize>1 GB</maxFileSize></rollingPolicy></appender><rootlevel="info"><appender-refref="File"/></root></configuration>log4j2.xml
<?xml version="1.0" encoding="UTF-8"?><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-dd HH:mm:ss.SSS} %5p [%t] %-40.40c{1.} : %m%n"/><Policies><TimeBasedTriggeringPolicy /><!--一天內大於size就單獨分隔--><SizeBasedTriggeringPolicysize="1 GB"/></Policies></RollingFile></Appenders><Loggers><Rootlevel="INFO"><AppenderRefref="File"/></Root></Loggers></Configuration>在log4j2中,appender的配置從使用 Appender 實現名即標籤名的形式,語法上更簡潔一些:
<RollingFilename="File"><!-- 等同於logback中的 --><appendername = "File"class= "ch.qos.logback.core.rolling.RollingFileAppender">與其他日誌抽象/門面適配
log4j2 由於拆分為 API 和 實現兩部分,所以可能也需要和其他日誌框架進行適配,詳細的日誌框架適配方案請參考我的另一篇文章。
其他的特點
非同步佇列使用高效能佇列 - LMAX DisruptorAppender豐富,有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時,需要注意項目中是否有多套日誌框架共存/衝突,需要適配的問題。具體可以參考:全網最全 Java 日誌框架適配方案,細節請參考上面的與其他日誌抽象/門面適配。
配置檔案示例
首先是配置檔案,預設的配置檔案路徑為:classpath:log4j2.xml(推薦使用xml)
<?xml version="1.0" encoding="UTF-8"?><Configurationxmlns:xi="http://www.w3.org/2001/XInclude"status="warn"name="XInclude"><Properties><Propertyname="PATTERN"value="%d{yyyy-MM-dd HH:mm:ss.SSS} %5p [%t] %-40.40c{1.} : %m%n"/></Properties><Appenders><!-- 輸出到控制檯,僅在本地開發環境使用 --><Consolename="Console"target="SYSTEM_OUT"><PatternLayoutpattern="${PATTERN}"/></Console><!--輸出到日誌檔案,滾動分割日誌檔案,自動打包gz--><RollingFilename="File"fileName="logs/app.log"filePattern="logs/archives/app-%d{yyyy-MM-dd}-%i.log.gz"><PatternLayoutpattern="${PATTERN}"/><Policies><!--預設一天一個檔案--><TimeBasedTriggeringPolicy /><!--一天內大於size就單獨分隔--><SizeBasedTriggeringPolicysize="1 GB"/></Policies></RollingFile></Appenders><Loggers><!-- 新增你的自定義logger,一般用於區分包名的日誌,不同包名不同的級別/appender --><!-- additivity 意思是,呼叫完當前appender,是否繼續呼叫parent logger appender,預設true--><Loggername="your logger/package name"level="debug"additivity="false"/><!--預設的Root Logger 級別--><Rootlevel="INFO"><!--這裡需要區分下環境(配合maven profile之類的)--><!-- 開發環境使用Console Appender,生產環境使用File Appender --><AppenderRefref="Console"/><AppenderRefref="File"/></Root></Loggers></Configuration>XML配置檔案語法
<?xml version="1.0" encoding="UTF-8"?>;<Configuration><Properties><Propertyname="name1">value</property><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:
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了!
作者:空無連結:https://juejin.cn/post/6945753017878577165
相關文章
「来源: |GitHub大本营 ID:githubcode」关注「Github大本营」,选择“设为星标”回复「资源」,赠送 价值12800元 编程资料一份~Logback算是<em>JAVA</em> 里一个老牌的日志框架,从06年开始第一个版本,迭代至今也十几年了。
2021-05-31 10:00:59
2020年苹果发布<em>iPhone</em>12系列的时候将2016年之前的笔记本充电方式和无线充电结合起来,变身成为Magesahe磁吸充电方式。其充电原理还是无线充电,但是在手机内部增加了一圈磁铁,可以在进行充电的时候更快的对准
2021-05-31 10:00:46
现代人看手机、看电脑的时间越来越多,蓝光的功能越来越重要,在<em>iPhone</em>与Mac上其实都有提供防蓝光的功能,今天小编教大家开启<em>iPhone</em>和Mac上的防滤蓝光功能的方法。开启<em>iPhone</em> 蓝光功能 要开启<
2021-05-31 10:00:39
去年华为备受美国的打压,国民是极其的愤怒,对于多个国家禁售<em>苹果手机</em>,那我们国家为什么没有对<em>苹果手机</em>进行禁售呢?其实也是因为这其中关乎我国众多企业的利益。 我们都知道,最开始我国的手机市场被
2021-05-31 10:00:14
处理器电压方面用的是普遍参数,10代i7而言<em>CPU</em> VCCIO和SA是内存控制器电压1.3V没有压力。DRAM voltage是内存电压,三星b-die压个1.5V不是问题,不过我一开始还是谨慎点,压1.4V先。3600@C20很顺利开机了,性能提升到
2021-05-31 09:31:05
比如新的第三代至强可扩展处理器在计算OpenSSL RSA 2048位的签名上,相比上一代<em>CPU</em>,单线程情况下有5.6倍的提升,在进行AES-GCM对称加密方式的情况下,相对上一代产品,单线程情况下有3.3倍的提升,这个提升幅度
2021-05-31 09:30:51