Extend the appender

我替老婆做了某個遊戲外掛,然後我希望能把log內容顯示在畫面上,例如:

我想透過log4j去通知畫面更新而不是再另開一個api;本篇文章主要告訴大家extend log4j appender的方法去達到這個目的。

原先我的Subject是目前工作的狀態,負責通知的是執行工作的controller;而Observer則是UI,實作以下介面,Subject有變動會通知它:

public interface IStateChangedListener {
	void update(Object[] messages);
}
 
public class MessageTable extends JTable implements IStateChangedListener {
	// skip
}

接著新增一個名為NotificationAppender的Log4j Appender,要做以下事情:

  1. Extend AppenderSkeleton。
  2. 負責Observer的註冊與通知。
public class NotificationAppender extends AppenderSkeleton {
 
	protected static List<IStateChangedListener> mStateChangedListenerList = new ArrayList<>();
 
	@Override
	protected void append(LoggingEvent arg0) {
		notify(arg0.getLevel().toString(), arg0.getMessage().toString());
	}
 
	public static 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 static 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.MESSAGETABBLE.Threshold=DEBUG

extend的appender如果需要特別的設定,例如:

log4j.appender.MESSAGETABBLE.DumpConsole=true

在appender中,可以加入set code去達到此需求:

	public void setDumpConsole(boolean value){
		System.out.println(value);
	}