log4j2的使用
Apache Log4j 2是對Log4j的升級版,參考了logback的一些優秀的設計,并且修復了一些問題,因此帶
來了一些重大的提升,主要有:
異常處理,在 logback中,Appender中的異常不會被應用感知到,但是在log4j2中,提供了一些異常處理機制。
性能提升, log4j2相較于log4j 和logback都具有很明顯的性能提升,后面會有官方測試的數據。
自動重載配置,參考了 logback的設計,當然會提供自動刷新參數配置,最實用的就是我們在生產
上可以動態的修改日志的級別而不需要重啟應用。
無垃圾機制, log4j2在大部分情況下,都可以使用其設計的一套無垃圾機制,避免頻繁的日志收集導致的jvm gc。
官網: https://logging.apache.org/log4j/2.x/
Log4j2入門
目前市面上最主流的日志門面就是SLF4J,雖然Log4j2也是日志門面,因為它的日志實現功能非常強
大,性能優越。所以大家一般還是將Log4j2看作是日志的實現,Slf4j + Log4j2應該是未來的大勢所趨。
1. 添加依賴
<!--log4j2日志門面-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.1</version>
</dependency>
<!--log4j2 日志實現-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.1</version>
</dependency>
public class Log4j2Test {
// 定義日志記錄器對象
public static final Logger LOGGER = LogManager.getLogger(Log4j2Test.class);
// 快速入門
@Test
public void testQuick()throws Exception{
// 日志消息輸出
LOGGER.fatal("fatal");
LOGGER.error("error");
LOGGER.warn("warn");
LOGGER.info("inf");
LOGGER.debug("debug");
LOGGER.trace("trace");
}
}
2. 使用slf4j作為日志的門面,使用log4j2作為日志的實現
<!--使用slf4j 作為日志門面-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.26</version>
</dependency>
<!--使用 log4j2 的適配器進行綁定-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.9.1</version>
</dependency>
public class Slf4jTest {
public static final Logger LOGGER = LoggerFactory.getLogger(Slf4jTest.class);
// 快速入門
@Test
public void test01()throws Exception{
// 日志輸出
LOGGER.error("error");
LOGGER.warn("wring");
LOGGER.info("info");
LOGGER.debug("debug");
LOGGER.trace("trace");
}
}
Log4j2配置
log4j2默認加載classpath下的 log4j2.xml 文件中的配置。
<?xml version="1.0" encoding="UTF-8"?>
<!--
status="warn" 日志框架本身的輸出日志級別
monitorInterval="5" 自動加載配置文件的間隔時間,不低于 5 秒
-->
<Configuration status="debug" monitorInterval="5">
<!--
集中配置屬性進行管理
使用時通過:${name}
-->
<properties>
<property name="LOG_HOME">/logs</property>
</properties>
<!--日志處理-->
<Appenders>
<!--控制臺輸出 appender-->
<Console name="Console" target="SYSTEM_ERR">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] [%-5level] %c{36}:%L --- %m%n" />
</Console>
<!--日志文件輸出 appender-->
<File name="file" fileName="${LOG_HOME}/myfile.log">
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n" />
</File>
<!--<Async name="Async">-->
<!--<AppenderRef ref="file"/>-->
<!--</Async>-->
<!--使用隨機讀寫劉的日志文件輸出 appender,性能提高-->
<RandomAccessFile name="accessFile" fileName="${LOG_HOME}/myAcclog.log">
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n" />
</RandomAccessFile>
<!--按照一定規則拆分的日志文件的 appender-->
<RollingFile name="rollingFile" fileName="${LOG_HOME}/myrollog.log"
filePattern="/logs/$${date:yyyy-MM-dd}/myrollog-%d{yyyy-MM-dd-HH-mm}-%i.log">
<!--日志級別過濾器-->
<ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" />
<!--日志消息格式-->
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %msg%n" />
<Policies>
<!--在系統啟動時,出發拆分規則,生產一個新的日志文件-->
<OnStartupTriggeringPolicy />
<!--按照文件大小拆分,10MB -->
<SizeBasedTriggeringPolicy size="10 MB" />
<!--按照時間節點拆分,規則根據filePattern定義的-->
<TimeBasedTriggeringPolicy />
</Policies>
<!--在同一個目錄下,文件的個數限定為 30 個,超過進行覆蓋-->
<DefaultRolloverStrategy max="30" />
</RollingFile>
</Appenders>
<!--logger 定義-->
<Loggers>
<!--自定義異步 logger 對象
includeLocation="false" 關閉日志記錄的行號信息
additivity="false" 不在繼承 rootlogger 對象
-->
<AsyncLogger name="com.topcheer" level="trace" includeLocation="false" additivity="false">
<AppenderRef ref="Console"/>
</AsyncLogger>
<!--使用 rootLogger 配置 日志級別 level="trace"-->
<Root level="trace">
<!--指定日志使用的處理器-->
<AppenderRef ref="Console" />
<!--使用異步 appender-->
<AppenderRef ref="Async" />
</Root>
</Loggers>
</Configuration>
Log4j2異步日志
log4j2最大的特點就是異步日志,其性能的提升主要也是從異步日志中受益,我們來看看如何使用
log4j2的異步日志。
同步日志
異步日志
Log4j2 提供了兩種實現日志的方式,一個是通過AsyncAppender,一個是通過AsyncLogger,分別對應
前面我們說的Appender組件和Logger組件。
注意:配置異步日志需要添加依賴
<!--異步日志依賴-->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.3.4</version>
</dependency>
1. AsyncAppender方式
<!--日志文件輸出 appender-->
<File name="file" fileName="${LOG_HOME}/myfile.log">
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n" />
</File>
<!--<Async name="Async">-->
<!--<AppenderRef ref="file"/>-->
<!--</Async>-->
<!--使用 rootLogger 配置 日志級別 level="trace"-->
<Root level="trace">
<!--指定日志使用的處理器-->
<AppenderRef ref="Console" />
<!--使用異步 appender-->
<AppenderRef ref="Async" />
</Root>
2 . AsyncLogger方式
AsyncLogger才是log4j2 的重頭戲,也是官方推薦的異步方式。它可以使得調用Logger.log返回的
更快。你可以有兩種選擇:全局異步和混合異步。
全局異步就是,所有的日志都異步的記錄,在配置文件上不用做任何改動,只需要添加一個
log4j2.component.properties 配置;
Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
混合異步 就是,你可以在應用中同時使用同步日志和異步日志,這使得日志的配置方式更加
靈活。
<!--自定義異步 logger 對象
includeLocation="false" 關閉日志記錄的行號信息
additivity="false" 不在繼承 rootlogger 對象
-->
<AsyncLogger name="com.topcheer" level="trace" includeLocation="false" additivity="false">
<AppenderRef ref="Console"/>
</AsyncLogger>
如上配置: com.topcheer日志是異步的,root日志是同步的。
使用異步日志需要注意的問題:
1. 如果使用異步日志,AsyncAppender、AsyncLogger和全局日志,不要同時出現。性能會和
AsyncAppender一致,降至最低。
2. 設置includeLocation=false ,打印位置信息會急劇降低異步日志的性能,比同步日志還要
慢。
Log4j2 的性能
Log4j2最牛的地方在于異步輸出日志時的性能表現,Log4j2在多線程的環境下吞吐量與Log4j和
Logback的比較如下圖。下圖比較中Log4j2有三種模式:1)全局使用異步模式;2)部分Logger采用異
步模式;3)異步Appender。可以看出在前兩種模式下,Log4j2的性能較之Log4j和Logback有很大的
優勢。
無垃圾記錄
垃圾收集暫停是延遲峰值的常見原因,并且對于許多系統而言,花費大量精力來控制這些暫停。
許多日志庫(包括以前版本的Log4j)在穩態日志記錄期間分配臨時對象,如日志事件對象,字符串,
字符數組,字節數組等。這會對垃圾收集器造成壓力并增加GC暫停發生的頻率。
從版本2.6開始,默認情況下Log4j以“無垃圾”模式運行,其中重用對象和緩沖區,并且盡可能不分配臨
時對象。還有一個“低垃圾”模式,它不是完全無垃圾,但不使用ThreadLocal字段。
Log4j 2.6中的無垃圾日志記錄部分通過重用ThreadLocal字段中的對象來實現,部分通過在將文本轉換
為字節時重用緩沖區來實現。
使用Log4j 2.5:內存分配速率809 MB /秒,141個無效集合。
Log4j 2.6 沒有分配臨時對象:0(零)垃圾回收。
有兩個單獨的系統屬性可用于手動控制 Log4j用于避免創建臨時對象的機制:
log4j2.enableThreadlocals - 如果“true”(非Web應用程序的默認值)對象存儲在
ThreadLocal字段中并重新使用,否則將為每個日志事件創建新對象。
log4j2.enableDirectEncoders - 如果將“true”(默認)日志事件轉換為文本,則將此文本轉換
為字節而不創建臨時對象。注意: 由于共享緩沖區上的同步,在此模式下多線程應用程序的同步
日志記錄性能可能更差。如果您的應用程序是多線程的并且日志記錄性能很重要,請考慮使用異步
記錄器
總結
- 上一篇: java错误 找不到或无法加载主类
- 下一篇: java线程礼让yield