為什么使用 SLF4J 而不是 Log4J 來做 Java 日志


阿里巴巴的代碼規范中 建議使用slf4j而不是 log4j;
slf4j使用了門面模式,
二) 日志規約

1. 【強制】應用中不可直接使用日志系統(Log4j、Logback)中的 API,而應依賴使用日志框架 SLF4J 中的 API,使用門面模式的日志框架,

   有利於維護和各個類的日志處理方式統一。

import org.slf4j.Logger; 

import org.slf4j.LoggerFactory; 

private static final Logger logger = LoggerFactory.getLogger(Abc.class); 

   【點評】規則好,未嚴格遵循

參考:點評阿里JAVA手冊之異常日志(異常處理 日志規約 )

原因:
每個Java開發人員都知道日志記錄對Java應用的重要性,尤其是對服務端應用,而且其中許多人都已經熟悉了各種記錄日志的庫,比如java.util.logging,Apache的log4j,logback,然而如果你不知道SLF4J,java的簡單記錄日志的設計的話 ,那么到了學習並在你的項目中使用它的時候了。在這篇Java文檔里,我們將學習為什么使用SLF4J比使用log4j或者java.util.logging更好。從我寫  Java開發人員的10個記錄日志的技巧 算起已經過去了很長一段時間了。我不記得我所寫的有關日志記錄的任何事情了。無論如何,讓我們回歸到這個主題上來,與所有提到的這些日志記錄庫相比,SLF4J與它們之間有一個主要的區別。SLF4J或者說是Java的簡單記錄日志設計沒有真正地實現日志記錄,相反它只是一個允許你使用任何處於后端的日志記錄庫的  抽象層 。如果你正在編寫內部或者外部使用的API或者應用庫的話,那么你真的不需要讓使用你所編寫的庫的客戶端還去選擇日志庫。假設項目已經使用了log4j,而且你包含一個名為Apache Active MQ的庫,這個庫還依賴於另一個日志記錄庫logback的話,那么你還需要包含它們,然而,如果Apache Active MQ使用了SLF4J的話,你可以繼續使用你的日志記錄庫,而不需要痛苦地添加和維護新的日志記錄框架。簡短的說,SLF4J讓你的代碼獨立於任何特定的日志記錄API,這個好的想法尤其適合於公共的API開發人員。雖然日志記錄庫的抽象理念不是新的,而且Apache的commons logging日志記錄庫也是用了這個理念,不過現在SLF4J很快就會成為Java世界里標准的日志記錄庫。讓我們看一些使用 SLF4J而不使用log4j,logback或者java.util.logging的理由。 
 

寧願使用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)|
各日志實現包

下面這個圖更能說明其原理:

 

在這里還需要注意的是,連接層的jar包和實現的jar的版本要一致。

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可以通過以下語句獲得:

public static Logger Logger.getRootLogger();

或:

public static Logger Logger.getLogger(Class clazz)

其中調用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)將不會被打印出來。

package log4j;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
public class Log4jTest {
    public static void main(String[] args) {    
        Logger logger = Logger.getLogger(Log4jTest.class);         
        //使用默認的配置信息,不需要寫log4j.properties
        BasicConfigurator.configure();
        //設置日志輸出級別為info,這將覆蓋配置文件中設置的級別
        logger.setLevel(Level.INFO);
        //下面的消息將被輸出
        logger.info("this is an info");
        logger.warn("this is a warn");
        logger.error("this is an error");
        logger.fatal("this is a fatal");
    }
}

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的程序

public static void main(String[] args) {
        
        Logger logger = Logger.getLogger(Log4jTest.class);        
        SimpleLayout layout = new SimpleLayout();
        //HTMLLayout  layout = new HTMLLayout();
        FileAppender appender = null;
        try{
            //把輸出端配置到out.txt
            appender = new FileAppender(layout,"out.txt",false);
        }catch(Exception e){            
        }
        logger.addAppender(appender);//添加輸出端
        logger.setLevel((Level)Level.DEBUG);//覆蓋配置文件中的級別
        logger.debug("debug");
        logger.info("info");
        logger.warn("warn");
        logger.error("error");
        logger.fatal("fatal");
    }

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對象時:

 static Logger logger = Logger.getLogger(mycalss.class);

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

PropertyConfigurator.configure("classes/my.properties");

 

四 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還能使用占位符,很方便。

參考:slf4j+log4j結合使用


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM