二) 日志規約
1. 【強制】應用中不可直接使用日志系統(Log4j、Logback)中的 API,而應依賴使用日志框架 SLF4J 中的 API,使用門面模式的日志框架,
有利於維護和各個類的日志處理方式統一。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger logger = LoggerFactory.getLogger(Abc.class);
【點評】規則好,未嚴格遵循
寧願使用SLF4J也不願使用Log4J,logback和java.util.Logging
正如我前面所說,在你的代碼中編寫日志記錄語句使用SLF4J的主要動機是讓你的程序獨立於任何特定的日志記錄庫,這些日志記錄庫可能需要與你現在配置不同的配置,而且還會引入更多令人頭疼的維護問題。然而除了這個之外,SLF4J API還有一個讓你使用SLF4J而不是用長期感興趣的 Log4j 更讓人信服的功能,也就是占位符功能,在代碼中用{}來表示。占位符功能與 String的format()方法中 的%s非常相似,因為它在運行時刻才提取所提供的真正的字符串。這不僅縮減了代碼中的許多字符串連接,而且減少了創建String對象所需要的資源。即便在你生產環境日志級別比如DEBUG和INFO級別的字符串連接可能不需要的時候,仍然可以起到同樣的效果。由於 字符串是不可更改的 ,而且它們是在字符串池中創建的,這些字符串使用了 堆內存 ,當應用在生產環境中運行在ERROR級別的時候,字符串在大多數情況下就不是必須的,比如DEBUG語句里的字符串就不是必須的。通過使用SLF4J,你可以延遲字符串的創建到運行時刻,這意味着只有在需要字符串的時候才創建它。如果你已經使用了log4j,那么你已經熟悉把調試語句放入if()條件內的工作場景,而SLF4J占位符功能比log4j更適合這種場景。下面是你用Log4j時的做法,當然這並不好玩而且它增加了不必要的公式化的代碼,減少了代碼的可讀性。
if (logger.isDebugEnabled()) {
logger.debug("Processing trade with id: " + id + " symbol: " + symbol); }
而如果你使用SLF4J,你可以使用更簡潔的格式達到同樣的效果,如下:
logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);
在SLF4J中,我們不需要進行字符串拼接,不會導致使用臨時字符串帶來的消耗。相反,我們使用帶占位符的模板消息來記錄日志信息,並提供實際值作為參數。也許你會想,要是有多個參數該怎么辦,你可以使用帶參數版的日志方法,也可以通過Object數組傳入。這確實是非常方便而且高效的記日志的方法。記住,在為日志信息產生最終的字符串之前,該方法會檢查是否開啟了特定的日志級別,這不僅降低了內存占用,而且預先減少了執行字符串拼接所消耗的CPU時間。下面的SLF4J日志方法的代碼,來自於slf4j-log4j12-1.6.1.jar包里的Log4j的適配器類Log4jLoggerAdapter.
public void debug(String format, Object arg1, Object arg2) { if (logger.isDebugEnabled()) { FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable()); } }
同樣值得了解是,日志也會對應用程序的性能產生壓力,大家通常宣揚的是只在生產環境中才強制記錄日志。
如何使用SLF4J和Log4J來做日志
除了上面所說的好處,我認為還有個警告需要說一下,為了使用SLF4J你不僅需要進入SLF4J API Jar包,比如slf4j-api-1.6.1.jar,還需要引入協同工作的JAR包,具體是什么jar包則依賴於后端你使用了什么日志工具庫。假如你想使用SLF4J,Simple Logging Facade for Java,還想使用Lo4J,那么你需要把下列jar包引入到你的classpath中,具體版本要視你使用的SLF4J和log4J版本而定, 比如:
slf4j-api-1.6.1.jar - JAR for SLF4J API
log4j-1.2.16.jar - JAR for Log4J API
slf4j-log4j12-1.6.1.jar - Log4J Adapter for SLF4J
如果你正在使用Maven來管理你的項目依賴,你可以只引入SLF4J JAR,然后maven會引入它所依賴的其它JAR包。為了使用Log4J和SLF4J,你可以在你項目的pom.xml中添加下列依賴:
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.6.1</version> </dependency>
順便說一下,如果你對使用帶參數版的日志方法感興趣,那就需要引入SLF4J 1.7版本。
總結
總結這篇文章,我具有充分的理由的來選擇SLF4J而不是直接選用Log4j, commons logging, logback 或者 java.util.logging。
1)在你的開源庫或者私有庫中使用SLF4J,可以使它獨立於任何的日志實現,這就意味着不需要管理多個庫和多個日志文件。你的客戶端將會體會到這一點。
2)SLF4J提供了占位日志記錄,通過移除對isDebugEnabled(), isInfoEnabled()等等的檢查提高了代碼的可讀性。
3)通過使用日志記錄方法,直到你使用到的時候,才會去構造日志信息(字符串),這就同時提高了內存和CPU的使用率。
4)做一個側面的說明,越少的臨時字符串,垃圾回收器就意味着越少的工作,這就意味着為你的應用程序提供更好的吞吐量和性能。
這些優勢都只是冰山一角,當你開始使用SL4J並閱讀它,你會學到更多的好處。我強烈建議,在java中任何新的代碼開發,都應使用SLF4J而不是任何的日志API,包括log4J
這里借鑒了很多大牛們的觀點和資料,參考網址:
1、http://www.cnblogs.com/ywlaker/p/6124067.html
2、http://www.cnblogs.com/xing901022/p/4149524.html
3、http://www.cnblogs.com/olmlo/p/3143468.html
4、http://www.open-open.com/lib/view/open1418652677495.html
5、http://www.cnblogs.com/eflylab/archive/2007/01/11/618001.html
一、slf4j介紹
SLF4J是為各種loging APIs提供一個簡單統一的接口,從而使得最終用戶能夠在部署的時候配置自己希望的loging APIs實現。Logging API實現既可以選擇直接實現SLF4J接口的loging APIs如: logback、SimpleLogger。也可以通過開發相應的來使用已有的API實現如Log4jLoggerAdapter、JDK14LoggerAdapter。
SLF4J 不依賴任何特殊的class loader機制,實際上,SLF4J 和已有日志實現的綁定是在編譯時靜態執行的,具體綁定工作是通過一個jar包實現的,使用時只要把相應的jar包(只有一個)放到類路徑上即可.
在 SLF4J發行版本中包含了幾個jar包,如slf4j-nop.jar, slf4j-simple.jar, slf4j-log4j12.jar, slf4j-log4j13.jar, slf4j-jdk14.jar and slf4j-jcl.jar等.SLF4J支持多個,比如NOP, Simple, log4j version 1.2, log4j version 1.3, JDK 1.4 logging, JCL and logback。
使用slf4j盡管很方便,但是讓很多人搞不明白slf4j那么多包怎么用。其實slf4j原理很簡單,他只提供一個核心slf4j api(就是slf4j-api.jar包),這個包只有日志的接口,並沒有實現,所以如果要使用就得再給它提供一個實現了些接口的日志包,比 如:log4j,common logging,jdk log日志實現包等,但是這些日志實現又不能通過接口直接調用,實現上他們根本就和slf4j-api不一致,因此slf4j又增加了一層來轉換各日志實 現包的使用,當然slf4j-simple除外。其結構如下:
slf4j-api(接口層)|
各日志實現包的連接層( slf4j-jdk14, slf4j-log4j)|
各日志實現包
下面這個圖更能說明其原理:
slf4j的構造是通過工廠類生存,我們調用接口時,接口的工廠會自動尋找恰當的實現,返回一個實現的實例給我服務。這些過程都是透明化的,用戶不需要進行任何操作。
loging APIs的接口,
關於上述所述的“實現查找符合自己接口的實現類”,對於slf4j其實同通過加載器的方式自動來實現。
關於JVM加載器,可以參考下圖理解:
二、slf4j具體使用
Logger logger = LoggerFactory.getLogger(name);
或者
Logger logger = LoggerFactory.getLogger(calss.class);
這樣就可使用logger對象進行日志輸出。
slf4j只提供了debug、warn、info、error等幾個簡單的接口,但由於slf4j只是接口,其具體實現是有對應的實現類完成。所以在在使用slf4j時都是和相應日志實現一起使用。
常用的使用有:slf4j+log4j、slf4j+Logback等
三、log4j介紹
Log4J是Apache的一個開放源代碼的項目。通過使用Log4J,程序員可以控制日志信息輸送的目的地,包括控制台,文件,GUI組件和NT事件記錄器,也可以控制每一條日志的輸出格式,或通過定義每一條日志信息的級別,更加細致地控制日志的生成過程。
Log4j的組成:
Log4j由三個重要的組成構成:日志記錄器(Loggers),輸出端(Appenders)和日志格式化器(Layout)。
Logger:控制要啟用或禁用哪些日志記錄語句,並對日志信息進行級別限制:Appenders指定了日志將打印到控制台還是文件中;而Layout則控制日志信息的顯示格式。
A).Logger對象的獲得或創建:
Logger被指定為實體,由一個String類的名字識別。Logger的名字是大小寫敏感的,且名字之間具有繼承關系,子名用父名作為前綴,用點“.”分隔,例如x.y是x.y.z的父親。
root Logger(根Logger)是所有Logger的祖先,它有如下屬性:
1.它總是存在的。
2.它不可以通過名字獲得。
root Logger可以通過以下語句獲得:
或:
其中調用Logger.getLogger(Class clazz)是目前ogger對象最理想的方法。
B)日志級別
每個Logger都被了一個日志級別(log level),用來控制日志信息的輸出。日志級別從高到低分為:
A:off 最高等級,用於關閉所有日志記錄。
B:fatal 指出每個嚴重的錯誤事件將會導致應用程序的退出。
C:error 指出雖然發生錯誤事件,但仍然不影響系統的繼續運行。
D:warm 表明會出現潛在的錯誤情形。
E:info 一般和在粗粒度級別上,強調應用程序的運行全程。
F:debug 一般用於細粒度級別上,對調試應用程序非常有幫助。
G:all 最低等級,用於打開所有日志記錄。
上面這些級別是定義在org.apache.log4j.Level類中。Log4j只建議使用4個級別,優先級從高到低分別是error,warn,info和debug。通過使用日志級別,可以控制應用程序中相應級別日志信息的輸出。例如,如果使用b了info級別,則應用程序中所有低於info級別的日志信息(如debug)將不會被打印出來。























C)輸出端Appender
Appender用來指定日志信息輸出到哪個地方,可以同時指定多個輸出目的地。Log4j允許將信息輸出到許多不同的輸出設備中,一個log信息輸出目的地就叫做一個Appender。
每個Logger都可以擁有一個或多個Appender,每個Appender表示一個日志的輸出目的地。可以使用Logger.addAppender(Appender app)為Logger增加一個Appender,也可以使用Logger.removeAppender(Appender app)為Logger刪除一個Appender。
以下為Log4j幾種常用的輸出目的地。
a:org.apache.log4j.ConsoleAppender:將日志信息輸出到控制台。
b:org.apache.log4j.FileAppender:將日志信息輸出到一個文件。
c:org.apache.log4j.DailyRollingFileAppender:將日志信息輸出到一個日志文件,並且每天輸出到一個新的日志文件。
d:org.apache.log4j.RollingFileAppender:將日志信息輸出到一個日志文件,並且指定文件的尺寸,當文件大小達到指定尺寸時,會自動把文件改名,同時產生一個新的文件。
e:org.apache.log4j.WriteAppender:將日志信息以流格式發送到任意指定地方。
f::org.apache.log4j.jdbc.JDBCAppender:通過JDBC把日志信息輸出到數據庫中。
日志輸出器,指定logger的輸出位置
1
|
log4j.appender.appenderName
=
className
|
每種appender都有若干配置項,下面逐一介紹
ConsoleAppender(常用)
1
2
3
|
Threshold
=
WARN:指定日志信息的最低輸出級別,默認DEBUG
ImmediateFlush
=
true:表示所有消息都會被立即輸出,設為false則不輸出,默認值是true
Target
=
System.err:默認值是System.out
|
FileAppender
1
2
3
4
|
Threshold
=
WARN:指定日志信息的最低輸出級別,默認DEBUG
ImmediateFlush
=
true:表示所有消息都會被立即輸出,設為false則不輸出,默認true
Append
=
false:true表示消息增加到指定文件中,false則將消息覆蓋指定的文件內容,默認true
File
=
D:
/
logs
/
logging.log4j:指定消息輸出到logging.log4j文件
|
DailyRollingFileAppender(常用)
1
2
3
4
5
6
7
8
9
10
11
12
|
Threshold
=
WARN:指定日志信息的最低輸出級別,默認DEBUG
ImmediateFlush
=
true:表示所有消息都會被立即輸出,設為false則不輸出,默認true
Append
=
false:true表示消息增加到指定文件中,false則將消息覆蓋指定的文件內容,默認true
File
=
D:
/
logs
/
logging.log4j:指定當前消息輸出到logging.log4j文件
DatePattern
=
'.'
yyyy
-
MM:每月滾動一次日志文件,即每月產生一個新的日志文件。當前月的日志文件名為logging.log4j,前一個月的日志文件名為logging.log4j.yyyy
-
MM
另外,也可以指定按周、天、時、分等來滾動日志文件,對應的格式如下:
1
)
'.'
yyyy
-
MM:每月
2
)
'.'
yyyy
-
ww:每周
3
)
'.'
yyyy
-
MM
-
dd:每天
4
)
'.'
yyyy
-
MM
-
dd
-
a:每天兩次
5
)
'.'
yyyy
-
MM
-
dd
-
HH:每小時
6
)
'.'
yyyy
-
MM
-
dd
-
HH
-
mm:每分鍾
|
RollingFileAppender
1
2
3
4
5
6
|
Threshold
=
WARN:指定日志信息的最低輸出級別,默認DEBUG
ImmediateFlush
=
true:表示所有消息都會被立即輸出,設為false則不輸出,默認true
Append
=
false:true表示消息增加到指定文件中,false則將消息覆蓋指定的文件內容,默認true
File
=
D:
/
logs
/
logging.log4j:指定消息輸出到logging.log4j文件
MaxFileSize
=
100KB
:后綴可以是KB,MB或者GB。在日志文件到達該大小時,將會自動滾動,即將原來的內容移到logging.log4j.
1
文件
MaxBackupIndex
=
2
:指定可以產生的滾動文件的最大數,例如,設為
2
則可以產生logging.log4j.
1
,logging.log4j.
2
兩個滾動文件和一個logging.log4j文件
|
日志格式化器Layout
有三種:
HTMLLayout:格式化日志輸出為HTML表格形式:如下
SimpleLayout:以一種非常簡單的方式格式化日志輸出,它打印三項內容:級別-信息
指定logger輸出內容及格式
1
|
log4j.appender.appenderName.layout
=
className
|
layout有4種選擇
1
2
3
4
|
org.apache.log4j.HTMLLayout(以HTML表格形式布局)
org.apache.log4j.PatternLayout(可以靈活地指定布局模式)
org.apache.log4j.SimpleLayout(包含日志信息的級別和信息字符串)
org.apache.log4j.TTCCLayout(包含日志產生的時間、線程、類別等信息)
|
layout也有配置項,下面具體介紹
HTMLLayout
1
2
|
LocationInfo
=
true:輸出java文件名稱和行號,默認false
Title
=
My Logging: 默認值是Log4J Log Messages
|
PatternLayout(最常用的配置)
1
|
ConversionPattern
=
%
m
%
n:設定以怎樣的格式顯示消息
|
設置格式的參數說明如下
1
2
3
4
5
6
7
8
9
10
11
12
13
|
%
p:輸出日志信息的優先級,即DEBUG,INFO,WARN,ERROR,FATAL
%
d:輸出日志時間點的日期或時間,默認格式為ISO8601,可以指定格式如:
%
d{yyyy
/
MM
/
dd HH:mm:ss,SSS}
%
r:輸出自應用程序啟動到輸出該log信息耗費的毫秒數
%
t:輸出產生該日志事件的線程名
%
l:輸出日志事件的發生位置,相當於
%
c.
%
M(
%
F:
%
L)的組合,包括類全名、方法、文件名以及在代碼中的行數
%
c:輸出日志信息所屬的類目,通常就是類全名
%
M:輸出產生日志信息的方法名
%
F:輸出日志消息產生時所在的文件名
%
L:輸出代碼中的行號
%
m:輸出代碼中指定的具體日志信息
%
n:輸出一個回車換行符,Windows平台為
"rn"
,Unix平台為
"n"
%
x:輸出和當前線程相關聯的NDC(嵌套診斷環境)
%
%
:輸出一個
"%"
字符
|
例:INFO - info
PatternLayout::根據指定的轉換模式格式化日志輸出,或者如果沒有指定任何轉換模式,就使用默認的轉化模式格式。
下面的代碼實現了SimpleLayout和FileAppender的程序



















Log4j的配置
配置Log4j環境就是指配置root Logger,包括把Logger為哪個級別,為它增加哪些Appender,以及為這些Appender設置Layout,等等。因為所有其他的Logger都是root Logger的后代,所以它們都繼承了root Logger的性質。這些可以通過設置系統屬性的方法來隱式地完成,也可以在程序中調用XXXConfigurator.configure()方法來顯式地完成。有以下幾種方式來配置Log4j。
A:配置放在文件里,通過環境變量傳遞文件名等信息,利用Log4j默認的初始化過程解析並配置。
B:配置放在文件里,通過應用服務器配置傳遞文件甸等信息,利用一個特定的Servlet來完成配置。
C:在程序中調用BasicConfigor.configure()方法。
D:配置放在文件里,通過命令行PropertyConfigurator.configure(args[])解析log4j.properties文件並配置Log4j。
下面對BasicConfigurator.configure()方法和PropertyConfigurator.config()方法分別進行介紹。
BasicConfigurator.configure()方法:
它使用簡單的方法配置Log4j環境。這個方法完成的任務是:
1:用默認的方式創建PatternLayout對象p:
PatternLayout p = new PatternLayout("%-4r[%t]%-5p%c%x-%m%n");
2:用p創建ConsoleAppender對象a,目標是System.out,標准輸出設備:
ConsoleAppender a = new CpnsoleAppender(p,ConsoleAppender.SYSTEM_OUT);
3:為root Logger增加一個ConsoleAppender p;
rootLogger.addAppender(p);
4:把rootLogger的log level設置為DUBUG級別;
rootLogger.setLevel(Level.DEBUG);
PropertyConfigurator.configure()方法:
當使用以下語句生成Logger對象時:

如果沒有調用BasicConfigurator.configure(),PropertyConfigurator.configure()或DOMConfigurator.configure()方法,Log4j會自動加載CLASSPATH下名為log4j.properties的配置文件。如果把此配置文件改為其他名字,例如my.properties,程序雖然仍能運行,但會報出不能正確初始化Log4j系統的提示。這時可以在程序中加上:

四 log4j完整配置示例
介紹完了log4j.properties內容,我們來配置一些常用的日志輸出吧
1
2
|
log4j.rootLogger
=
DEBUG,console,dailyFile,rollingFile,logFile
log4j.additivity.org.apache
=
true
|
控制台console日志輸出器
1
2
3
4
5
6
7
|
# 控制台(console)
log4j.appender.console
=
org.apache.log4j.ConsoleAppender
log4j.appender.console.Threshold
=
DEBUG
log4j.appender.console.ImmediateFlush
=
true
log4j.appender.console.Target
=
System.err
log4j.appender.console.layout
=
org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern
=
%
d{yyyy
-
MM
-
dd HH:mm:ss} [
%
p]
%
m
%
n
|
文件logFile日志輸出器
1
2
3
4
5
6
7
8
|
# 日志文件(logFile)
log4j.appender.logFile
=
org.apache.log4j.FileAppender
log4j.appender.logFile.Threshold
=
DEBUG
log4j.appender.logFile.ImmediateFlush
=
true
log4j.appender.logFile.Append
=
true
log4j.appender.logFile.
File
=
D:
/
logs
/
log.log4j
log4j.appender.logFile.layout
=
org.apache.log4j.PatternLayout
log4j.appender.logFile.layout.ConversionPattern
=
%
d{yyyy
-
MM
-
dd HH:mm:ss} [
%
p]
%
m
%
n
|
滾動文件rollingFile日志輸出器
1
2
3
4
5
6
7
8
9
10
|
# 滾動文件(rollingFile)
log4j.appender.rollingFile
=
org.apache.log4j.RollingFileAppender
log4j.appender.rollingFile.Threshold
=
DEBUG
log4j.appender.rollingFile.ImmediateFlush
=
true
log4j.appender.rollingFile.Append
=
true
log4j.appender.rollingFile.
File
=
D:
/
logs
/
log.log4j
log4j.appender.rollingFile.MaxFileSize
=
200KB
log4j.appender.rollingFile.MaxBackupIndex
=
50
log4j.appender.rollingFile.layout
=
org.apache.log4j.PatternLayout
log4j.appender.rollingFile.layout.ConversionPattern
=
%
d{yyyy
-
MM
-
dd HH:mm:ss} [
%
p]
%
m
%
n
|
定期滾動文件dailyFile日志輸出器
1
2
3
4
5
6
7
8
9
|
# 定期滾動日志文件(dailyFile)
log4j.appender.dailyFile
=
org.apache.log4j.DailyRollingFileAppender
log4j.appender.dailyFile.Threshold
=
DEBUG
log4j.appender.dailyFile.ImmediateFlush
=
true
log4j.appender.dailyFile.Append
=
true
log4j.appender.dailyFile.
File
=
D:
/
logs
/
log.log4j
log4j.appender.dailyFile.DatePattern
=
'.'
yyyy
-
MM
-
dd
log4j.appender.dailyFile.layout
=
org.apache.log4j.PatternLayout
log4j.appender.dailyFile.layout.ConversionPattern
=
%
d{yyyy
-
MM
-
dd HH:mm:ss} [
%
p]
%
m
%
n
|
五、log4j局部日志配置
以上介紹的配置都是全局的,整個工程的代碼使用同一套配置,意味着所有的日志都輸出在了相同的地方,你無法直接了當的去看數據庫訪問日志、用戶登錄日志、操作日志,它們都混在一起,因此,需要為包甚至是類配置單獨的日志輸出,下面給出一個例子,為“com.demo.test”包指定日志輸出器“test”,“com.demo.test”包下所有類的日志都將輸出到/log/test.log文件
1
2
3
4
5
|
log4j.logger.com.demo.test
=
DEBUG,test
log4j.appender.test
=
org.apache.log4j.FileAppender
log4j.appender.test.
File
=
/
log
/
test.log
log4j.appender.test.layout
=
org.apache.log4j.PatternLayout
log4j.appender.test.layout.ConversionPattern
=
%
d{yyyy
-
MM
-
dd HH:mm:ss} [
%
p]
%
m
%
n
|
也可以讓同一個類輸出不同的日志,為達到這個目的,需要在這個類中實例化兩個logger
1
2
|
private
static
Log logger1 = LogFactory.getLog(
"myTest1"
);
private
static
Log logger2 = LogFactory.getLog(
"myTest2"
);
|
然后分別配置
1
2
3
4
5
6
7
8
9
10
11
12
|
log4j.logger.myTest1
=
DEBUG,test1
log4j.additivity.myTest1
=
false
log4j.appender.test1
=
org.apache.log4j.FileAppender
log4j.appender.test1.
File
=
/
log
/
test1.log
log4j.appender.test1.layout
=
org.apache.log4j.PatternLayout
log4j.appender.test1.layout.ConversionPattern
=
%
d{yyyy
-
MM
-
dd HH:mm:ss} [
%
p]
%
m
%
n
log4j.logger.myTest2
=
DEBUG,test2
log4j.appender.test2
=
org.apache.log4j.FileAppender
log4j.appender.test2.
File
=
/
log
/
test2.log
log4j.appender.test2.layout
=
org.apache.log4j.PatternLayout
log4j.appender.test2.layout.ConversionPattern
=
%
d{yyyy
-
MM
-
dd HH:mm:ss} [
%
p]
%
m
%
n
|
六、slf4j與log4j聯合使用
slf4j是什么?slf4j只是定義了一組日志接口,但並未提供任何實現,既然這樣,為什么要用slf4j呢?log4j不是已經滿足要求了嗎?
是的,log4j滿足了要求,但是,日志框架並不只有log4j一個,你喜歡用log4j,有的人可能更喜歡logback,有的人甚至用jdk自帶的日志框架,這種情況下,如果你要依賴別人的jar,整個系統就用了兩個日志框架,如果你依賴10個jar,每個jar用的日志框架都不同,豈不是一個工程用了10個日志框架,那就亂了!
如果你的代碼使用slf4j的接口,具體日志實現框架你喜歡用log4j,其他人的代碼也用slf4j的接口,具體實現未知,那你依賴其他人jar包時,整個工程就只會用到log4j日志框架,這是一種典型的門面模式應用,與jvm思想相同,我們面向slf4j寫日志代碼,slf4j處理具體日志實現框架之間的差異,正如我們面向jvm寫java代碼,jvm處理操作系統之間的差異,結果就是,一處編寫,到處運行。況且,現在越來越多的開源工具都在用slf4j了
那么,怎么用slf4j呢?
首先,得弄到slf4j的jar包,maven依賴如下,log4j配置過程完全不變
1
2
3
4
5
|
<
dependency
>
<
groupId
>org.slf4j</
groupId
>
<
artifactId
>slf4j-api</
artifactId
>
<
version
>1.7.21</
version
>
</
dependency
>
|
然后,弄到slf4j與log4j的關聯jar包,通過這個東西,將對slf4j接口的調用轉換為對log4j的調用,不同的日志實現框架,這個轉換工具不同
1
2
3
4
5
|
<
dependency
>
<
groupId
>org.slf4j</
groupId
>
<
artifactId
>slf4j-log4j12</
artifactId
>
<
version
>1.7.21</
version
>
</
dependency
>
|
當然了,slf4j-log4j12這個包肯定依賴了slf4j和log4j,所以使用slf4j+log4j的組合只要配置上面這一個依賴就夠了
最后,代碼里聲明logger要改一下,原來使用log4j是這樣的
1
2
3
4
5
6
7
|
import
org.apache.log4j.Logger;
class
Test {
final
Logger log = Logger.getLogger(Test.
class
);
public
void
test() {
log.info(
"hello this is log4j info log"
);
}
}
|
現在要改成這樣
1
2
3
4
5
6
7
8
|
import
org.slf4j.Logger;
import
org.slf4j.LoggerFactory;
class
Test {
Logger log = LoggerFactory.getLogger(Test.
class
);
public
void
test() {
log.info(
"hello, my name is {}"
,
"chengyi"
);
}
}
|
依賴的Logger變了,而且,slf4j的api還能使用占位符,很方便。