Java的Log架構(Log4j2 + Slf4j)
目錄
常見的日誌門面
JCL,slf4j(Simple Logging For java)
常見的日誌實現
JUL,log4j,logback,log4j2
日誌框架介紹
JUL
Java自帶的日誌框架,不需要引入,直接可以使用
Log4j
非常經典的日誌框架,但是已經停止更新和維護了
LogBack
logBack和log4j不是同一個公司開發的,LogBack是Spring自動整合的日誌框架了。目前比較流行
Log4j2
Log4j2是Log4j的進階版,相比於LogBack,在非同步的時候速度可以快近10倍,目前Spring專案中,都會把自動引入的LogBack註釋掉,改用Log4j2. 未來使用Log4j2+slf4j這套組合一定是未來的幾年的主流日誌框架。
SLF4J的使用
簡介
SLF4J(Simple Logging Facade For Java)是給Java日誌訪問提供的一套標準,具體的實現,主要交給log4j,logback,log4j2等日誌框架。SLF4J其實也實現了簡單的日誌實現,但是幾乎不會有人去使用,而日誌框架一般會選擇slf4j-api作為門面,配上具體的實現框架,中間使用連線橋(介面卡)來完成日誌框架的建立。 slf4j-api 和 slf4j-simple 引入。 api是日誌門戶,simple是日誌的簡單實現。
slf4j-api 和 slf4j-simple 使用
log的級別有trace,debug,info,warn,error和fatal六個級別,預設情況下,只會輸出info,warn和error,fatal四個級別的日誌。 佔位符的使用,可以使用{}作為佔位符,後邊跟具體的變數,只要能使用佔位符就一定要使用這種模式作為日誌模式,但是需要小心注入攻擊。 使用slf4j-api 和 slf4j-simple的方式輸出日誌,不需要匯入中間的介面卡,當多個log實現框架同時存在的時候,會預設先使用slf4j-simple框架。
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Slf4jTest {
private static final Logger LOGGER = LoggerFactory.getLogger(Slf4jTest.class);
@Test
public void test01() {
// 日誌輸出,預設會輸出info級別以上的日誌
LOGGER.error("error");
LOGGER.warn("warn");
LOGGER.info("info");
LOGGER.debug("debug");
LOGGER.trace("trace");
// 使用佔位符輸出日誌資訊
String name = "Peter";
Integer age = 10;
LOGGER.info("User:{}, Age:{}", name, age);
}
}
Log4j2的使用
簡介
Apache Log4j2 是 log4j 的升級版,參考了logback的優秀設計,優化並解決了很多問題: 異常處理,在logback中,Appender中的異常不會被應用感知到,但是在log4j2中提供了一些異常處理機制。 效能提升,log4j2相比於logback和log4j在效能上有了很大的提升。 自動過載配置,提供了自動重新整理引數配置,可以再生產上動態修改日誌的級別而不需要重啟應用。 無垃圾機制,log4j2在大部分情況下,使用自動垃圾清收機制,避免日誌頻繁的GC。 Log4j2 也可以做為日誌的門面,但是因為其實現功能強大,但是門面略弱,所以當前主流的日誌框架都是使用slf4j作為日誌的門面,使用Log4j2作為日誌的實現,通過聯結器繫結,進行工作。 使用log4j-api和log4j-core的日誌架構如下:
依賴資訊:
<!--匯入日誌門面-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.13.3</version>
</dependency>
<!--匯入日誌實現-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.13.3</version>
</dependency>
Demo
package logger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.Test;
public class Log4j_Api_Core {
private static final Logger LOGGER = LogManager.getLogger(Log4j_Api_Core.class);
@Test
public void test02(){
// 日誌輸出,預設會輸出info級別以上的日誌
LOGGER.fatal("fatal");
LOGGER.error("error");
LOGGER.warn("warn");
LOGGER.info("info");
LOGGER.debug("debug");
LOGGER.trace("trace");
// 使用佔位符輸出日誌資訊
String name = "Peter";
Integer age = 10;
LOGGER.info("User:{}, Age:{}", name, age);
}
}
非同步日誌(效率提升的原因)
同步日誌:
正常的日誌,線上程需要列印日誌的時候,會走一套流程,初始化,並生成日誌,判斷等級是否過濾等等,最後決定是否輸出非同步日誌:
非同步日誌
非同步日誌的使用方式是在主執行緒需要生成日誌之後,就將資訊傳遞給一個阻塞的訊息佇列ArrayBlockingQueue,這個佇列將啟動一個(或多個)新的執行緒,完成後續日誌的生成,所以效率高了很多
效能圖表:
通常使用全域性非同步日誌的效率最高,使用非同步日誌和同步日誌混合的效率其次,使用同步日誌的效率最低。通常情況下,都會直接使用非同步日誌提高效率。
使用Log4j2和slf4j的日誌架構
當前最主流的日誌使用方式事Log4j2作為實現,slf4j作為門戶。
包引入
這個組合需要引入4個包,分別為Log4j2的門戶和實現,slf4j的門戶,slf4j和Log4j2的聯結器。 之後就可以按照slf4j的所有實現模式和門戶模式進行操作了。
<!--匯入slf4j日誌門面-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<!--匯入log4j2日誌實現-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.13.3</version>
</dependency>
<!--匯入log4j2日誌門面-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.13.3</version>
</dependency>
<!--使用介面卡-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.9.1</version>
</dependency>
Domo實現
使用slf4j和log4j2的組合,Demo如下:
package logger;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Slf4j_Log4j2 {
private static final Logger LOGGER = LoggerFactory.getLogger(Slf4j_Log4j2.class);
@Test
public void test03() {
// 日誌輸出,預設會輸出info級別以上的日誌
LOGGER.error("error");
LOGGER.warn("warn");
LOGGER.info("info");
LOGGER.debug("debug");
LOGGER.trace("trace");
// 使用佔位符輸出日誌資訊
String name = "Peter";
Integer age = 10;
LOGGER.info("User:{}, Age:{}", name, age);
}
}
Log4j2的配置檔案
log4j2 預設會載入在resources下的xml配置檔案,名稱為log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--status = debug 日誌框架本身的輸出的日誌級別,不是我們定義的日誌,而是框架自身日誌輸出的級別-->
<!--monitorInterval 自動載入配置檔案的間隔時間,不低於5s,可以實現熱更新-->
<Configuration status="debug" monitorInterval="5">
<!-- 集中配置屬性進行管理 可以定義各種名稱和對應的值 -->
<properties>
<property name="LOG_HOME">E:/logs</property>
<property name="FILE_NAME">mylog</property>
<property name="log.sql.level">info</property>
</properties>
<!--日誌處理-->
<Appenders>
<!--控制檯輸出結果 appender-->
<!--target 為日誌的等級,如果為 SYSTEM_OUT 是普通日誌,為白色;如果是SYSTEM_ERR,則為報警顏色,紅色-->
<Console name="Console" target="SYSTEM_OUT">
<!--日誌輸出的格式-->
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %l - %msg%n"/>
</Console>
<!-- 日誌的檔案輸出 -->
<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>
<!--隨機讀寫流實現檔案日誌的輸出,效能得到了提高,功能和 name = file是一樣的-->
<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-->
<RollingRandomAccessFile name="RollingRandomAccessFile" fileName="${LOG_HOME}/${FILE_NAME}.log"
filePattern="${LOG_HOME}/$${date:yyyy-MM}/${FILE_NAME}-%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} - %m%n"/>
<Policies>
<!--在系統啟動時,觸發拆分規則,生產一個新的日誌檔案-->
<OnStartupTriggeringPolicy/>
<!--按照時間的節點進行拆分,規則根據filePattern定義-->
<TimeBasedTriggeringPolicy interval="1"/>
<!--按照10Mb大小為一個檔案的上限-->
<SizeBasedTriggeringPolicy size="10 MB"/>
</Policies>
<!--最多可以生成多少個日誌檔案,超出之後,最舊的會被覆蓋-->
<DefaultRolloverStrategy max="20"/>
</RollingRandomAccessFile>
</Appenders>
<!--Logger定義-->
<Loggers>
<!--日誌輸出的等級,超過該等級的進行輸出-->
<Root level="info">
<!--指定日誌的處理器-->
<AppenderRef ref="Console"/>
<AppenderRef ref="RollingRandomAccessFile"/>
<AppenderRef ref="file"/>
<AppenderRef ref="accessFile"/>
</Root>
</Loggers>
</Configuration>
Log4j2配置非同步日誌
非同步配置有兩種方式,全域性非同步和區域性非同步(非同步和同步混合的方式)。區域性非同步的方式,如果處理不好,可能效能比完全同步效率還低,因此,僅介紹全域性非同步的使用方式。
需要引入一個新的jar包,用於非同步日誌生成;
<!--非同步log4j2日誌的依賴包-->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.3.4</version>
</dependency>
之後在resources下,定義一個檔案 log4j2.component.properties 在這個檔案中啟動全域性非同步日誌的指令即可:
log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
Log4j2無垃圾機制
在log4j2的2.6版本之後,會啟動一個無垃圾機制,它會自動的清除日誌中的垃圾,減少了系統自動GC的頻率,大大提高了速度(無垃圾機制自動開啟,不需要手動操作)。
相關文章
- 帶你深入Java Log框架,徹底搞懂Log4J、Log4J2、LogBack,SLF4JJava框架
- Log4j2 + SLF4j打造日誌系統
- log4j2生效
- log4j2使用及log4j2.xml分析XML
- 微服務架構Day02-SpringBoot日誌slf4j微服務架構Spring Boot
- SpringBoot整合Log4j2日誌框架Spring Boot框架
- apache log4j2 漏洞復現linuxApacheLinux
- SpringBoot 整合 Log4j2 日誌框架Spring Boot框架
- 常見日誌輸出目標(Logback | Log4j2 | Java Util Logging)Java
- Log4j2 + Maven的配置檔案示例詳解Maven
- Log4j2—漏洞分析(CVE-2021-44228)
- 使用Log4j2輸出日誌演示
- SpringBoot 實現整合log4j2日誌Spring Boot
- log4j2分層輸出日誌
- java架構的程式碼結構Java架構
- Log4j 1.x 將直接升級到Log4j2
- log4j2同步日誌引發的效能問題
- 修復 KubeSphere 內建 Jenkins 的 Apache Log4j2 漏洞JenkinsApache
- 【緊急】Spring爆出比Log4j2還大的漏洞?Spring
- Apache Log4j2遠端命令執行漏洞Apache
- Spring Boot 應對 Log4j2 注入漏洞指南Spring Boot
- 【log4j2日誌框架】敏感字元過濾框架字元
- Log4j2 Jndi 漏洞原理解析、覆盤
- log4j2 ERROR StatusLogger Unrecognized conversion specifier解決ErrorZed
- 如何編寫Log4j2脫敏外掛
- java之JVM的架構模型JavaJVM架構模型
- 為什麼加上<log4j2.version>配置就可以更新log4j2的版本?
- SpringBoot—整合log4j2入門和log4j2.xml配置詳解Spring BootXML
- Log4j2 Zero Day 漏洞 Apache Flink 應對指南Apache
- Log4j2 消停了,Logback 開始塌房了?
- Apache Log4j2,RASP 防禦優勢及原理Apache
- 測試中出現ERROR StatusLogger No log4j2 configuration fileError
- 日誌-log4j2基於AsyncLogger的非同步日誌列印非同步
- 日誌-log4j2基於AsyncAppender的非同步日誌列印APP非同步
- 記一次log4j2引發的滲透測試
- Java架構-到底什麼才是業務架構?Java架構
- 基於bin-log&position搭建主從架構MySQL架構MySql
- 使用 Apache APISIX serverless 能力快速攔截 Apache Log4j2 的高危漏洞ApacheAPIServer