作為一個程序設計人員,我們深知日志的重要性,對於日志的監控,我們通常不外乎采用以下兩種方式:日志文件方式和后台打印方式,常規情況下,這兩種日志監控方式完全可以滿足我們對日志監控的需要。但是,當我們用Swing進行前台開發時,常常想能不能把后台服務運行日志實時地顯示在前台窗口中,或者只是將某類我們比較關心的日志信息(譬如異常日志等)實時動態地顯示在前台窗口中,這樣方便我們及時監控和處理。這個設想我們稱之為“后台日志信息前台監控器”。
設計這樣一個“后台日志信息前台監控器”,有兩個難點,第一個是,當我們捕捉到后台日志信息時,如何將日志信息傳遞給前台監控器,實現實時傳遞。第二個是,當前台監控器收到日志信息后,如何實時顯示。總結起來,就是一個“實時”的問題:實時傳遞和顯示日志信息。
對於如何將后台日志信息實時傳遞到前台進行監控顯示,我們采用了自定義事件機制,通過事件觸發機制,監控日志內容的變更。思路是這樣的,在LogMonitor類中,用StringBuilder實例化一個變量logs,用來存儲日志信息,通過addLog和clearLogs方法來添加和刪除日志信息,並在這兩個方法體內監控日志信息的變更,當日志信息發生變更時,觸發事件變更事件,最后在此事件內實時刷新前台監控區域。
- 日志信息變更事件類
/** * Description:日志信息事件<br> * Copyright: Copyright (c) 2015<br> * Company: 河南電力科學研究院智能電網所<br> * * @author shangbingbing 2015-01-01編寫 * @version 1.0 */ public class LogChangedEvent extends java.util.EventObject { private static final long serialVersionUID = 7573194493258326711L; public LogChangedEvent(Object source) { super(source); } }
- 日志信息變更監聽器類
/** * Description:日志信息變更監聽器<br> * Copyright: Copyright (c) 2015<br> * Company: 河南電力科學研究院智能電網所<br> * * @author shangbingbing 2015-01-01編寫 * @version 1.0 */ public class LogChangedListener implements java.util.EventListener { public void EventActivated(LogChangedEvent me) { } }
- 日志信息監聽器類
/** * Description:日志信息監聽器類<br> * Copyright: Copyright (c) 2015<br> * Company: 河南電力科學研究院智能電網所<br> * @author shangbingbing 2015-01-01編寫 * @version 1.0 */ public class LogMonitor implements Serializable { private static final long serialVersionUID = 1L; private static StringBuilder logs = new StringBuilder(); /** * 獲取日志信息 * @return */ public static StringBuilder getLogs() { return logs; } /** * 新增日志信息 * @param log */ public static void addLog(String log) { if(StringUtils.isBlank(log)) { logs.append("\r\n"); } else { log = String.format("%s %s\r\n", new Date().toString(), log); logs.append(log); } activateLogChangedEvent(); } /** * 清除日志信息 */ public static void clearLogs() { logs = new StringBuilder(); activateLogChangedEvent(); } private static Vector<LogChangedListener> vectorListeners = new Vector<LogChangedListener>(); public static synchronized void addLogChangedListener(LogChangedListener listener) { vectorListeners.addElement(listener); } public static synchronized void removeLogChangedListener(LogChangedListener listener) { vectorListeners.removeElement(listener); } public static void activateLogChangedEvent() { Vector<LogChangedListener> tempVector = null; LogChangedEvent e = new LogChangedEvent(LogMonitor.class); synchronized(LogMonitor.class) { tempVector = (Vector<LogChangedListener>)vectorListeners.clone(); for(int i=0;i<tempVector.size();i++) { LogChangedListener listener = tempVector.elementAt(i); listener.EventActivated(e); } } } }
- 日志信息前台監控窗口
import javax.swing.JDialog; import javax.swing.UIManager; import javax.swing.GroupLayout; import javax.swing.GroupLayout.Alignment; import javax.swing.JScrollPane; import javax.swing.JTextArea; /** * Description:日志信息監聽窗口<br> * Copyright: Copyright (c) 2015<br> * Company: 河南電力科學研究院智能電網所<br> * @author shangbingbing 2015-01-01編寫 * @version 1.0 */ public class DialogLogMonitor extends JDialog { private static final long serialVersionUID = 1L; private JTextArea txtLogInfo; public static void main(String[] args) { try { //設置系統觀感器 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); DialogLogMonitor dialog = new DialogLogMonitor(); dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); dialog.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } /** * 日志信息變更監聽處理(關鍵點) */ private void init() { LogMonitor.addLogChangedListener(new LogChangedListener() { @Override public void EventActivated(LogChangedEvent me) { txtLogInfo.setText(LogMonitor.getLogs().toString()); txtLogInfo.setCaretPosition(txtLogInfo.getText().length()); txtLogInfo.paintImmediately(txtLogInfo.getBounds()); } }); } public DialogLogMonitor() { setResizable(false); setTitle("\u540E\u53F0\u65E5\u5FD7\u76D1\u63A7\u5668"); setBounds(100, 100, 439, 274); JScrollPane scrollPane = new JScrollPane(); GroupLayout groupLayout = new GroupLayout(getContentPane()); groupLayout.setHorizontalGroup( groupLayout.createParallelGroup(Alignment.LEADING) .addGroup(groupLayout.createSequentialGroup() .addContainerGap() .addComponent(scrollPane) .addContainerGap()) ); groupLayout.setVerticalGroup( groupLayout.createParallelGroup(Alignment.LEADING) .addGroup(groupLayout.createSequentialGroup() .addContainerGap() .addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, 230, Short.MAX_VALUE) .addContainerGap()) ); txtLogInfo = new JTextArea(); txtLogInfo.setEditable(false); txtLogInfo.setLineWrap(true); scrollPane.setViewportView(txtLogInfo); getContentPane().setLayout(groupLayout); this.init(); } }
- 后台日志模擬生成窗口
我們設計了一個后台日志模擬生成窗口,來測試日志信息的監控效果。窗口源代碼如下:
import javax.swing.JDialog; import javax.swing.UIManager; import javax.swing.GroupLayout; import javax.swing.GroupLayout.Alignment; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JLabel; import javax.swing.LayoutStyle.ComponentPlacement; import javax.swing.JButton; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; /** * Description:后台日志信息模擬生成窗口<br> * Copyright: Copyright (c) 2015<br> * Company: 河南電力科學研究院智能電網所<br> * @author shangbingbing 2015-01-01編寫 * @version 1.0 */ public class DialogLogGenerator extends JDialog { private static final long serialVersionUID = 1L; private JTextArea txtLogInfo; public static void main(String[] args) { try { //設置系統觀感器 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); DialogLogGenerator dialog = new DialogLogGenerator(); dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); dialog.setVisible(true); DialogLogMonitor dialogLogMonitor = new DialogLogMonitor(); dialogLogMonitor.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); dialogLogMonitor.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } private void generatorLog() { LogMonitor.addLog(this.txtLogInfo.getText()); this.txtLogInfo.setText(""); } public DialogLogGenerator() { setResizable(false); setTitle("\u540E\u53F0\u65E5\u5FD7\u6A21\u62DF\u751F\u6210\u6D4B\u8BD5\u7A97\u53E3"); setBounds(100, 100, 439, 278); JLabel lblNewLabel = new JLabel("\u8BF7\u8F93\u5165\u6A21\u62DF\u65E5\u5FD7\u4FE1\u606F\uFF1A"); JScrollPane scrollPane = new JScrollPane(); JButton btnCreateLog = new JButton("\u4F20\u9012\u6A21\u62DF\u65E5\u5FD7"); btnCreateLog.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { generatorLog(); } }); GroupLayout groupLayout = new GroupLayout(getContentPane()); groupLayout.setHorizontalGroup( groupLayout.createParallelGroup(Alignment.LEADING) .addGroup(groupLayout.createSequentialGroup() .addContainerGap() .addGroup(groupLayout.createParallelGroup(Alignment.LEADING) .addGroup(groupLayout.createSequentialGroup() .addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, 413, Short.MAX_VALUE) .addContainerGap()) .addGroup(groupLayout.createSequentialGroup() .addGroup(groupLayout.createParallelGroup(Alignment.LEADING) .addComponent(btnCreateLog, GroupLayout.PREFERRED_SIZE, 131, GroupLayout.PREFERRED_SIZE) .addComponent(lblNewLabel, GroupLayout.PREFERRED_SIZE, 170, GroupLayout.PREFERRED_SIZE)) .addGap(253)))) ); groupLayout.setVerticalGroup( groupLayout.createParallelGroup(Alignment.LEADING) .addGroup(groupLayout.createSequentialGroup() .addGap(18) .addComponent(lblNewLabel) .addPreferredGap(ComponentPlacement.UNRELATED) .addComponent(scrollPane, GroupLayout.PREFERRED_SIZE, 131, GroupLayout.PREFERRED_SIZE) .addGap(18) .addComponent(btnCreateLog, GroupLayout.PREFERRED_SIZE, 41, GroupLayout.PREFERRED_SIZE) .addContainerGap(17, Short.MAX_VALUE)) ); txtLogInfo = new JTextArea(); scrollPane.setViewportView(txtLogInfo); getContentPane().setLayout(groupLayout); } }
- 運行測試
啟動運行DialogLogGenerator窗口,會同時顯示DialogLogMonitor窗口,在日志模擬窗口輸入一些日志信息,然后點擊“傳遞模擬日志”按鈕,你將可以在DialogLogMonitor監控區域看到模擬的日志信息。運行效果圖如下所示:
運行程序打包下載 hnepri-log-monitor.jar
作者:商兵兵
單位:河南省電力科學研究院智能電網所
QQ:52190634


