簡介
- 本篇是關于
Log4j日志框架的介紹, - 閱讀本文請至少了解
JUL日志框架,因為大部分的知識點是類似的,
Log4j日志框架
Log4j全稱是Log for Java,它是Apache的一個開源專案,通過使用Log4j,我們可以控制日志資訊輸出的位置是控制臺、檔案還是GUI組件,輸出位置甚至可以是套介面服務器、NT的事件記錄器、UNIX Syslog守護行程等;- 使用
Log4j也可以控制每一條日志的輸出格式;通過定義每一條日志資訊的級別,我們能夠更加細致地控制日志的生成程序,
入門案例
- 所使用的專案使用
Maven構建,需要引入Log4j依賴:
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
Log4j默認情況下是需要提供組態檔的,如果resource目錄下不存在log4j.properties組態檔,則控制臺中會輸出相應的警告資訊,- 考慮以下代碼:
@Test
public void test() {
// 1.在沒有log4j.properties的情況下,獲取日志記錄器物件Logger
Logger logger = Logger.getLogger(Log4jTest.class);
// 2.嘗試輸出日志記錄
logger.info("Hey, log4j.");
}
- 此時控制臺輸出為:

- 接觸過
JUL的都知道,當普通的Logger沒有進行額外的配置時,其默認會繼承并使用RootLogger的配置, - 同樣地,
Log4j中也存在RootLogger,但由于默認情況下RootLogger不具有任何的Appender(即Handler), - 如果代碼僅為了測驗某項功能,并不想撰寫復雜的
log4j.properties,可以使用Log4j提供的默認配置,在獲取Logger前使用以下代碼加載默認配置:BasicConfigurator.configure(); - 查看
configure()方法的原始碼:
/**
Add a {@link ConsoleAppender} that uses {@link PatternLayout}
using the {@link PatternLayout#TTCC_CONVERSION_PATTERN} and
prints to <code>System.out</code> to the root category. */
static
public
void configure() {
Logger root = Logger.getRootLogger();
root.addAppender(new ConsoleAppender(
new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN)));
}
- 古早時期的原始碼格式有點不太現代,但意義明確:為
RootLogger物件添加一個Appender,其中Appender的型別為控制器輸出的ConsoleAppender,輸出的格式使用PatternLayout.TTCC_CONVERSION_PATTERN, - 以下為
PatternLayout.TTCC_CONVERSION_PATTERN原始碼:
/** A conversion pattern equivalent to the TTCCCLayout.
Current value is <b>%r [%t] %p %c %x - %m%n</b>. */
public final static String TTCC_CONVERSION_PATTERN
= "%r [%t] %p %c %x - %m%n";
- 關于
PatternLayout的相關格式化規則,后續會列舉出來, - 于是,使用以下代碼加載默認配置并輸出日志:
@Test
public void testQuick() {
// 1.初始化配置資訊,使用默認的配置,如果不加載默認配置同時不具有log4j.properties組態檔,程式將發出警告
BasicConfigurator.configure();
// 2.獲取日志記錄器物件Logger
Logger logger = Logger.getLogger(Log4jTest.class);
// 3.日志記錄輸出
logger.info("Hey, log4j.");
}
- 此時控制臺輸出為:

日志級別
Log4j中的日志級別與JUL的不同,一共提供了6中日志級別:FATAL:嚴重錯誤,一般會造成系統崩潰并終止運行;ERROR:錯誤資訊,不會影響系統運行;WARN:警告資訊,可能會發生問題;INFO:運行資訊,資料連接、網路連接、I/O操作等等;DEBUG:除錯資訊,一般在開發中使用,記錄程式變數引數傳遞資訊等等,默認級別;TRACE:追蹤資訊,記錄程式所有的流程資訊,
- 參考以下示例代碼:
@Test
public void testQuick() {
// 1.初始化配置資訊,使用默認的配置,如果不加載默認配置同時不具有log4j.properties組態檔,程式將發出警告
BasicConfigurator.configure();
// 2.獲取日志記錄器物件Logger
Logger logger = Logger.getLogger(Log4jTest.class);
// 3.日志級別測驗
logger.fatal("[FATAL] 嚴重錯誤,一般會造成系統崩潰并終止運行,");
logger.error("[ERROR] 錯誤資訊,不會影響系統運行,");
logger.warn("[WARN] 警告資訊,可能會發生問題,");
logger.info("[INFO] 運行資訊,資料連接、網路連接、I/O操作等等,");
logger.debug("[DEBUG] 除錯資訊,一般在開發中使用,記錄程式變數引數傳遞資訊等等,默認級別,");
logger.trace("[TRACE] 追蹤資訊,記錄程式所有的流程資訊,");
}
- 運行輸出,得到:

- 輸出的日志仍然由默認的日志級別所決定,其中默認級別為
DEBUG, - 為了測驗默認日志級別,可以使用以下代碼測驗
RootLogger:- 使用
getRootLogger()獲取RootLogger物件; - 使用
RootLogger中的相關方法獲取日志物件的日志等級及其關聯的Appender詳情,
- 使用
@Test
public void testDetails() {
// 1.初始化配置資訊,使用默認的配置,如果不加載默認配置,將無法正常運行
BasicConfigurator.configure();
// 2.獲取日志記錄器物件RootLogger
final Logger rootLogger = Logger.getRootLogger();
// 3.輸出配置詳情
System.out.println("Logger level: " + rootLogger.getLevel());
final Enumeration allAppenders = rootLogger.getAllAppenders();
while (allAppenders != null && allAppenders.hasMoreElements()) {
final Appender appender = (Appender) allAppenders.nextElement();
System.out.println("Appender is: " +appender.getClass().getSimpleName());
}
}
- 運行輸出:

- 注意,對于
Log4j中的Appender來說,它們不具有日志等級,只有Logger物件具有日志等級,
Log4j相關組件
Log4J主要由Loggers(日志記錄器)、Appenders(輸出端)和Layout(日志格式化器)組成:Loggers:控制日志的輸出級別與日志是否輸出;Appenders:指定日志的輸出方式(輸出到控制臺、檔案等);Layout:控制日志資訊的輸出格式,
a. Logger
- 日志記錄器,負責收集處理日志記錄,
Logger的實體命名通常是類的全限定類名, Logger的名字大小寫敏感,其命名有繼承機制,- 例如:
name為org.apache.commons的logger會繼承name為org.apache的logger,
- 例如:
- 自
log4j 1.2版以來,Logger類已經取代了Category類,對于熟悉早期版本的log4j的人來說,Logger類可以被視為Category類的別名,
b. Appenders
Appender用來指定日志輸出到哪個地方,可以同時指定日志的輸出目的地,Log4j常用的輸出目的地有以下幾種:
| 輸出端型別 | 作用 |
|---|---|
ConsoleAppender |
將日志輸出到控制臺 |
FileAppender |
將日志輸出到檔案中 |
DailyRollingFileAppender |
將日志輸出到一個日志檔案,周期為天,即每天輸出 |
RollingFileAppender |
將日志資訊輸出到一個日志檔案,并且指定檔案的大小,當超過指定大小,會自動將檔案重命名,同時產生一個新的檔案 |
JDBCAppender |
將日志資訊保存到資料庫中 |
c. Layouts
- 布局器
Layouts用于控制日志輸出內容的格式,我們可以使用各種自定義格式輸出日志, Log4j常用的Layouts有以下幾種:
| 格式化器型別 | 作用 |
|---|---|
HTMLLayout |
格式化日志輸出為HTML表格形式 |
SimpleLayout |
簡單的日志輸出格式,列印的日志格式為info-message |
PatternLayout |
最強大的格式化方式,可以根據自定義格式輸出日志,如果沒有指定轉換格式,則使用默認的轉換格式 |
PatternLayout中的格式化規則:
* log4j采用類似C語言的printf函式的列印格式格式化日志資訊,具體的占位符及其含義如下:
%m 輸出代碼中指定的日志資訊
%p 輸出優先級,及DEBUG、INFO等
%n 換行符(Windows平臺的換行符為"\n",Unix平臺為"\n")
%r 輸出自應用啟動到輸出該 log 資訊耗費的毫秒數
%c 輸出列印陳述句所屬的類的全名
%t 輸出產生該日志的執行緒全名
%d 輸出服務器當前時間,默認為ISO8601,也可以指定格式,如:%d{yyyy年MM月dd日 HH:mm:ss}
%l 輸出日志時間發生的位置,包括類名、執行緒、及在代碼中的行數,如:Test.main(Test.java:10)
%F 輸出日志訊息產生時所在的檔案名稱
%L 輸出代碼中的行號
%% 輸出一個"%"字符
* 可以在%與字符之間加上修飾符來控制最小寬度、最大寬度和文本的對其方式,如:
%5c 輸出category名稱,最小寬度是5,category<5,默認的情況下右對齊
%-5c 輸出category名稱,最小寬度是5,category<5,"-"號指定左對齊,會有空格
%.5c 輸出category名稱,最大寬度是5,category>5,就會將左邊多出的字符截掉,<5不會有空格
%20.30c category名稱<20補空格,并且右對齊,>30字符,就從左邊交遠銷出的字符截掉
自定義配置
-
使用
Log4j不需要顯式地加載組態檔,對于Maven專案來說,程式會自動掃描resources目錄下的log4j.properties組態檔, -
自定義配置如下:
- 日志輸出等級為
INFO,此時RootLogger擁有三個Appender:ConsoleAppender:配置中的命名為Console;DailyRollingFileAppender:配置中的命名為UserDefinedName;JDBCAppender:配置中的命名為logDB,
RootLogger的默認輸出級別配置在log4j.rootLogger的首位,隨后緊跟的是關聯的Appender的名稱,表示其默認支持輸出的方式有哪些,
- 日志輸出等級為
# 指定日志的輸出級別與輸出端
log4j.rootLogger=INFO, Console, UserDefinedName, logDB
# 控制臺輸出配置
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
# 檔案輸出配置
log4j.appender.UserDefinedName=org.apache.log4j.DailyRollingFileAppender
# 指定日志的輸出路徑
log4j.appender.UserDefinedName.File=log4j.log
# 是否以追加日志的形式添加
log4j.appender.UserDefinedName.Append=true
# 使用自定義日志格式化器
log4j.appender.UserDefinedName.layout=org.apache.log4j.PatternLayout
# 指定日志的輸出格式
log4j.appender.UserDefinedName.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%t:%r] - [%p] %m%n
# 指定日志的檔案編碼
log4j.appender.UserDefinedName.encoding=UTF-8
# MySQL輸出配置
log4j.appender.logDB=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.logDB.layout=org.apache.log4j.PatternLayout
log4j.appender.logDB.Driver=com.mysql.cj.jdbc.Driver
log4j.appender.logDB.URL=jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8&useAffectedRows=true
log4j.appender.logDB.User=root
log4j.appender.logDB.Password=root
log4j.appender.logDB.Sql=INSERT INTO log(project_name, create_date, level, category, file_name, thread_name, line, all_category, message) \
values('log4j', '%d{yyyy-MM-dd HH:mm:ss}', '%p', '%c', '%F', '%t', '%L', '%l', '%m')
- 配置中包含了
sql輸出日志的方式,log表的創建代碼為:
CREATE TABLE `log` (
`log_id` INT ( 11 ) NOT NULL AUTO_INCREMENT,
`project_name` VARCHAR ( 255 ) DEFAULT NULL COMMENT '專案名稱',
`create_date` VARCHAR ( 255 ) DEFAULT NULL COMMENT '創建時間',
`level` VARCHAR ( 255 ) DEFAULT NULL COMMENT '優先級',
`category` VARCHAR ( 255 ) DEFAULT NULL COMMENT '所在類的全名',
`file_name` VARCHAR ( 255 ) DEFAULT NULL COMMENT '輸出日志訊息產生時所在的檔案名稱 ',
`thread_name` VARCHAR ( 255 ) DEFAULT NULL COMMENT '日志事件的執行緒名',
`line` VARCHAR ( 255 ) DEFAULT NULL COMMENT '行號',
`all_category` VARCHAR ( 255 ) DEFAULT NULL COMMENT '日志事件的發生位置',
`message` VARCHAR ( 4000 ) DEFAULT NULL COMMENT '輸出代碼中指定的訊息',
PRIMARY KEY ( `log_id` )
);
- 讓特定名稱的
logger使用特定的配置:- 一個
log4j.properties中可以配置多個且可重復的Appender,但Appender的命名不可重復; - 通過
log4j.logger.{loggerName}的方式,讓指定名為loggerName的logger使用該配置; - 由于該
logger仍然是隸屬于rootLogger,因此輸出是累加的形式:- 例:如果
RootLogger使用了ConsoleAppender,同時Logger也使用了ConsoleAppender,此時控制臺將輸出兩次日志記錄,一次為Logger繼承自RootLogger的輸出,另一次則為Logger自身的輸出,
- 例:如果
- 但日志等級
level則取決于子日志Logger與RootLogger,以等級高的一方為準,- 例:此時
RootLogger和Logger同時使用了ConsoleAppender,但輸出等級分別為INFO和WARN,此時控制臺輸出的日志等級僅有高于等于WARN的記錄,即使此時RootLogger的等級為INFO,
- 例:此時
- 一個
- 有如下
log4j.properties組態檔:- 其中
RootLogger和名為cn.hanna的Logger使用同一個ConsoleAppender,但日志等級不一致,
- 其中
# 指定日志的輸出級別與輸出端
log4j.rootLogger=INFO, Console
# 控制臺輸出配置
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
# 讓名為“cn.hanna”的logger使用名為Another的Appender
# 此時仍會使用rootLogger中的控制臺輸出,而Level則以兩者間較高的為準
log4j.logger.cn.hanna=WARN, Console
- 測驗代碼如下:
@Test
public void testAnother() {
// 1.獲取日志記錄器物件Logger
Logger logger = Logger.getLogger("cn.hanna");
// 2.日志級別測驗
logger.fatal("[FATAL] 嚴重錯誤,一般會造成系統崩潰并終止運行,");
logger.error("[ERROR] 錯誤資訊,不會影響系統運行,");
logger.warn("[WARN] 警告資訊,可能會發生問題,");
logger.info("[INFO] 運行資訊,資料連接、網路連接、I/O操作等等,");
logger.debug("[DEBUG] 除錯資訊,一般在開發中使用,記錄程式變數引數傳遞資訊等等,默認級別,");
logger.trace("[TRACE] 追蹤資訊,記錄程式所有的流程資訊,");
}
- 運行輸出:

- 輸出印證了之前所陳述的觀點,不再贅述,
- 此時,如果一定需要使用
ConsoleAppender,但不希望控制臺輸出兩次記錄,有兩種方式:- 摒棄
RootLogger的輸出,即斷開指定Logger與RootLogger的繼承關系; - 摒棄
Logger的輸出,即指定名稱的Logger直接使用RootLogger關聯的Appender,不再額外指定,
- 摒棄
- 如果選擇斷開指定
Logger與RootLogger的繼承關系,需修改組態檔如下:
# 指定日志的輸出級別與輸出端
log4j.rootLogger=INFO, Console
# 控制臺輸出配置
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
# 名為“cn.hanna”的Logger不再繼承使用RootLogger中的Appender
log4j.additivity.cn.hanna=false
log4j.logger.cn.hanna=WARN, Console
- 如果選擇直接使用
RootLogger關聯的Appender,需修改組態檔如下:
# 指定日志的輸出級別與輸出端
log4j.rootLogger=INFO, Console
# 控制臺輸出配置
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
# 對于名稱“cn.hanna”的Logger來說,將直接使用RootLogger中關聯的Appender,但日志等級由自身決定
log4j.logger.cn.hanna=WARN
- 兩種方式的測驗類運行結果均為:

- 實際應用中,應該靈活選擇適合與代碼的方式,去撰寫組態檔,
完整的組態檔示例
- 同樣,在此給出一個完整的
log4j組態檔示例:
log4j.rootLogger=INFO, Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.appender.UserDefinedName=org.apache.log4j.DailyRollingFileAppender
log4j.appender.UserDefinedName.File=log4j.log
log4j.appender.UserDefinedName.Append=true
log4j.appender.UserDefinedName.layout=org.apache.log4j.PatternLayout
log4j.appender.UserDefinedName.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%t:%r] - [%p] %m%n
log4j.appender.UserDefinedName.encoding=UTF-8
log4j.appender.logDB=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.logDB.layout=org.apache.log4j.PatternLayout
log4j.appender.logDB.Driver=com.mysql.cj.jdbc.Driver
log4j.appender.logDB.URL=jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8&useAffectedRows=true
log4j.appender.logDB.User=root
log4j.appender.logDB.Password=root
log4j.appender.logDB.Sql=INSERT INTO log(project_name, create_date, level, category, file_name, thread_name, line, all_category, message) \
values('log4j', '%d{yyyy-MM-dd HH:mm:ss}', '%p', '%c', '%F', '%t', '%L', '%l', '%m')
log4j.appender.Another=org.apache.log4j.DailyRollingFileAppender
log4j.appender.Another.File=hanna.log
log4j.appender.Another.Append=true
log4j.appender.Another.layout=org.apache.log4j.PatternLayout
log4j.appender.Another.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%t:%r] - [%p] %m%n
log4j.appender.Another.encoding=UTF-8
log4j.logger.cn.xyz=WARN, Another
log4j.additivity.cn.xyz=false
- 說明:其中
log4j.appeder.APPENDER_NAME中的APPENDER_NAME為相應Appender的名稱,可以自行定義,
總結
Log4j日志框架近似于JUL日志框架,但功能性上要優于JUL,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/242705.html
標籤:其他
上一篇:Python練習題
