目錄
log4j2的介紹
Log4j2的性能
SpringBoot中的使用Log4j2
log4j2的進階--異步日志
?AsyncAppender方式
AsyncLogger方式?
log4j2的介紹
Apache Log4j 2是對Log4j的升級版,參考了logback的一些優秀的設計,并且修復了一些問題,因此帶 來了一些重大的提升,主要有:
- 異常處理,在 logback中,Appender中的異常不會被應用感知到,但是在log4j2中,提供了一些異 常處理機制。
- 性能提升, log4j2相較于log4j 和logback都具有很明顯的性能提升,后面會有官方測試的數據。
- 自動重載配置,參考了 logback的設計,當然會提供自動刷新參數配置,最實用的就是我們在生產 上可以動態的修改日志的級別而不需要重啟應用。
- 無垃圾機制, log4j2在大部分情況下,都可以使用其設計的一套無垃圾機制,避免頻繁的日志收集 導致的jvm gc。
官網地址:? ??https://logging.apache.org/log4j/2.x/
Log4j2的性能
Log4j2最牛的地方在于異步輸出日志時的性能表現,Log4j2在多線程的環境下吞吐量與Log4j和 Logback的比較如下圖。下圖比較中Log4j2有三種模式:1)全局使用異步模式;2)部分Logger采用異步模式;3)異步Appender。可以看出在前兩種模式下,Log4j2的性能較之Log4j和Logback有很大的 優勢。
無垃圾記錄
垃圾收集暫停是延遲峰值的常見原因,并且對于許多系統而言,花費大量精力來控制這些暫停。
許多日志庫(包括以前版本的Log4j)在穩態日志記錄期間分配臨時對象,如日志事件對象,字符串, 字符數組,字節數組等。這會對垃圾收集器造成壓力并增加GC暫停發生的頻率。
從版本2.6開始,默認情況下Log4j以“無垃圾”模式運行,其中重用對象和緩沖區,并且盡可能不分配臨 時對象。還有一個“低垃圾”模式,它不是完全無垃圾,但不使用ThreadLocal字段。
Log4j 2.6中的無垃圾日志記錄部分通過重用ThreadLocal字段中的對象來實現,部分通過在將文本轉換 為字節時重用緩沖區來實現。?
從圖中可以看出log4j2的性能是完全吊打其他日志框架的,而且log4j2的異步日志功能非常的強大,可以大大的減少日志系統對業務系統的負擔。基于這些功能,所以現在主流的日志開發架構就是SLF4J+Log4j2這個組合,所以這個log4j2這個日志框架是必須要學會的
SpringBoot中的使用Log4j2
springboot框架在企業中的使用越來越普遍,springboot日志也是開發中常用的日志系統。springboot 默認就是使用SLF4J作為日志門面,logback作為日志實現來記錄日志。所以如果我們要在springboot項目中使用Log4j2,需要內置的日志框架給去除。
分成三步,第一移除默認的日志框架,第二加入log4j2的依賴(啟動器),第三編寫配置文件
- 移除默認的日志框架
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><!--排除默認spring-boot-starter-logging啟動器--><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions> </dependency>
- 加入log4j2的依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId> </dependency>
編寫log4j2.xml配置文件‘
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"><!-- 定義全局變量,日志文件路徑和格式 --><Properties><Property name="log.path">./dev</Property><Property name="log.name">forlan-log4j2</Property><Property name="file.pattern">%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{50} - %msg%n</Property></Properties><!-- 控制臺輸出配置 --><Appenders><Console name="STDOUT" target="SYSTEM_OUT"><PatternLayout pattern="${file.pattern}"/><ThresholdFilter level="DEBUG"/></Console><!-- 文件輸出配置 --><RollingFile name="INFO_FILE" fileName="${log.path}/${log.name}.info.log"filePattern="${log.path}/%d{yyyy-MM-dd}/${log.name}.info.%d{yyyy-MM-dd}-%i.log"><PatternLayout pattern="${file.pattern}"/><LevelMatchFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/><!-- 每個文件最大10MB --><SizeBasedTriggeringPolicy size="10MB"/><!-- 最多保留30天的歷史記錄 --><DefaultRolloverStrategy max="30"/></RollingFile><!-- 文件輸出配置 --><RollingFile name="ERROR_FILE" fileName="${log.path}/${log.name}.error.log"filePattern="${log.path}/%d{yyyy-MM-dd}/${log.name}.error.%d{yyyy-MM-dd}-%i.log"><PatternLayout pattern="${file.pattern}"/><LevelMatchFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/><!-- 每個文件最大10MB --><SizeBasedTriggeringPolicy size="10MB"/><!-- 最多保留30天的歷史記錄 --><DefaultRolloverStrategy max="30"/></RollingFile></Appenders><!-- 設置root logger --><Loggers><Root level="INFO"><AppenderRef ref="STDOUT"/><AppenderRef ref="INFO_FILE"/><AppenderRef ref="ERROR_FILE"/></Root></Loggers> </Configuration>
- ?運行測試
@SpringBootTest public class Slf4jTest {// 聲明日志對象public final static Logger LOGGER = LoggerFactory.getLogger(Slf4jTest.class);@Testpublic void testQuick() throws Exception {//打印日志信息LOGGER.error("error");LOGGER.warn("warn");LOGGER.info("info");LOGGER.debug("debug");LOGGER.trace("trace");// 使用占位符輸出日志信息String name = "jack";Integer age = 18;LOGGER.info("用戶:{},{}", name, age);// 將系統異常信息寫入日志try {int i = 1 / 0;} catch (Exception e) {// e.printStackTrace();LOGGER.info("出現異常:", e);}} }
?
出現入上圖的結果就代表log4j2就配置成功了,主要注意那個dev的日志文件是否生成,這個日志文件是在前面的配置文件中配置的。
到這里log4j2的基本使用其實已經可以實現了,對于一些小的項目,這樣子配置就可以了,但對于那些大型項目,log4j2還可以更加強大,那就是使用它的異步日志功能?
log4j2的進階--異步日志
logl4j2最大的特點就是異步日志,其性能的提升主要也是從異步日志中受益,我們來看看如何使用 log4j2的異步日志。
Log4j2 提供了兩種實現日志的方式,一個是通過AsyncAppender,一個是通過AsyncLogger,分別對應 前面我們說的Appender組件和Logger組件。?
log4j2的全局異步AsyncLogger性能最好,第二個是混合異步AsyncLogger,性能最差的是AsyncAppender(和同步日志相比沒有什么性能提升。和logback性能一樣)
如果使用異步日志,全局異步AsyncLogger、混合異步AsyncLogger、AsyncAppender,不要同時使用。否則會使用性能較低的一種異步方式
?
注意:配置異步日志需要添加依賴
<!--異步日志依賴-->
?<dependency>
?????????<groupId>com.lmax</groupId>
?????????<artifactId>disruptor</artifactId>
?????????<version>3.3.4</version>
?</dependency>
?AsyncAppender方式
?AsyncAppender:這種使用方式較為簡單,只需要在我們上述的Appender中加入以下標簽即可:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" monitorInterval="5"><properties><property name="LOG_HOME">C:/Users/dell/Desktop/java11Test/logs</property></properties><Appenders><File name="File" fileName="${LOG_HOME}/myFile.log"><PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%-5level] %l --- %msg%n" /></File><!-- AsyncAppender引用appender --><Async name="Async"><AppenderRef ref="File"/></Async></Appenders><Loggers><Root level="INFO"><!-- 直接引用AsyncAppender --><AppenderRef ref="Async" /></Root></Loggers></Configuration>
AsyncLogger方式?
AsyncLogger才是log4j2 的重頭戲,也是官方推薦的異步方式。它可以使得調用Logger.log返回的 更快。你可以有兩種選擇:全局異步和混合異步。
全局異步 就是,所有的日志都異步的記錄,在配置文件上不用做任何改動,只需要添加一個 log4j2.component.properties 配置;
Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
混合異步 就是,你可以在應用中同時使用同步日志和異步日志,這使得日志的配置方式更加 靈活。?
<!--logger定義--><Loggers><!--自定義異步logger對象includeLocation = "false" 關閉日志記錄行好信息additivity = "false" 不再繼承rootlogger對象--><AsyncLogger name = "com.itcats" level = "trace" includeLocation = "false" additivity = "false"><AppenderRef ref="Console"/></AsyncLogger><Root level = "trace"><AppenderRef ref ="Console"/></Root></Loggers>
將以上配置配置到我們之前的log4j2.xml配置文件中,將之前的logger定義替換。此時我們com.itcats日志是異步的,root日志是同步的。
使用異步日志需要注意的問題:
1. 如果使用異步日志,AsyncAppender、AsyncLogger和全局日志,不要同時出現。性能會和 AsyncAppender一致,降至最低。
2. 設置includeLocation=false ,打印位置信息會急劇降低異步日志的性能,比同步日志還要慢
到這里我們的java日志框架基本就介紹完了