差異處
這裏顯示兩個版本的差異處。
java:log4j:config_watchdog [2013/03/13 19:23] tony |
java:log4j:config_watchdog [2023/06/25 09:48] |
||
---|---|---|---|
行 1: | 行 1: | ||
- | {{tag>java log4j}} | ||
- | ====== FileWatchDog for Configuration ====== | ||
- | ===== Problem ===== | ||
- | 在軟體開發與debug的時候,為了幫助了解程式做到什麼地方、發生問題在哪或狀態如何,會使用log去記錄重要的執行過程。但每次修改完log4j property file為了讓它生效,會重新啟動應用程式讓它reload,但這樣不是很煩嗎?為了解決這樣問題,我們可以透過Log4J提供的PropertyWatchdog去polling config是否有做過修改,使用也只要透過PropertyConfigurator的configureAndWatch就可以了,預設是60秒check一次。 | ||
- | <code java> | ||
- | org.apache.log4j.PropertyConfigurator.configureAndWatch(aLogPropertyFilePath); | ||
- | </code> | ||
- | 但如果你是使用1.2版本或之前的,可能會遇到和我一樣的情況。在我將package名稱如以下更動後(增加.internal),就收到了**log4j:ERROR Attempted to append to closed appender named**的訊息,還狂跳不停。這是怎麼一回事? | ||
- | <code> | ||
- | log4j.additivity.org.tonylin.facebook=false | ||
- | log4j.logger.org.tonylin.facebook=INFO, CONSOLE, LOGFILE | ||
- | -> | ||
- | log4j.additivity.org.tonylin.facebook.internal=false | ||
- | log4j.logger.org.tonylin.facebook.internal=INFO, CONSOLE, LOGFILE | ||
- | </code> | ||
- | ===== How to resolve? ===== | ||
- | 我先告訴大家我最後的解法,細部內容待我最後說明,有興趣的再繼續看。一看訊息就可以猜應該是狀態不正常造成的,在trace code後發現原先在每次檔案有改變後,也僅做了下面的動作。 | ||
- | <code> | ||
- | new PropertyConfigurator().doConfigure(filename, LogManager.getLoggerRepository()) | ||
- | </code> | ||
- | 於是我直接寫了一個class去繼承Log4j既有的FileWatchdog,並於發生改變時,初始化之前做Configuration的reset,這個問題就這樣解決了。 | ||
- | <code java> | ||
- | public class Log4jPropertyWatcher extends FileWatchdog { | ||
- | private static Logger mLogger = LoggerFactory.getLogger(Log4jPropertyWatcher.class); | ||
- | private static long mDefaultInterval = 1000l; | ||
- | |||
- | Log4jPropertyWatcher(String filename){ | ||
- | super(filename); | ||
- | } | ||
- | |||
- | @Override | ||
- | protected void doOnChange() { | ||
- | mLogger.debug("Log4j config is changed."); | ||
- | LogManager.getLoggerRepository().resetConfiguration(); | ||
- | new PropertyConfigurator().doConfigure(filename, LogManager.getLoggerRepository()); | ||
- | } | ||
- | |||
- | public static void configureAndWatch(String filename){ | ||
- | Log4jPropertyWatcher fileWatcher = new Log4jPropertyWatcher(filename); | ||
- | fileWatcher.setDelay(mDefaultInterval); | ||
- | fileWatcher.start(); | ||
- | } | ||
- | |||
- | public static void setWatchInterval(long aInterval){ | ||
- | mDefaultInterval = aInterval; | ||
- | } | ||
- | } | ||
- | </code> | ||
- | 那Root Cuase呢? 錯誤訊息是由AppenderSkeleton丟出的,原因是因為它發現它已經被執行過close了。close也許是關閉檔案或串流等等動作,根據Append實做決定,但重點的確是被某人給關閉了。 | ||
- | <code java> | ||
- | public synchronized void doAppend(LoggingEvent event) | ||
- | { | ||
- | if (this.closed) { | ||
- | LogLog.error("Attempted to append to closed appender named [" + this.name + "]."); | ||
- | return; | ||
- | } | ||
- | </code> | ||
- | 於是重頭開始trace PropertyConfigurator的parseCategory,發現它會將每一個logger執行removeAllAppenders()的動作。 | ||
- | |||
- | ===== Reference ===== | ||
- | * [[http://blog.csdn.net/bxyz1203/article/details/7645185|log4j:ERROR Attempted to append to closed appender named的問題]] | ||
- | * [[http://aofengblog.blog.163.com/blog/static/631702120114295537239/|Log4j的架構]] | ||
- | * [[https://issues.apache.org/bugzilla/show_bug.cgi?id=17531|PropertyConfigurator.configureAndWatch() Bug]] | ||
- | |||
- | ===== ===== | ||
- | ---- | ||
- | \\ | ||
- | ~~DISQUS~~ |