雖然開源社區有不少優秀的日誌框架,但咱們學習標準的java日誌框架是爲了更好的理解其餘框架啊(近期項目要用ELK)java
看本身之前寫的Log4J簡直不忍直視啊啊啊啊,那時還感受自我良好網絡
咱們都試過在代碼中插入System.out.println方法來進行調試吧,當找出問題根源後就把插入的print語句刪除,若又出現問題則需再次插入這些語句,如此反覆。那麼日誌API就是爲了解決這個問題而設計的,使用日誌的優點:框架
java有標準的日誌系統,在java.util.logging包下。由於它不太好用,就出現了各類補充的日誌框架,其實我看着也還行,可以應付個人平常使用了ide
看不懂不要緊,碼入下面的程序就能夠看到日誌記錄的狀況了學習
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
記錄器是用來 "記錄"、定位日誌記錄的,通常咱們不想把全部的日誌都記錄到一個全局記錄器上,那麼咱們就能夠自定義一個記錄器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"); } }
日誌的記錄器有相似於
包名繼承
的層次結構,父記錄器設置了日誌級別,那麼子記錄器就會繼承這個級別,因此日誌框架的記錄器命名都以類名限定設計
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
處理器是用於處理記錄的(也有日誌級別),記錄器有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,取消使用父處理器
記錄器,處理器只能根據日誌級別來過濾,而過濾器則更加自由多樣化。咱們須要實現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
格式化器顧名思義是用來格式化記錄的,看須要生成什麼樣格式的記錄,個人話就在日誌前加點東西就行了。也是須要實現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
補丁
使其兼容 JCL 的接口,看着好複雜日誌門面 | 組件實現 |
---|---|
JCL、slf4j | log4j、log4j、logback、JUL |
使用框架需選一個日誌門面,而後再選擇個門面的實現,不選擇實現的話默認使用 java 的標準庫
筆者還沒在項目中實際用過日誌框架,體會到的很少,目前只知道 JUL 的配置管理器實屬敗筆~ 。等筆者搭完此次項目用到的ELK以後再慢慢體會把