和Java標準庫提供的日志不同赤屋,Commons Logging是一個第三方日志庫罢缸,它是由Apache創(chuàng)建的日志模塊。
Commons Logging的特色是,它可以掛接不同的日志系統(tǒng)蹈垢,并通過配置文件指定掛接的日志系統(tǒng)。默認情況下袖裕,Commons Loggin自動搜索并使用Log4j(Log4j是另一個流行的日志系統(tǒng))曹抬,如果沒有找到Log4j,再使用JDK Logging急鳄。
使用Commons Logging只需要和兩個類打交道谤民,并且只有兩步:
- 第一步,通過
LogFactory
獲取Log
類的實例疾宏; - 第二步张足,使用
Log
實例的方法打日志。
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Main {
public static void main(String[] args) {
Log log = LogFactory.getLog(Main.class);
log.info("start...");
log.warn("end.");
}
}
運行上述代碼灾锯,肯定會得到編譯錯誤兢榨,類似error: package org.apache.commons.logging does not exist
(找不到org.apache.commons.logging
這個包)。因為Commons Logging是一個第三方提供的庫顺饮,所以吵聪,必須先把它下載下來。下載后兼雄,解壓吟逝,找到commons-logging-1.2.jar
這個文件,再把Java源碼Main.java
放到一個目錄下赦肋,例如work
目錄:
然后用javac
編譯Main.java
块攒,編譯的時候要指定classpath
励稳,不然編譯器找不到我們引用的org.apache.commons.logging
包。編譯命令如下:
javac -cp commons-logging-1.2.jar Main.java
如果編譯成功囱井,那么當前目錄下就會多出一個Main.class
文件:
現(xiàn)在可以執(zhí)行這個Main.class
驹尼,使用java命令,也必須指定classpath
庞呕,命令如下:
java -cp .;commons-logging-1.2.jar Main
注意到傳入的classpath有兩部分:一個是.
新翎,一個是commons-logging-1.2.jar
,用;
分割住练。.
表示當前目錄地啰,如果沒有這個.
,JVM不會在當前目錄搜索Main.class
讲逛,就會報錯亏吝。
如果在Linux或macOS下運行,注意classpath的分隔符不是;
盏混,而是:
:
java -cp .:commons-logging-1.2.jar Main
運行結(jié)果如下:
//Mar 02, 2019 7:15:31 PM Main main
//INFO: start...
//Mar 02, 2019 7:15:31 PM Main main
//WARNING: end.
Commons Logging定義了6個日志級別:
- FATAL
- ERROR
- WARNING
- INFO
- DEBUG
- TRACE
默認級別是INFO蔚鸥。使用Commons Logging時,如果在靜態(tài)方法中引用Log
许赃,通常直接定義一個靜態(tài)類型變量:
// 在靜態(tài)方法中引用Log:
public class Main {
static final Log log = LogFactory.getLog(Main.class);
static void foo() {
log.info("foo");
}
}
在實例方法中引用Log株茶,通常定義一個實例變量:
// 在實例方法中引用Log:
public class Person {
protected final Log log = LogFactory.getLog(getClass());
void foo() {
log.info("foo");
}
}
注意到實例變量log
的獲取方式是LogFactory.getLog(getClass())
,雖然也可以用LogFactory.getLog(Person.class)
图焰,但是前一種方式有個非常大的好處,就是子類可以直接使用該log
實例蹦掐。例如:
// 在子類中使用父類實例化的log:
public class Student extends Person {
void bar() {
log.info("bar");
}
}
由于Java類的動態(tài)特性技羔,子類獲取的log
字段實際上相當于LogFactory.getLog(Student.class)
,但卻是從父類繼承而來卧抗,并且無需改動代碼藤滥。
此外,Commons Logging的日志方法社裆,例如info()
拙绊,除了標準的info(String)
外,還提供了一個非常有用的重載方法:info(String, Throwable)
泳秀,這使得記錄異常更加簡單:
try {
...
} catch (Exception e) {
log.error("got exception!", e);
}
小結(jié)
- Commons Logging是使用最廣泛的日志模塊标沪;
- Commons Logging的API非常簡單;
- Commons Logging可以自動檢測并使用其他日志模塊嗜傅。
使用Log4j
前面介紹了Commons Logging金句,可以作為“日志接口”來使用。而真正的“日志實現(xiàn)”可以使用Log4j吕嘀。Log4j是一種非常流行的日志框架违寞,最新版本是2.x贞瞒。
Log4j是一個組件化設(shè)計的日志系統(tǒng),它的架構(gòu)大致如下:
當我們使用Log4j輸出一條日志時趁曼,Log4j自動通過不同的Appender把同一條日志輸出到不同的目的地军浆。例如:
- console:輸出到屏幕;
- file:輸出到文件挡闰;
- socket:通過網(wǎng)絡輸出到遠程計算機乒融;
- jdbc:輸出到數(shù)據(jù)庫
在輸出日志的過程中,通過Filter來過濾哪些log需要被輸出尿这,哪些log不需要被輸出簇抵。例如,僅輸出ERROR
級別的日志射众。
上述結(jié)構(gòu)雖然復雜碟摆,但我們在實際使用的時候,并不需要關(guān)心Log4j的API叨橱,而是通過配置文件來配置它典蜕。
以XML配置為例,使用Log4j的時候罗洗,我們把一個log4j2.xml的文件放到classpath下就可以讓Log4j讀取配置文件并按照我們的配置來輸出日志愉舔。下面是一個配置文件的例子:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Properties>
<!-- 定義日志格式 -->
<Property name="log.pattern">%d{MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36}%n%msg%n%n</Property>
<!-- 定義文件名變量 -->
<Property name="file.err.filename">log/err.log</Property>
<Property name="file.err.pattern">log/err.%i.log.gz</Property>
</Properties>
<!-- 定義Appender,即目的地 -->
<Appenders>
<!-- 定義輸出到屏幕 -->
<Console name="console" target="SYSTEM_OUT">
<!-- 日志格式引用上面定義的log.pattern -->
<PatternLayout pattern="${log.pattern}" />
</Console>
<!-- 定義輸出到文件,文件名引用上面定義的file.err.filename -->
<RollingFile name="err" bufferedIO="true" fileName="${file.err.filename}" filePattern="${file.err.pattern}">
<PatternLayout pattern="${log.pattern}" />
<Policies>
<!-- 根據(jù)文件大小自動切割日志 -->
<SizeBasedTriggeringPolicy size="1 MB" />
</Policies>
<!-- 保留最近10份 -->
<DefaultRolloverStrategy max="10" />
</RollingFile>
</Appenders>
<Loggers>
<Root level="info">
<!-- 對info級別的日志伙菜,輸出到console -->
<AppenderRef ref="console" level="info" />
<!-- 對error級別的日志轩缤,輸出到err,即上面定義的RollingFile -->
<AppenderRef ref="err" level="error" />
</Root>
</Loggers>
</Configuration>
雖然配置Log4j比較繁瑣贩绕,但一旦配置完成火的,使用起來就非常方便。對上面的配置文件淑倾,凡是INFO
級別的日志馏鹤,會自動輸出到屏幕,而ERROR
級別的日志娇哆,不但會輸出到屏幕湃累,還會同時輸出到文件。并且碍讨,一旦日志文件達到指定大兄瘟Α(1MB),Log4j就會自動切割新的日志文件勃黍,并最多保留10份琴许。
有了配置文件還不夠,因為Log4j也是一個第三方庫溉躲,我們需要從這里下載Log4j榜田,解壓后益兄,把以下3個jar包放到classpath
中:
- log4j-api-2.x.jar
- log4j-core-2.x.jar
- log4j-jcl-2.x.jar
因為Commons Logging會自動發(fā)現(xiàn)并使用Log4j,所以箭券,把上一節(jié)下載的commons-logging-1.2.jar
也放到classpath
中净捅。
要打印日志,只需要按Commons Logging的寫法寫辩块,不需要改動任何代碼蛔六,就可以得到Log4j的日志輸出,類似:
03-03 12:09:45.880 [main] INFO com.itranswarp.learnjava.Main
Start process...
最佳實踐
在開發(fā)階段废亭,始終使用Commons Logging接口來寫入日志国章,并且開發(fā)階段無需引入Log4j。如果需要把日志寫入文件豆村, 只需要把正確的配置文件和Log4j相關(guān)的jar
包放入classpath
液兽,就可以自動把日志切換成使用Log4j寫入,無需修改任何代碼掌动。
小結(jié)
- 通過Commons Logging實現(xiàn)日志四啰,不需要修改代碼即可使用Log4j;
- 使用Log4j只需要把log4j2.xml和相關(guān)jar放入classpath粗恢;
- 如果要更換Log4j柑晒,只需要移除log4j2.xml和相關(guān)jar;
- 只有擴展Log4j時眷射,才需要引用Log4j的接口(例如匙赞,將日志加密寫入數(shù)據(jù)庫的功能,需要自己開發(fā))妖碉。