這是本文件的舊版!
Extend the appender (Working)
Problem
我替老婆做了某個遊戲外掛,然後我希望能把log內容顯示在畫面上,例如:
我想透過log4j去通知畫面更新而不是再另開一個api;本篇文章主要告訴大家extend log4j appender的方法去達到這個目的。
How to?
原先我的Subject是目前工作的狀態,負責通知的是工作的controller;而Observer則是UI,實作以下介面,Subject有變動會通知它:
public interface IStateChangedListener { void update(Object[] messages); } public class MessageTable extends JTable implements IStateChangedListener { // skip }要達到我們目的,會新增一個Log4j Appender,身負Subject的使命。我們要做以下事情:
- Extend AppenderSkeleton。
- 負責Observer的註冊與通知。
public class NotificationAppender extends AppenderSkeleton { protected static List<IStateChangedListener> mStateChangedListenerList = new ArrayList<>(); private static NotificationAppender mInstance = new NotificationAppender(); public static NotificationAppender getInstance(){ return mInstance; } @Override protected void append(LoggingEvent arg0) { notify(arg0.getLevel().toString(), arg0.getMessage().toString()); } public void addListener(IStateChangedListener aListener){ mStateChangedListenerList.add(aListener); } private static String getTimeString(Date aDate){ DateFormat df = new SimpleDateFormat("HH:mm:ss"); return df.format(aDate); } protected void notify(String aState, String aMessage){ Date now = new Date(); for( IStateChangedListener listener : mStateChangedListenerList){ listener.update(new Object[]{ getTimeString(now), aState, aMessage }); } } @Override public void close() { } @Override public boolean requiresLayout() { return false; } }在config的部分如下,我針對某兩個類別將訊息送至MessageTable UI:
log4j.additivity.org.tonylin.bot.fantasycity.RunBotJob=false log4j.logger.org.tonylin.bot.fantasycity.RunBotJob=DEBUG, CONSOLE, LOGFILE, MESSAGETABBLE log4j.additivity.org.tonylin.bot.fantasycity.BotUtils=false log4j.logger.org.tonylin.bot.fantasycity.BotUtils=DEBUG, CONSOLE, LOGFILE, MESSAGETABBLE # MessageTable Logger log4j.appender.MESSAGETABBLE=org.tonylin.bot.common.NotificationAppender log4j.appender.CONSOLE.Threshold=DEBUG