Problem
許多third-party api都是使用Java Util Logging(JUL)來Log資訊,但你可能會遇到幾點問題:
- Log格式與Log4j或Slf4j不相同,看了礙眼。
- 我平常不需要JUL的訊息,但發生問題時就需要了。怎樣可以方便設定?
- 不要讓我學兩份Config的方式。好嗎?
也許還有種種原因,我只是希望能有一個統一輸出界面。還好有好心人士做了Bridge,目前看到有Log4j的JULBridgeLogManager與SLF4J的SLF4JBridgeHandler。這篇文章中挑SLF4JBridgeHandler做介紹。
How to use?
Config
直接看我的cofng。首先我將JUL的所有Log level打開。假如你沒這麼做,JUL預設Level為Info,你只有在Info Level以上的才有辦法將內容導向SLF4J;再來就是針對你要的Package做設定。我選用Expect4j做範例
log4j.rootCategory=WARN, CONSOLE .level= ALL handlers= java.util.logging.ConsoleHandler java.util.logging.ConsoleHandler.level= ALL log4j.additivity.expect4j=false log4j.logger.expect4j=TRACE, CONSOLE # CONSOLE is set to be a ConsoleAppender using a PatternLayout. log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.Threshold=TRACE log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=%d{dd/MM HH:mm:ss} %5p[%t] %X{usedheap}(%F:%M:%L) - %m%n
這是JUL與Log4j之對應,可以根據這個設定你的config。(參考Javadoc for SLF4JBridgeHandler)
FINEST -> TRACE FINER -> DEBUG FINE -> DEBUG INFO -> INFO WARNING -> WARN SEVERE -> ERROR
Load Config
除了用檔案設定,當然你也可以透過寫Code的方式去設定,但我比較偏好透過檔案。提供給你兩種方法: 1. 從Classpath讀取設定;2. 從File path讀取設定。我將檔案放在source folder test目錄下。
Load from ClassPath
private void readLog4jConfigFromClasspath(){ InputStream is = this.getClass().getResourceAsStream("/log4j.properties"); try { LogManager.getLogManager().readConfiguration(is); } catch(Exception e) { throw new RuntimeException(e); } finally { Cleaner.close(is); } }
註: Cleaner是自製類別,負責關閉串流。
Load from FilePath
這是透過java.util.logging.config.file的設定,你也可以藉由傳入-Djava.util.logging.config.file參數。
private void readLog4jConfigFromFilePath(){ Properties prop = System.getProperties(); prop.setProperty("java.util.logging.config.file", "test/log4j.properties"); try { LogManager.getLogManager().readConfiguration(); } catch(Exception e) { throw new RuntimeException(e); } }
Bridging
先閱讀一下範例程式:
@Test public void test() throws Exception { readLog4jConfigFromClasspath(); //readLog4jConfigFromFilePath(); SLF4JBridgeHandler.removeHandlersForRootLogger(); SLF4JBridgeHandler.install(); Expect4j.log.finest("test1"); Expect4j.log.info("test2"); Expect4j.log.fine("test3"); }
最重要的兩個method是removeHandlersForRootLogger與install。以下圖結果來說,假如你沒呼叫removeHandlersForRootLogger,原本JUL的訊息也會被Log,如圖片中紅色的字。install就是安裝bridge的功能,當然也有uninstall去移除拉!另外紅色的有三筆,黑色的只有兩筆,原因是finest為TRACE Level,設定為Debug並不會顯示。
友藏內心獨白: 趁著修改測試程式,順便學習新招。
留言
張貼留言