slf4j的簡單用法以及與log4j的區別

前在項目中用的日誌記錄器都是log4j的日誌記錄器,但是到了新公司發現都是slf4j,因而想着研究一下slf4j的用法。html

   注意:每次引入Logger的時候注意引入的jar包,由於有Logger的包太多了。。。。。。java

     Logger必須做爲類的靜態變量使用。緣由以下:apache

1 使用static修飾的屬性是歸這個類使用的
2 也就是說不論這個類實例化多少個,你們用的都是同一個static屬性
3 log4j記錄的是當前類的日誌,不是每一個實例的日誌
4 因此只要有一個記錄就能夠了


建立日誌記錄器方法:(最好聲明加final關鍵字)
    //private static final Logger logger = LoggerFactory.getLogger(Slf4jTest.class);// slf4j日誌記錄器
    private static final Logger logger = LoggerFactory.getLogger(Slf4jTest.class.getName());// slf4j日誌記錄器

 

簡要記錄一下日誌級別:
複製代碼
每一個Logger都被了一個日誌級別(log level),用來控制日誌信息的輸出。日誌級別從高到低分爲:
A:off         最高等級,用於關閉全部日誌記錄。
B:fatal       指出每一個嚴重的錯誤事件將會致使應用程序的退出。
C:error      指出雖然發生錯誤事件,但仍然不影響系統的繼續運行。
D:warm     代表會出現潛在的錯誤情形。
E:info         通常和在粗粒度級別上,強調應用程序的運行全程。
F:debug     通常用於細粒度級別上,對調試應用程序很是有幫助。
G:all           最低等級,用於打開全部日誌記錄。
複製代碼


其實對於不一樣的版本有不一樣的級別,不過最經常使用的就是debug\info\warn\error.下面是摘自log4j-1.2.17.jar中的級別:
能夠看出:all\TRACE\debug
同級別。off與fatal同級別。
複製代碼
package org.apache.log4j;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;


public class Level extends Priority implements Serializable {

   /**
    * TRACE level integer value.
    * @since 1.2.12
    */
  public static final int TRACE_INT = 5000;

final static public Level OFF = new Level(OFF_INT, "OFF", 0); final static public Level FATAL = new Level(FATAL_INT, "FATAL", 0); final static public Level ERROR = new Level(ERROR_INT, "ERROR", 3); final static public Level WARN = new Level(WARN_INT, "WARN", 4); final static public Level INFO = new Level(INFO_INT, "INFO", 6); final static public Level DEBUG = new Level(DEBUG_INT, "DEBUG", 7); public static final Level TRACE = new Level(TRACE_INT, "TRACE", 7); final static public Level ALL = new Level(ALL_INT, "ALL", 7); static final long serialVersionUID = 3491141966387921974L; protected Level(int level, String levelStr, int syslogEquivalent) { super(level, levelStr, syslogEquivalent); } public static Level toLevel(int val, Level defaultLevel) { switch(val) { case ALL_INT: return ALL; case DEBUG_INT: return Level.DEBUG; case INFO_INT: return Level.INFO; case WARN_INT: return Level.WARN; case ERROR_INT: return Level.ERROR; case FATAL_INT: return Level.FATAL; case OFF_INT: return OFF; case TRACE_INT: return Level.TRACE; default: return defaultLevel; } } 。。。。。
複製代碼


0.依賴的Jar包
複製代碼
        <!-- slf4j 依賴包 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.0-rc1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.0-rc1</version>
        </dependency>
複製代碼

 

或者手動導入下面的包:api

 

介紹:slf4j-api提供接口,slf4j-log4j提供具體的實現。也就是 slf4j只是一個日誌標準,並非日誌系統的具體實現,若是項目只有slf4j的包是沒有辦法實現日誌功能的。多線程

 

1 基本介紹

  SLF4J不一樣於其餘日誌類庫,與其它日誌類庫有很大的不一樣。SLF4J(Simple logging Facade for Java)不是一個真正的日誌實現,而是一個抽象層( abstraction layer),它容許你在後臺使用任意一個日誌類庫。若是是在編寫供內外部均可以使用的API或者通用類庫,那麼你真不會但願使用你類庫的客戶端必須使用你選擇的日誌類庫。app

  若是一個項目已經使用了log4j,而你加載了一個類庫,比方說 Apache Active MQ——它依賴於於另一個日誌類庫logback,那麼你就須要把它也加載進去。但若是Apache Active MQ使用了SLF4J,你能夠繼續使用你的日誌類庫而無需忍受加載和維護一個新的日誌框架的痛苦。框架

  總的來講,SLF4J使你的代碼獨立於任意一個特定的日誌API,這是對於API開發者的很好的思想。雖然抽象日誌類庫的思想已經不是新鮮的事物,並且Apache commons logging也已經在使用這種思想了,但SLF4J正迅速成爲Java世界的日誌標準。讓咱們再看幾個使用SLF4J而不是log4j、logback或者java.util.logging的理由。post

2 SLF4J對比Log4J,logback和java.util.Logging的優點

正如我以前說的,在你的代碼中使用SLF4J寫日誌語句的主要出發點是使得你的程序獨立於任何特定的日誌類庫,依賴於特定類庫可能須要使用不一樣於你已有的配置,而且致使更多維護的麻煩。除此以外,還有一個SLF4J API的特性是使得我堅持使用SLF4J而拋棄我長期間鍾愛的Log4j的理由,是被稱爲佔位符(place holder),在代碼中表示爲「{}」的特性。佔位符是一個很是相似於在Stringformat()方法中的%s,由於它會在運行時被某個提供的實際字符串所替換。這不只下降了你代碼中字符串鏈接次數,並且還節省了新建的String對象。經過使用SLF4J,你能夠在運行時延遲字符串的創建,這意味着只有須要的String對象才被創建。而若是你已經使用log4j,那麼你已經對於在if條件中使用debug語句這種變通方案十分熟悉了,但SLF4J的佔位符就比這個好用得多。測試

3.slf4j的簡單用法

1.簡單使用

1.配置文件(log4j.properties)ui

複製代碼
log4j.rootLogger=debug, C

log4j.appender.A=org.apache.log4j.ConsoleAppender
log4j.appender.A.layout=org.apache.log4j.PatternLayout
log4j.appender.A.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n

log4j.appender.B=org.apache.log4j.FileAppender
log4j.appender.B.File=E:\\log.log
log4j.appender.B.layout=org.apache.log4j.SimpleLayout

log4j.appender.C=org.apache.log4j.RollingFileAppender
log4j.appender.C.File=E:\\log.html
log4j.appender.C.MaxFileSize=1000KB
log4j.appender.C.MaxBackupIndex=10
log4j.appender.C.layout=org.apache.log4j.HTMLLayout
log4j.appender.C.encoding=gbk

log4j.appender.D=org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File=E:\\log.log
log4j.appender.D.layout=org.apache.log4j.TTCCLayout
複製代碼

 

注意:  

  1.若是須要輸出到多個位置的時候能夠逗號隔開,好比:   log4j.rootLogger=info, A, B 

  2.    log4j.appender.C.encoding=gbk 的配置是爲了解決中文亂碼,有時候也能夠設置爲UTF-8試試

 

關於pattern的設置以下:

複製代碼
%p: 輸出日誌信息優先級,即DEBUG,INFO,WARN,ERROR,FATAL,%d: 輸出日誌時間點的日期或時間,默認格式爲ISO8601,也能夠在其後指定格式,好比:%d{yyyy-MM-dd HH:mm:ss,SSS},輸出相似:2011-10-18 22:10:28,921 
%r: 輸出自應用啓動到輸出該log信息耗費的毫秒數 
%c: 輸出日誌信息所屬的類目,一般就是所在類的全名 
%t: 輸出產生該日誌事件的線程名 
%l: 輸出日誌事件的發生位置,至關於%C.%M(%F:%L)的組合,包括類目名、發生的線程,以及在代碼中的行數。 
%x: 輸出和當前線程相關聯的NDC(嵌套診斷環境),尤爲用到像java servlets這樣的多客戶多線程的應用中。 
%%: 輸出一個"%"字符 
%F: 輸出日誌消息產生時所在的文件名稱 
%L: 輸出代碼中的行號 
%m: 輸出代碼中指定的消息,產生的日誌具體信息 
%n: 輸出一個回車換行符,Windows平臺爲"\r\n",Unix平臺爲"\n"輸出日誌信息換行 
複製代碼

 

2.測試代碼:

複製代碼
package cn.xm.exam.test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Slf4jTest {
    private static Logger logger = LoggerFactory.getLogger(Slf4jTest.class);// slf4j日誌記錄器

    public static void main(String[] args) {

        // 普通的日誌記錄
        logger.debug("普通的日誌記錄");

        // {}佔位符記錄日誌
        for (int i = 0; i < 3; i++) {
            logger.debug("這是第{}條記錄", i);
        }

        // 用\轉義{}
        logger.debug("Set \\{} differs from {}", "3"); // output:Set {} differs
                                                        // from 3

        // 兩個參數
        logger.debug("兩個佔位符,能夠傳兩個參數{}----{}", 1, 2);

        // 多個參數(可變參數)
        logger.debug("debug:多個佔位符,{},{},{},{}", 1, 2, 3, 4);

        // 多個參數(可變參數)
        logger.info("info:多個佔位符,{},{},{},{}", 1, 2, 3, 4);

        // 多個參數(可變參數)
        logger.error("error:多個佔位符,{},{},{},{}", 1, 2, 3, 4);

    }

}
複製代碼

結果:

2018-08-18 10:58:38 [cn.xm.exam.test.Slf4jTest]-[DEBUG] 普通的日誌記錄
2018-08-18 10:58:38 [cn.xm.exam.test.Slf4jTest]-[DEBUG] 這是第0條記錄
2018-08-18 10:58:38 [cn.xm.exam.test.Slf4jTest]-[DEBUG] 這是第1條記錄
2018-08-18 10:58:38 [cn.xm.exam.test.Slf4jTest]-[DEBUG] 這是第2條記錄
2018-08-18 10:58:38 [cn.xm.exam.test.Slf4jTest]-[DEBUG] Set {} differs from 3
2018-08-18 10:58:38 [cn.xm.exam.test.Slf4jTest]-[DEBUG] 兩個佔位符,能夠傳兩個參數1----2
2018-08-18 10:58:38 [cn.xm.exam.test.Slf4jTest]-[DEBUG] debug:多個佔位符,1,2,3,4
2018-08-18 10:58:38 [cn.xm.exam.test.Slf4jTest]-[INFO] info:多個佔位符,1,2,3,4
2018-08-18 10:58:38 [cn.xm.exam.test.Slf4jTest]-[ERROR] error:多個佔位符,1,2,3,4

 

注意:debug,info,error,等各個級別的方法均可以傳入多個可變參數:

 

至於詳細的日誌級別的介紹參考個人另外一篇博客:http://www.cnblogs.com/qlqwjy/p/7192947.html

 

2.關於正式開發中的日記記錄的方法:(重要)

  項目中日誌記錄仍是有不少說法的,好比保存日誌級別,日誌應該打印的信息,日誌參數的設置等:

 

1.通常是將捕捉到的Exception對象做爲日誌記錄的最後一個參數(會顯示具體的出錯信息以及出錯位置),並且要放在{}能夠格式化的參數以外,防止被{}轉爲e.toString()

例如一個標準的日記記錄的方法:

複製代碼
package cn.xm.exam.test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Slf4jTest {

    private static Logger log = LoggerFactory.getLogger(Slf4jTest.class);

    public static void main(String[] args) {
        openFile("xxxxxx");
    }

    public static void openFile(String filePath) {
        File file = new File(filePath);
        try {
            InputStream in = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            log.error("can found file [{}]", filePath, e);
        }
    }

}
複製代碼

結果:

複製代碼
2018-08-18 10:50:03 [cn.xm.exam.test.Slf4jTest]-[ERROR] can found file [xxxxxx]
java.io.FileNotFoundException: xxxxxx (系統找不到指定的文件。)
    at java.io.FileInputStream.open(Native Method)
    at java.io.FileInputStream.<init>(FileInputStream.java:146)
    at cn.xm.exam.test.Slf4jTest.openFile(Slf4jTest.java:22)
    at cn.xm.exam.test.Slf4jTest.main(Slf4jTest.java:16)
複製代碼

 

注意: {}的做用是調用對應參數的toString()方法格式化日誌,若是exception放在對應參數的位置上也會被格式化。因此,e要放在{}參數以外,並且只能放在最後一個。若是放在中間也不會被打印錯誤信息:

例如:

  • 只要放到{}以外的最後一個參數能夠打印錯誤信息(包括信息和位置)
複製代碼
    public static void openFile(String filePath) {
        File file = new File(filePath);
        try {
            InputStream in = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            log.error("error:can found file [{}]", filePath, 3, e);
        }
    }
複製代碼

結果:

複製代碼
2018-08-18 11:11:18 [cn.xm.exam.test.Slf4jTest]-[ERROR] error:can found file [xxxxxx]
java.io.FileNotFoundException: xxxxxx (系統找不到指定的文件。)
    at java.io.FileInputStream.open(Native Method)
    at java.io.FileInputStream.<init>(FileInputStream.java:146)
    at cn.xm.exam.test.Slf4jTest.openFile(Slf4jTest.java:22)
    at cn.xm.exam.test.Slf4jTest.main(Slf4jTest.java:16)
複製代碼

 

  • 放到{}以外的非最後一個參數不會打印錯誤信息
複製代碼
    public static void openFile(String filePath) {
        File file = new File(filePath);
        try {
            InputStream in = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            log.error("error:can found file [{}]", filePath,e,3);
        }
    }
複製代碼

結果:

2018-08-18 11:10:38 [cn.xm.exam.test.Slf4jTest]-[ERROR] error:can found file [xxxxxx]

 

 

 

2.儘可能不使用e.getMessage(),由於有的異常不必定有message,可使用e.toString只會顯示信息,不會顯示出錯的位置信息(不建議這種)

例如:

複製代碼
package cn.xm.exam.test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Slf4jTest {

    private static Logger log = LoggerFactory.getLogger(Slf4jTest.class);

    public static void main(String[] args) {
        openFile("xxxxxx");
    }

    public static void openFile(String filePath) {
        File file = new File(filePath);
        try {
            InputStream in = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            //下面兩句的效果同樣
            log.error("can found file [{}],cause:{}", filePath, e.toString());
            log.error("can found file [{}],cause:{}", filePath, e);
        }
    }

}
複製代碼

結果:

2018-08-18 10:53:31 [cn.xm.exam.test.Slf4jTest]-[ERROR] can found file [xxxxxx],cause:java.io.FileNotFoundException: xxxxxx (系統找不到指定的文件。)
2018-08-18 10:53:31 [cn.xm.exam.test.Slf4jTest]-[ERROR] can found file [xxxxxx],cause:java.io.FileNotFoundException: xxxxxx (系統找不到指定的文件。)

 

 

補充:一份上線系統使用的log4j.properties配置:

複製代碼
log4j.rootLogger=info,B

log4j.appender.A=org.apache.log4j.ConsoleAppender
log4j.appender.A.layout=org.apache.log4j.PatternLayout
log4j.appender.A.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n

log4j.appender.B=org.apache.log4j.RollingFileAppender
log4j.appender.B.File=E:\\test.log
log4j.appender.B.MaxFileSize=10MB
log4j.appender.B.MaxBackupIndex=5
log4j.appender.B.layout=org.apache.log4j.PatternLayout
log4j.appender.B.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n
複製代碼

%d{yyyy-MM-dd HH:mm:ss} 也能夠改成%d{yyyy-MM-dd HH:mm:ss,SSS} SSS表明至少輸出3位數字的毫秒。若是4個S的話不足位補0。

 

解釋:org.apache.log4j.RollingFileAppender是log4j的一個類,下面的配置都是它的屬性的配置:(其中還有好多屬性來自其父類,須要的時候咱們能夠去查閱)

 

log4j.appender.B.File    指定輸出的日誌的文件名稱以及路徑

log4j.appender.B.MaxFileSize   指定每一個文件的最大大小

log4j.appender.B.MaxBackupIndex  指定文件達到文件大小以後最多重命名的文件數量

log4j.appender.B.layout  指定採用的樣式

log4j.appender.B.layout.ConversionPattern  指定樣式的格式(值通常固定)

 

測試代碼:

複製代碼
package cn.qlq.slf4jTest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Slf4jTest {
    private static Logger logger = LoggerFactory.getLogger(Slf4jTest.class);// slf4j日誌記錄器

    public static void main(String[] args) {

        while (true) {

            // 普通的日誌記錄
            logger.error("普通的日誌記錄");

            // {}佔位符記錄日誌
            for (int i = 0; i < 3; i++) {
                logger.info("這是第{}條記錄", i);
            }

            // 用\轉義{}
            logger.info("Set \\{} differs from {}", "3"); // output:Set {} differs from 3

            // 兩個參數
            logger.info("兩個佔位符,能夠傳兩個參數{}----{}", 1, 2);

        }

    }

}
複製代碼

結果:(會產生對應的文件,test.log永遠保存最新的日誌,達到10M後會重命名文件爲test.log.1,並將原來test.log.1命名爲test.log.2....)

log內容以下:

 

 

補充:Threshold還能夠指定輸出的日誌級別: (若是設置不起做用查看項目是否是用的log4j的包,有可能有多個log4j包,形成衝突)

  有時候咱們須要把一些報錯ERROR日誌單獨存到指定文件 ,這時候,Threshold屬性就派上用場了,好比:

複製代碼
log4j.rootLogger=info,B,C

log4j.appender.B=org.apache.log4j.RollingFileAppender
log4j.appender.B.Threshold=info
log4j.appender.B.File=E:\\info.log
log4j.appender.B.MaxFileSize=10MB
log4j.appender.B.MaxBackupIndex=5
log4j.appender.B.layout=org.apache.log4j.PatternLayout
log4j.appender.B.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n

log4j.appender.C=org.apache.log4j.RollingFileAppender
log4j.appender.C.Threshold=error
log4j.appender.C.File=E:\\error.log
log4j.appender.C.MaxFileSize=10MB
log4j.appender.C.MaxBackupIndex=5
log4j.appender.C.layout=org.apache.log4j.PatternLayout
log4j.appender.C.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n
複製代碼

 

上面B格式的就是info級別以上的日誌,包括error信息 

  C格式的就是error級別以上的信息。

 

  固然這裏有個提早  rootLogger裏配置的level必須小於Threshold等級,不然無效 仍是按照總的rootLogger裏的level來輸出,通常咱們實際實用的話 rootLogger裏配置DEBUG,而後某個文件專門存儲ERRO日誌,就配置下Threshold爲ERROR

 

代碼仍是上面的測試代碼:

結果:

 

 

 error.log內容:全是error級別以上的日誌

 

info.log內容(info級別以上,包括error)

 

補充:log4j也能夠對不一樣的包進行不一樣的配置,也就是針對不一樣的包採用不一樣的日誌級別與日誌控制器

  有時候咱們也但願對不一樣的包採用不通的日誌記錄級別以及不一樣的日誌記錄方式。log4j徹底能夠作到這點,例以下面

默認包採用rootLogger的配置,info級別、在控制檯與文件中進行顯示;同時又修改了cn下面的a、b、c包的日誌級別:

  cn.a只下降了級別爲debug,輸出方式仍是console與file兩種。(通常咱們採用這種方式修改級別便可,若是再設置輸出方式會在原來的基礎上增長方式)

  cn.b級別設爲info,方式設爲console,實際是加了第三種方式

  cn.c級別設置爲error,方式設爲file,實際也是在rootLogger基礎上增長第三種方式

   級別會以log4j.logger.XX級別爲準,無論rootLogger級別高於對具體包的設置仍是低於具體包的設置;輸出方式會在rootLogger的基礎上增長新的方式,若是沒有額外的方式採用rootLogger的方式。

例如:(注意標紅地方)

複製代碼
log4j.rootLogger=info,console,file

log4j.logger.cn.a=debug
log4j.logger.cn.b=info,console
log4j.logger.cn.c=error,file

log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n

log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=E:\\test.log
log4j.appender.file.MaxFileSize=10MB
log4j.appender.file.MaxBackupIndex=5
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n
複製代碼

 

測試:

包結構:

 

Root

複製代碼
package cn;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RootClass {
    private static final Logger LOGGER = LoggerFactory.getLogger(RootClass.class);

    public static void main(String[] args) {
        LOGGER.debug("RootClass");
        LOGGER.info("RootClass");
        LOGGER.error("RootClass");
    }
}
複製代碼

運行結果:

2018-10-23 19:38:04 [cn.RootClass]-[INFO] RootClass
2018-10-23 19:38:04 [cn.RootClass]-[ERROR] RootClass

 

 AC1

複製代碼
package cn.a;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AC1 {
    private static final Logger LOGGER = LoggerFactory.getLogger(AC1.class);

    public static void main(String[] args) {
        LOGGER.debug("AC1");
        LOGGER.info("AC1");
        LOGGER.error("AC1");
    }
}
複製代碼

運行結果:

2018-10-23 19:38:31 [cn.a.AC1]-[DEBUG] AC1
2018-10-23 19:38:31 [cn.a.AC1]-[INFO] AC1
2018-10-23 19:38:31 [cn.a.AC1]-[ERROR] AC1

 

BC1:

複製代碼
package cn.b;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class BC1 {
    private static final Logger LOGGER = LoggerFactory.getLogger(BC1.class);

    public static void main(String[] args) {
        LOGGER.debug("BC1");
        LOGGER.info("BC1");
        LOGGER.error("BC1");
    }
}
複製代碼

運行結果:

2018-10-23 19:39:04 [cn.b.BC1]-[INFO] BC1
2018-10-23 19:39:04 [cn.b.BC1]-[INFO] BC1
2018-10-23 19:39:04 [cn.b.BC1]-[ERROR] BC1
2018-10-23 19:39:04 [cn.b.BC1]-[ERROR] BC1

 

CC1:

複製代碼
package cn.c;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CC1 {
    private static final Logger LOGGER = LoggerFactory.getLogger(CC1.class);
    public static void main(String[] args) {
        LOGGER.debug("CC1");
        LOGGER.info("CC1");
        LOGGER.error("CC1");
    }
}
複製代碼

運行結果:

2018-10-23 19:39:28 [cn.c.CC1]-[ERROR] CC1

 

最後查看E:/test.log

複製代碼
2018-10-23 19:38:04 [cn.RootClass]-[INFO] RootClass
2018-10-23 19:38:04 [cn.RootClass]-[ERROR] RootClass
2018-10-23 19:38:31 [cn.a.AC1]-[DEBUG] AC1
2018-10-23 19:38:31 [cn.a.AC1]-[INFO] AC1
2018-10-23 19:38:31 [cn.a.AC1]-[ERROR] AC1
2018-10-23 19:39:04 [cn.b.BC1]-[INFO] BC1
2018-10-23 19:39:04 [cn.b.BC1]-[ERROR] BC1
2018-10-23 19:39:28 [cn.c.CC1]-[ERROR] CC1
2018-10-23 19:39:28 [cn.c.CC1]-[ERROR] CC1
複製代碼

 

補充:對父包設置日誌級別,若是子包沒有設置默認採用父包的設置,若是子包設置了會採用單獨的設置

配置修改cn包設置以及對b包單獨進行設置:

log4j.logger.cn=error
log4j.logger.cn.b=info,console

 

測試cn.d包默認採用cn包的error級別:

複製代碼
package cn.d;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DC1 {
    private static final Logger LOGGER = LoggerFactory.getLogger(DC1.class);

    public static void main(String[] args) {
        LOGGER.debug("D");
        LOGGER.info("D");
        LOGGER.error("D");
    }
}
複製代碼

結果:

2018-12-29 13:30:09 [cn.d.DC1]-[ERROR] D

 

測試cn.b採用單獨對cn.b包的配置

複製代碼
package cn.b;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class BC1 {
    private static final Logger LOGGER = LoggerFactory.getLogger(BC1.class);

    public static void main(String[] args) {
        LOGGER.debug("BC1");
        LOGGER.info("BC1");
        LOGGER.error("BC1");
    }
}
複製代碼

結果:

2018-12-29 13:31:27 [cn.b.BC1]-[INFO] BC1
2018-12-29 13:31:27 [cn.b.BC1]-[INFO] BC1
2018-12-29 13:31:27 [cn.b.BC1]-[ERROR] BC1
2018-12-29 13:31:27 [cn.b.BC1]-[ERROR] BC1

 

補充:上面的對包的具體設置日誌級別雖然不受總的log4j.rootLogger的日誌級別的限制,可是卻受特殊的日誌的Threshold屬性的限制,也就是對具體包的設置必須高於其記錄器的Threshold屬性,不然以其記錄器的Threshold屬性爲準

例如:修改上面的日誌配置(每一個日誌記錄器增長Threshold屬性)

複製代碼
log4j.rootLogger=info,console,file

log4j.logger.cn.a=debug
log4j.logger.cn.b=info,console
log4j.logger.cn.c=error,file

log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Threshold=info
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n

log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.Threshold=error
log4j.appender.file.File=E:\\test.log
log4j.appender.file.MaxFileSize=10MB
log4j.appender.file.MaxBackupIndex=5
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n
複製代碼

運行RootClass:

2018-11-12 23:02:44 [cn.RootClass]-[INFO] RootClass
2018-11-12 23:02:44 [cn.RootClass]-[ERROR] RootClass

 

運行AC1:

2018-11-12 23:03:08 [cn.a.AC1]-[INFO] AC1
2018-11-12 23:03:08 [cn.a.AC1]-[ERROR] AC1

 

運行BC1:

2018-11-12 23:03:33 [cn.b.BC1]-[INFO] BC1
2018-11-12 23:03:33 [cn.b.BC1]-[INFO] BC1
2018-11-12 23:03:33 [cn.b.BC1]-[ERROR] BC1
2018-11-12 23:03:33 [cn.b.BC1]-[ERROR] BC1

 

運行CC1:

2018-11-12 23:04:25 [cn.c.CC1]-[ERROR] CC1

 

查看test.log:

2018-11-12 23:02:44 [cn.RootClass]-[ERROR] RootClass
2018-11-12 23:03:08 [cn.a.AC1]-[ERROR] AC1
2018-11-12 23:03:33 [cn.b.BC1]-[ERROR] BC1
2018-11-12 23:04:25 [cn.c.CC1]-[ERROR] CC1
2018-11-12 23:04:25 [cn.c.CC1]-[ERROR] CC1

因此總結上面的日記記錄級別的設置優先級能夠總結爲:Threshold  > 具體包的設置  >  rootLogger的全局配置

相關文章
相關標籤/搜索