Log4j 學習紀錄
這邊是 log4j 1.x 版
log4j-1.2.17.jar
下面的 Appender / Layout 等若未設定則採用預設的 Root Logger 中設定
Log4j 是一套開放源碼的工具,方便開發人員在程式中加入 log 機制,並輸出到不同媒介上。
Log4j 由properites
或 XML
設定檔進行設定。
輸出媒介包含 console, 檔案,串流,TCP 協定的伺服器,Unix Syslog daemon 等。
Log4j 具有 5 種 log 層級( DEBUG
, INFO
, WARN
, ERROR
, FATAL
),可用於不同的系統狀態下所產生的訊息。
組成 Log4j 的三大元件
Log4j 的階層架構
-
一個程式中可以擁有多個 Logger,Logger 間以
名稱
區分,並以名稱分階層。
例如: 當一個 Logger 的名稱為 package.a ,另一個名為 package.a.b 的 Logger 就隸屬於 package.a logger,
如果 package.a.b 未定義自己的 log 等級,則以 package.a 的 log 等級為預設值。 -
階層的最高為
Root logger
。
Root logger 為預設物件,不具有名稱屬性,
可以隨時在程式中以 Logger.getRootLogger() 取得,
其它 logger 則以 Logger.getLogger(String name) 取得。
Logger
- Logger 可以被指派等級 。
- 能夠指派給 Logger 的等級有 :
DEBUG
,INFO
,WARN
,ERROR
,FATAL
5 種,定義在 org.apache.log4j.Level 類別中。 - 這 5 種等級的高低順序為 FATAL > ERROR > WARN > INFO > DEBUG。
- 能夠指派給 Logger 的等級有 :
- Logger 的等級決定它產生 log message 的種類 : Logger 只寫 出高於或等於本身等級 的 log message。
例如: 某個 WARN 等級的 Logger ,它可寫出等級為 WARN、ERROR、FATAL 等級的 log message,
並忽略 DEBUG, INFO 等級的 log message 。 - 若是 Logger 的等級未被設定,則自動套用 parent(上一層) 的等級。
如果程式中所有的 Logger 都未設定等級,則套用 root logger。 - Logger 以名稱辨別,所以在程式中任何地方,呼叫 Logger.getLogger(),並傳入同一個 Logger 名稱,則會得到同一個 Logger 的 reference。
- Logger 之間以名稱區分出階層。即使父階層在程式中出現的時機比子階層晚,例如 package.a logger 比 package.a.b 被取得的時間來得晚,package.a 仍然是 package.a.b 的父階層。仍然會影響到子階層 logger 未被定義的屬性, 如: log 等級、appender、layout 等等。
- 通常 Logger.getLogger(loggerName) 當中的 loggerName 會以 Logger 所在 Class 的 class.getName() 來命名以避免重名。
Appender
- 透過 Appender,Logger 能夠將 log message 輸出到指定的媒體上。
- 一個 Logger 能夠擁有多個 Appender,所以 Logger 能夠同時輸出到多個媒體上。
- Appender 的設定亦會反映在 Logger 的階層中 。
- 當 Logger 輸出一筆 log 時,父階層的 Appender 和自己的 Appender 輸出設定都會反應到這筆 log 中。
- 例如: package.insect Logger 有一個 Appender 將 message 輸出到 console,而 package.insect.totem 有一個 Appender 將 message 輸出到檔案。當 package.insect.totem 輸出 log 時,console 和檔案都會出現這筆 log。
- 例外情況是: 當 logger 將
additivity 屬性設為 false
,則此 logger 與它的子 logger 都不會承襲父層的設定。
Logger.setAdditivity(false)
Layout
- Layout 的設定亦會反映在 Logger 的階層中
- 開發人員藉由 Layout 的設定,改變 message 所輸出的格式。
- 例如: 為 Logger 加入一個 conversion pattern 為
%r %t %-5p %c - %m%n
的 PatternLayout,則輸出的 message 就可能會像下列這樣:
- 例如: 為 Logger 加入一個 conversion pattern 為
176 [main] INFO org.foo.Bar - Located nearest gas station.
-
PatternLayout 的 格式字元列表如下:
說明 %c 輸出日誌訊息所屬的 Class 的全名 %d 輸出日誌時間點的 日期或時間 ,指定格式的方式:%d{dd-MM-yy HH:mm:ss,SSS} %l 輸出日誌事件的發生位置,即輸出日誌訊息的語句處於它所在的類別的 第幾行 %m 輸出代碼中指定的訊息,如log(message)中的message %n 輸出一個 換行符號 %p 輸出優先階層,即 DEBUG,INFO,WARN,ERROR,FATAL
如果是呼叫 debug() 輸出的,則為 DEBUG,依此類推
-5p 代表將此字串以空白補至 5 個字元%r 輸出啟動到輸出該日誌訊息所耗費的毫秒數 %t 輸出產生該日誌事件的 thread 名 %f 輸出日誌訊息所屬的 Class 的類別名
設定
-
Log4j 有 3 種設定方式
- 經由 Java 程式配置
- 經由
property
檔設定 - 經由
xml
設定檔
-
步驟:
- 先定義 Root Logger 等級: 所有 logger 的預設等級
- 再定義 Root Logger Appender: 若定義 Root Logger,則 Root Logger 的 Appender 一定要指定
- 定義 Root Logger Layout: 定義 Layout 的類別後,選擇性定義 Layout 的 conversion pattern
- 依需要定義個別的 Logger、Appender、Layout
Java 程式配置 log4j
使用 BasicConfigurator 進行設定
Root Logger 預設被設定為 DEBUG 等級
log message 以 %r %t %p %c %x - %m%n
的格式輸出到 console
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
public class Log4jByBasicConfigurator {
private static Logger logger = Logger.getLogger(Log4jByBasicConfigurator.class);
//private static Logger logger =
// Logger.getLogger(Log4jByBasicConfigurator.class.getName());
public static void main(String[] args){
BasicConfigurator.configure();
logger.info("This is an info message.");
logger.debug("This is a debug message.");
}
}
Property 配置 log4j
以 *.properties 設定移至外部檔案,增加靈活與 DevOp 偕同
- Log4j 會從 class path 中尋找
log4j.properties
,並讀取相關設定。 - 設定範例:
- package insect.totem.school.School;
- package insect.totem.school.classroom.ClassRoom;
- Root Logger 資料輸出到 console
- School 的資料只輸出到 file
- ClassRoom 的資料只輸出到 email
- 變色區域是自定義的名稱
log4j.properties
! =========================
! 1. Root Logger 設定 (console)
! =========================
!定義 Root Logger 的等級為 INFO,且為其指定一個 appender 名為 CONSOLE
log4j.rootLogger=INFO, CONSOLE
! CONSOLE Appender
log4j.appender. CONSOLE =org.apache.log4j.ConsoleAppender
!指定 Console 的 Layout
log4j.appender. CONSOLE .layout=org.apache.log4j.PatternLayout
!指定 Console Layout 的輸出格式
log4j.appender. CONSOLE .layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c - %m%n
! =========================
! 設定特定名稱的 Logger
! 2. Logger for insect.totem.school.School (file)
! =========================
log4j.logger.insect.totem.school.School=DEBUG, SCHOOL_FILE
log4j.additivity.insect.totem.school.School=false
log4j.appender.SCHOOL_FILE=org.apache.log4j.RollingFileAppender
log4j.appender.SCHOOL_FILE.File=logs/school.log
log4j.appender.SCHOOL_FILE.MaxFileSize=1MB
log4j.appender.SCHOOL_FILE.MaxBackupIndex=3
log4j.appender.SCHOOL_FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.SCHOOL_FILE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c - %m%n
! =========================
! 設定特定名稱的 Logger
! 3. Logger for insect.totem.school.classroom.ClassRoom (email)
! =========================
log4j.logger.insect.totem.school.classroom.ClassRoom=ERROR, MAIL
log4j.additivity.insect.totem.school.classroom.ClassRoom=false
log4j.appender. MAIL =org.apache.log4j.net.SMTPAppender
log4j.appender. MAIL .Threshold=ERROR
log4j.appender. MAIL .SMTPHost=smtp.example.com
log4j.appender. MAIL .SMTPUsername=your_email@example.com
log4j.appender. MAIL .SMTPPassword=your_password
log4j.appender. MAIL .From=your_email@example.com
log4j.appender. MAIL .To=admin@example.com
log4j.appender. MAIL .Subject=Log4j Error in ClassRoom
log4j.appender. MAIL .layout=org.apache.log4j.PatternLayout
log4j.appender. MAIL .layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c - %m%n
# =========================
# 1. Root Logger 設定 (console)
# =========================
#定義 Root Logger 的等級為 INFO,且為其指定一個 appender 名為 CONSOLE
log4j.rootLogger=INFO, CONSOLE
# Console Appender
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
#指定 Console 的 Layout
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
#指定 Console Layout 的輸出格式
log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c - %m%n
# =========================
# 2. Logger for insect.totem.school.School (file)
# #設定特定名稱的 Logger
# =========================
log4j.logger.insect.totem.school.School=DEBUG, SCHOOL_FILE
log4j.additivity.insect.totem.school.School=false
log4j.appender.SCHOOL_FILE=org.apache.log4j.RollingFileAppender
log4j.appender.SCHOOL_FILE.File=logs/school.log
log4j.appender.SCHOOL_FILE.MaxFileSize=1MB
log4j.appender.SCHOOL_FILE.MaxBackupIndex=3
log4j.appender.SCHOOL_FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.SCHOOL_FILE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c - %m%n
# =========================
# 3. Logger for insect.totem.school.classroom.ClassRoom (email)
# #設定特定名稱的 Logger
# =========================
log4j.logger.insect.totem.school.classroom.ClassRoom=ERROR, MAIL
log4j.additivity.insect.totem.school.classroom.ClassRoom=false
log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender
log4j.appender.MAIL.Threshold=ERROR
log4j.appender.MAIL.SMTPHost=smtp.example.com
log4j.appender.MAIL.SMTPUsername=your_email@example.com
log4j.appender.MAIL.SMTPPassword=your_password
log4j.appender.MAIL.From=your_email@example.com
log4j.appender.MAIL.To=admin@example.com
log4j.appender.MAIL.Subject=Log4j Error in ClassRoom
log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout
log4j.appender.MAIL.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c - %m%n
區塊 | 說明 |
---|---|
rootLogger | 全域預設 Logger,這裡設定為 INFO 級別並輸出到 Console。 |
logger.insect.totem.school.School | 設定 School 的 logger 為 DEBUG 級別,輸出到 school.log 檔案。使用 additivity=false 避免輸出重複到 root logger(console)。 |
logger.insect.totem.school.classroom.ClassRoom | 設定 ClassRoom logger 為 ERROR 級別,並將錯誤透過 email 通知,additivity=false 避免輸出到其他 appender。 |
SMTPAppender | 為 email 通知的組件,記得替換 SMTP 主機與帳號密碼。 |
Java 中使用方式
package insect.totem.school;
import org.apache.log4j.Logger;
public class School {
private static final Logger logger = Logger.getLogger(School.class);
public void performTask() {
logger.debug("School debug message - something detailed.");
logger.info("School info message - general process update.");
logger.warn("School warning message - something might be wrong.");
}
}
package insect.totem.school.classroom;
import org.apache.log4j.Logger;
public class ClassRoom {
private static final Logger logger = Logger.getLogger(ClassRoom.class);
// 或 private static final Logger logger = Logger.getLogger(ClassRoom.class.getName());
public void causeError() {
try {
// 模擬錯誤
int result = 10 / 0;
} catch (Exception e) {
logger.error("ClassRoom error occurred!", e);
}
}
}
Xml 配置 log4j
- 需將 log4j.xml 放在你的 classpath 根目錄
- 相同情境改以 xml 設定
log4j.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<!-- ========== Root Logger:輸出到 console ========== -->
<root>
<priority value="info" />
<appender-ref ref="CONSOLE" />
</root>
<!-- ========== Logger for insect.totem.school.School:輸出到 file ========== -->
<logger name="insect.totem.school.School" additivity="false">
<level value="debug" />
<appender-ref ref="SCHOOL_FILE" />
</logger>
<!-- ========== Logger for insect.totem.school.classroom.ClassRoom:輸出到 email ========== -->
<logger name="insect.totem.school.classroom.ClassRoom" additivity="false">
<level value="error" />
<appender-ref ref="MAIL" />
</logger>
<!-- ========== Appender:CONSOLE ========== -->
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c - %m%n"/>
</layout>
</appender>
<!-- ========== Appender:SCHOOL_FILE ========== -->
<appender name="SCHOOL_FILE" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="logs/school.log"/>
<param name="MaxFileSize" value="1MB"/>
<param name="MaxBackupIndex" value="3"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c - %m%n"/>
</layout>
</appender>
<!-- ========== Appender:MAIL ========== -->
<appender name="MAIL" class="org.apache.log4j.net.SMTPAppender">
<param name="Threshold" value="ERROR"/>
<param name="SMTPHost" value="smtp.example.com"/>
<param name="SMTPUsername" value="your_email@example.com"/>
<param name="SMTPPassword" value="your_password"/>
<param name="From" value="your_email@example.com"/>
<param name="To" value="admin@example.com"/>
<param name="Subject" value="Log4j Error in ClassRoom"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c - %m%n"/>
</layout>
</appender>
</log4j:configuration>