作为一个程序设计人员,我们深知日志的重要性,对于日志的监控,我们通常不外乎采用以下两种方式:日志文件方式和后台打印方式,常规情况下,这两种日志监控方式完全可以满足我们对日志监控的需要。但是,当我们用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