Java的標準日誌

雖然開源社區有不少優秀的日誌框架,但咱們學習標準的java日誌框架是爲了更好的理解其餘框架啊(近期項目要用ELK)java

看本身之前寫的Log4J簡直不忍直視啊啊啊啊,那時還感受自我良好網絡



1. 爲何要使用日誌

咱們都試過在代碼中插入System.out.println方法來進行調試吧,當找出問題根源後就把插入的print語句刪除,若又出現問題則需再次插入這些語句,如此反覆。那麼日誌API就是爲了解決這個問題而設計的,使用日誌的優點:框架

  • 可隨時開閉日誌記錄,還能分級別篩選日誌,而且保留日誌代碼開銷很小
  • 日誌可簡單地被定向到控制檯顯示,文件保存,或者網絡傳輸
  • 日誌可格式化其記錄的格式
  • 日誌可由配置文件控制
  • 日誌利於往後錯誤的定位






2. Logger

java有標準的日誌系統,在java.util.logging包下。由於它不太好用,就出現了各類補充的日誌框架,其實我看着也還行,可以應付個人平常使用了ide


2.1 示例

看不懂不要緊,碼入下面的程序就能夠看到日誌記錄的狀況了學習

public class loggerTest {
    public static void main(String[] args) {
        
        // 1. 得到一個全局的日誌記錄器
        Logger global = Logger.getGlobal();
        
        // 2. 日誌有七個級別,從高到低分別是:Sever、Warning、Info、Config、Fine、Finer、Finest
        // 	  默認級別爲INFO,意思只輸出前三個級別的記錄
        global.info("INFO MSG");
        global.warning("WARNING MSG");
        global.severe("SERVE MSG");
        
         // 3. 可經過setLevel來設置日誌級別,來限制其餘級別的記錄
        global.setLevel(Level.WARNING);
    }
}

// 控制檯輸出
// 七月 23, 2021 8:57:17 下午 logging.loggerTest main
// 信息: INFO MSG
// 七月 23, 2021 8:57:17 下午 logging.loggerTest main
// 警告: WARNING MSG
// 七月 23, 2021 8:57:17 下午 logging.loggerTest main
// 嚴重: SERVE MSG


2.2 日誌的記錄器

記錄器是用來 "記錄"、定位日誌記錄的,通常咱們不想把全部的日誌都記錄到一個全局記錄器上,那麼咱們就能夠自定義一個記錄器this


public class loggerTest {

    // 未被任何變量引用的日誌記錄器可能被垃圾回收掉,因此採用了靜態變量的方式
    private static  final Logger myLogger = Logger.getLogger("com.howl.logger.loggerTest");;

    public static void main(String[] args) {
         myLogger.info("this is my logger msg");
    }
}

日誌的記錄器有相似於包名繼承的層次結構,父記錄器設置了日誌級別,那麼子記錄器就會繼承這個級別,因此日誌框架的記錄器命名都以類名限定設計



2.3 日誌配置

java有個叫日誌管理器的東西專門來管配置的,java9的配置文件是在 jre/conf/logging.properties。日誌管理器在虛擬機啓動時就初始化,就是在main方法執行以前調試


咱們能夠在啓動項目時就指定日誌的配置文件:java -Djava.util.logging.config.file=新文件名日誌

也可在項目運行時用System.setProperty("java.util.logging.config.file", file)指定配置文件,並LogManager.getLogManager().readConfiguration()從新初始化日誌管理器生效配置(食用配置文件形式很差,其餘日誌框架的配置在項目根目錄,會自動讀取的)code



2.4 日誌的處理器

處理器是用於處理記錄的(也有日誌級別),記錄器有ConsoleHandler、FileHandler、SocketHandler。默認狀況下記錄器將記錄發到ConsoleHandler而後輸出,如想輸出到其餘地方就添加其餘的處理器。具體流程的話,就是記錄器將記錄發給本身的處理器和父記錄器的處理器,所有記錄器的最終祖先是名爲 "" 的一個記錄器,它有一個ConsoleHandler,因此默認的日誌記錄都輸出到控制檯


public class loggerTest {

    // 靜態變量放垃圾回收
    private static  final Logger myLogger = Logger.getLogger("com.howl.logger.loggerTest");;

    public static void main(String[] args) throws IOException {

        // 文件、控制檯處理器
        FileHandler fileHandler = new FileHandler();
        ConsoleHandler consoleHandler = new ConsoleHandler();
        
        myLogger.addHandler(consoleHandler);	// 這條語句在控制檯輸出了兩次
        myLogger.addHandler(fileHandler);

        myLogger.info("add two handler");
    }
}

// 控制檯輸出
// 七月 23, 2021 9:31:26 下午 logging.loggerTest main
// 信息: add two handler
// 七月 23, 2021 9:31:26 下午 logging.loggerTest main
// 信息: add two handler

怎麼會有兩條記錄?

  • fileHander是輸出文件的(不在控制檯輸出),日誌文件默認保存在用戶目錄下的javaN.log中,其中N是惟一編號,默認格式爲XML

  • 上面說的myLogger發給本身處理器consoleHandler輸出,也會發給父處理器輸出,因此有兩條,可配置userParentHandlers = false,取消使用父處理器



2.5 日誌的過濾器

記錄器,處理器只能根據日誌級別來過濾,而過濾器則更加自由多樣化。咱們須要實現Filter接口(注意是Logger下的接口)而後將其交給記錄器(是記錄器啊,下面標題2.6的纔是交給處理器)


public class loggerTest {

    private static  final Logger myLogger = Logger.getLogger("com.howl.logger.loggerTest");;

    public static void main(String[] args) throws IOException {

        // 過濾器
        Filter filter = new Filter() {
            @Override
            public boolean isLoggable(LogRecord record) {
                return record.getMessage().contains("HAHA");    // 記錄包含了HAHA就不過濾
            }
        };

        myLogger.setFilter(filter);
        myLogger.info("add two handler");
        myLogger.info("i am HAHA");
    }
}

// 控制檯輸出
// 七月 23, 2021 9:43:27 下午 logging.loggerTest main
// 信息: i am HAHA


2.6 日誌的格式化器

格式化器顧名思義是用來格式化記錄的,看須要生成什麼樣格式的記錄,個人話就在日誌前加點東西就行了。也是須要實現format接口的,固然記錄的格式化操做是交給處理器的


public class loggerTest {

    private static  final Logger myLogger = Logger.getLogger("com.howl.logger.loggerTest");;

    public static void main(String[] args) throws IOException {

        // 格式化器
        Formatter formatter = new Formatter() {
            @Override
            public String format(LogRecord record) {
                return "這裏是格式化器: "+ record.getMessage() + "\n\n";
            }
        };

        ConsoleHandler consoleHandler = new ConsoleHandler();
        consoleHandler.setFormatter(formatter);

        myLogger.addHandler(consoleHandler);
        myLogger.info("i am HAHA");
    }
}

// 控制檯輸出
// 這裏是格式化器: i am HAHA
// 
// 七月 23, 2021 9:52:58 下午 logging.loggerTest main
// 信息: i am HAHA






3. java日誌的發展史

  • Apache 的 log4j 日誌框架最先出現(可用配置文件管理日誌,並動態加載)
  • java1.4 後面才添加的標準日誌庫 java.util.logging(JUL)
  • Apache 推出日誌門面Apache Commons Logging(JCL,提供了一套日誌接口,兼容上面兩者)
  • 再而後 JCL 的做者弄了個新的日誌門面 slf4j,並提供了其組件實現 logback
  • 最後 Apache 重寫log4j,推出 log4j2
  • 由於 slf4j 門面後面纔出現,因此推出了各類補丁使其兼容 JCL 的接口,看着好複雜

日誌門面 組件實現
JCL、slf4j log4j、log4j、logback、JUL

使用框架需選一個日誌門面,而後再選擇個門面的實現,不選擇實現的話默認使用 java 的標準庫







4. 項目中爲何不使用JUL

筆者還沒在項目中實際用過日誌框架,體會到的很少,目前只知道 JUL 的配置管理器實屬敗筆~ 。等筆者搭完此次項目用到的ELK以後再慢慢體會把

相關文章
相關標籤/搜索