Java日誌框架之JUL(java util logging)詳解

定義:

JUL全稱Java util logging,是java原生的日誌框架,使用時不需要另外引入第三方類庫,相對於其他框架使用方便,學習簡單,能夠在小型的應用中靈活使用。

架構:
在這裏插入圖片描述

  • Application:我們的程序應用。
  • LogManager:管理Logger,是個單例Bean。
  • Logger:日誌記錄器,我們的應用程序通過獲取日誌記錄器Logger對象,調用其API來發布日誌信息,Logger通常是應用程序訪問日誌系統的入口。
  • Handler:日誌處理器,每個Logger會關聯持有多個Handler,Logger會把日誌交給Handler進行處理,由Handler負責日誌記錄。Handler在這裏是一個抽象,其具體實現決定了日誌輸出的位置,比如控制檯,文件等。
  • Formattter:日誌格式轉化器,負責對日誌的格式進行處理。決定了輸出的日誌的最終形式。
  • Level:每條日誌信息都有一個關聯的日誌級別,該級別處理指導了日誌信息的重要性。我們可以將Level作用於Logger和Handler上。以便於我們過濾消息。
  • Filter:過濾器,根據規則過濾掉某些日誌信息。

總體流程:

  1. 初始化LogManager,加載logging.properties配置文件,添加Logger到LogManager中。
  2. 從單例Bean LogManager獲取Logger。
  3. 設置日誌級別Level。
  4. Handler處理日誌輸出。
  5. Formatter處理日誌格式。

日誌的級別:

JUL日誌級別由類java.util.logging.Level記錄,總共有七個日誌級別,由高到低分別是:

SEVERE //錯誤信息,一般是記錄導致系統終止的信息。
WARNING //警告信息,一般記錄程序的問題,該問題不會導致系統終止,但是卻值得我們關注。
INFO // 一般信息,一般記錄一些連接信息,訪問信息等。(這是JUL的默認級別)
CONFIG // 一般記錄加載配置文件等日誌信息。
FINE // Debug日誌信息,一般記錄程序一般運行的狀態。執行的流程參數的傳遞等信息。
FINER //與FINE 類似,只是記錄的顆粒度要高一些。
FINEST //與上面兩個類似,只是記錄的顆粒度要高一些。

還有兩個特殊的級別:
OFF: 可用來關閉日誌信息,不輸出任何級別的日誌。
ALL: 記錄所有級別的日誌信息。

當Logger或者Handler設置了某一日誌級別,低於該級別的日誌信息將不會被記錄。

入門案例:

public class JULDemo {

    @Test
    public void testHelloWorld(){
        //創建日誌記錄器,傳入參數是日誌記錄器的名稱
        Logger logger = Logger.getLogger("juldemo.JULDemo");

        //記錄severe級別信息
        logger.severe("severe信息");
        //記錄warning級別信息
        logger.warning("warning信息");
        logger.info("info信息");
        logger.config("config信息");
        logger.fine("fine信息");
        logger.finer("finer信息");
        logger.finest("finest信息");
    }
}

輸出結果:
在這裏插入圖片描述
因爲默認的日誌級別是INFO,所以比INFO級別低的 CONFIG、FINE、FINER、FINEST的日誌記錄消息沒有記錄。

自定義日誌級別:

@Test
    public void testCustomLogLevel(){
        //創建日誌記錄器,傳入參數是日誌記錄器的名稱
        Logger logger = Logger.getLogger("juldemo.JULDemo");



        //創建一個輸出到控制檯的handler
        ConsoleHandler consoleHandler = new ConsoleHandler();
        //設置handler的日誌級別爲ALL,輸出全部日誌。
        consoleHandler.setLevel(Level.ALL);

        //把handler添加到logger中
        logger.addHandler(consoleHandler);
        //logger也設置日誌級別爲ALL
        logger.setLevel(Level.ALL);

        //logger設置不使用父logger的handler,不然日誌會重複記錄。此處後面會講
        logger.setUseParentHandlers(false);
        //記錄severe級別信息
        logger.severe("severe信息");
        //記錄warning級別信息
        logger.warning("warning信息");
        logger.info("info信息");
        logger.config("config信息");
        logger.fine("fine信息");
        logger.finer("finer信息");
        logger.finest("finest信息");
    }

結果:
在這裏插入圖片描述
七個級別的日誌信息都輸出了。

Logger之間的父子關係:

JUL的Logger之間會存在父子關係,這種父子關係通過樹狀關係存儲。JUL在初始化時會創建一個頂層的RootLogger作爲所有Logger的父Logger。RootLogger作爲樹結構的根節點,Logger之間的關係通過樹路徑來關聯。Logger記錄器是用名稱作爲標誌的。子Logger和默認使用父Logger的Handler。

Logger的父子關係默認是通過名子的層級關係來確定的。層級關係用 . 號分開。
也可以通過手動設置父Logger。

@Test
    public void testLoggerParent(){
        //創建一個名稱爲aaa的logger
        Logger logger1 = Logger.getLogger("aaa");

        //創建一個名稱爲aaa.bbb的logger
        Logger logger2 = Logger.getLogger("aaa.bbb");

        //創建一個名稱爲aaa.bbb.ccc的logger
        Logger logger3 = Logger.getLogger("aaa.bbb.ccc");

        //此時logger3的父Logger是logger2, logger2的父logger是logger1

        //判斷logger3的父Logger是不是logger2
        System.out.println(logger3.getParent() == logger2);

        //判斷logger2的父logger是不是logger1
        System.out.println(logger2.getParent() == logger1);

        //logger1的父節點是頂級Logger RootLogger
        System.out.println("logger1的父logger是 " + logger1.getParent());

        //RootLogger的父Logger
        System.out.println("RootLogger的父Logger是 " + logger1.getParent().getParent());

        //手動設置父Logger
        logger3.setParent(logger1);
        //判斷設置是否成功
        System.out.println(logger3.getParent() == logger1);

    }

執行結果:
在這裏插入圖片描述
子Logger默認會使用父Logger的Handler:

@Test
    public void testUserParentHandler() throws IOException {
        //創建一個名爲aaa的logger
        Logger logger1 = Logger.getLogger("aaa");
        //創建一個名爲aaa.bbb的logger,父Logger是handler
        Logger logger2 = Logger.getLogger("aaa.bbb");

        //創建一個handler
        ConsoleHandler consoleHandler  = new ConsoleHandler();

        //把handler添加到logger1和logger2中。
        logger1.addHandler(consoleHandler);
        logger2.addHandler(consoleHandler);

        //使用logger進行日誌輸出

        //記錄severe級別信息
        logger2.severe("severe信息");
        //記錄warning級別信息
        logger2.warning("warning信息");
        logger2.info("info信息");
        logger2.config("config信息");
        logger2.fine("fine信息");
        logger2.finer("finer信息");
        logger2.finest("finest信息");

    }

結果:
在這裏插入圖片描述
分析:
每個級別的日誌信息輸出了三次,因爲logger2使用了父Logger logger1 ,父Logger的父Logger RootLogger、還有自身的handler共三個handler,所以日誌會輸出三倍。

使用logger2.setUseParentHandlers(false); 設置不使用父Logger的Handler。

結果:
在這裏插入圖片描述
只用了自身的handler。

使用FileHandler和SimpleFormatter

 @Test
    public void testFileHandler(){
        Logger logger = Logger.getLogger("juldemo.JULDemo");
        logger.setLevel(Level.ALL);
        try {
            //創建一個輸出到文件的handler,第一個參數是生成文件名的pattern,第二個參數是是否已追加的方式輸出到文件,默認false
            FileHandler fileHandler = new FileHandler("D:\\logs\\java%u.log",true);
            //創建一個SimpleFormatter,輸出格式
            SimpleFormatter formatter = new SimpleFormatter();
            //設置formatter
            fileHandler.setFormatter(formatter);
            //設置日誌級別
            fileHandler.setLevel(Level.ALL);
            //把handler添加到logger
            logger.addHandler(fileHandler);
            //設置不使用父Logger的handler
            logger.setUseParentHandlers(false);
            logger.severe("severe信息");
            //記錄warning級別信息
            logger.warning("warning信息");
            logger.info("info信息");
            logger.config("config信息");
            logger.fine("fine信息");
            logger.finer("finer信息");
            logger.finest("finest信息");
        } catch (IOException e) {
           e.printStackTrace();
        }

    }

輸出到文件:
在這裏插入圖片描述

配置文件詳解:

上面的使用方式都是使用硬編碼方式進行配置,現在介紹配置文件配置。

默認的配置文件:
$JAVA_HOME/jre/lib/logging.properties
默認配置:

#配置RootLogger的Handler,多個用逗號分隔。默認只有一個輸出到控制檯的handler
handlers= java.util.logging.ConsoleHandler

#配置RootLogger的日誌級別,默認是INFO
.level= INFO

#配置FileHandler
#配置FileHandler的生成文件路徑以及文件名的生成方式
java.util.logging.FileHandler.pattern = %h/java%u.log
#默認一個文件最多50000條日誌記錄
java.util.logging.FileHandler.limit = 50000
#默認生成一個文件
java.util.logging.FileHandler.count = 1
#默認使用XMLFormatter格式器
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter

#ConsoleHandler的日誌級別默認是INFO
java.util.logging.ConsoleHandler.level = INFO
#ConsoleHandler的默認格式化器時SimpleFormatter
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

我們可以使用自定義的文件或者修改默認配置文件進行配置。


#配置RootLogger的Handler,有java.util.logging.ConsoleHandler,java.util.logging.FileHandler
handlers= java.util.logging.ConsoleHandler,java.util.logging.FileHandler

#配置RootLogger的日誌級別ALL
.level= ALL

java.util.logging.FileHandler.pattern = D:/logs/java%u.log
#默認一個文件最多50000條日誌記錄
java.util.logging.FileHandler.limit = 50000
#設置FileHandle的日誌級別爲ALL
java.util.logging.FileHandler.level= ALL

#配置生成一個文件
java.util.logging.FileHandler.count = 1
#配置使用SimpleFormatter格式器
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
#配置追加模式
java.util.logging.FileHandler.append=true

#ConsoleHandler的日誌級別默認是INFO
java.util.logging.ConsoleHandler.level = ALL
#ConsoleHandler的默認格式化器時SimpleFormatter
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter



#設置日誌格式
java.util.logging.SimpleFormatter.format= %1$tc %2$s%n%4$s: %5$s%6$s%n



使用:

 @Test
    public void testCustomConfig(){
        LogManager logManager = LogManager.getLogManager();
        try {
            logManager.readConfiguration(this.getClass().getClassLoader().getResourceAsStream("logging.properties"));
            Logger logger = Logger.getLogger("juldemo.JULDemo");
            logger.severe("severe信息");
            //記錄warning級別信息
            logger.warning("warning信息");
            logger.info("info信息");
            logger.config("config信息");
            logger.fine("fine信息");
            logger.finer("finer信息");
            logger.finest("finest信息");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

在這裏插入圖片描述

結果:
在這裏插入圖片描述
並且生成了日誌文件,這裏就不貼了。

如果不想用logmanager加載指定配置文件的話,就直接修改$JAVA_HOME/jre/lib/logging.properties文件也行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章