如何自建appender扩展Log4j框架

本文介绍如何在应用中自建日志模块
author: ZJ 07-11-3
Blog: [url]http://zhangjunhd.blog.51cto.com/[/url]
  1 log4j 概述
log4j 环境包括三个主要组件:
logger (日志记录器):控制要启用或禁用哪些日志记录语句。可以对日志记录器指定如下级别: ALL DEBUG INFO WARN ERROR , FATAL
layout (布局):根据用户的愿望格式化日志记录请求。
appender :向目的地发送格式化的输出。
2 .理解 appender
log4j 框架允许向任何日志记录器附加多个 appender 。可以在任何时候对某个日子记录器添加(或删除) appender 。附随 log4j 分发的 appender 有多个,包括:
ConsoleAppender;FileAppender;SMTPAppender ;JDBCAppender;JMSAppender;NTEventLogAppender;SyslogAppender
也可以创建自己的自定义 appender
3 .本工程设计的目标
通过自建 appender 类,来实现:
[1] 在控制台输出日志;
[2] log 文件输出日志;
[3] 在应用程序中建立日志模块(在 UI 层表现为建立一个日志面板),输出日志;
[4] 对于不同包路径下的日志独立输出(在 UI 层表现为分不同的面板输出)。
4. 预备知识
你可以在下面 2 篇文章中找到 Log4j 的相关基础介绍。
Log4j配置说明
Log4j使用实例
5 .项目文件分布与效果
文件分布如图一所示。我们对于 com.log.one 包下的所有 java 文件中的日志信息输出到 log one 模块(图二);对于 com.log.two 包下的所有 java 文件中的日志信息输出到 log two 模块(图四)。本文只象征性的建立了两个测试文件,分别放在两个包下。
com.log.one.LogTestOne.java
public class LogTestOne {
    private final static Logger log = Logger.getLogger(LogTestOne. class );
    public void doLog(){
       log .debug( "TestOne debug" );
       log .info( "TestOne info" );
       log .warn( "TestOne warn" );
       log .error( "TestOne error" );
       log .fatal( "TestOne fatal" );
    }
}
 
com.log.two.LogTestTwo.java
public class LogTestTwo {
    private final static Logger log = Logger.getLogger(LogTestTwo. class );
    public void doLog() {
       log .debug( "TestTwo debug" );
       log .info( "TestTwo info" );
       log .warn( "TestTwo warn" );
       log .error( "TestTwo error" );
       log .fatal( "TestTwo fatal" );
    }
}
 
图一
 
对于应用程序中的日志模块,提供一些 UI 层的基本操作,包括清空(图二,图四);变灰(图三);复制到粘贴板。
The Main Text 象征性的表示主应用程序的所有操作。
图二
 
图三
 
图四
 
同时在控制台输出所有日志信息。(图五)
图五
 
    同时在文本文件中输出所有日志信息。(图六)
图六
6 log4j.xml
本项目使用如下日志配置文件,将其放在项目的 classpath 下。
<! DOCTYPE log4j:configuration SYSTEM "log4j.dtd" >
< log4j:configuration xmlns:log4j = "http://jakarta.apache.org/log4j/" debug = "false" >  
   <!-- =================== -->
   <!-- Appenders           -->
   <!-- =================== -->
   < appender name = "CONSOLE" class = "org.apache.log4j.ConsoleAppender" >
       < errorHandler class = "org.apache.log4j.helpers.OnlyOnceErrorHandler" />
      < param name = "Target" value = "System.out" />
      < param name = "Threshold" value = "DEBUG" />
      < layout class = "org.apache.log4j.PatternLayout" >
         <!-- The default pattern: Date Priority [Category] Message\n -->
         < param name = "ConversionPattern" value = "%-5p %l%m%n" />
      </ layout >
   </ appender >
 
   < appender name = "FILE" class = "org.apache.log4j.RollingFileAppender" >
     < errorHandler class = "org.apache.log4j.helpers.OnlyOnceErrorHandler" />
     < param name = "File" value = "logui.log" />
     < param name = "Threshold" value = "INFO" />
     < param name = "Append" value = "false" />
     < param name = "MaxFileSize" value = "5000KB" />
     < param name = "MaxBackupIndex" value = "50" />
     < layout class = "org.apache.log4j.PatternLayout" >
       < param name = "ConversionPattern" value = "%d %-5p [%c{1}] %m%n" />
     </ layout >    
   </ appender >
     
   < appender name = "ONE" class = "com.log.utils.LogOneAppender" >
      < errorHandler class = "org.apache.log4j.helpers.OnlyOnceErrorHandler" />
   </ appender >
  
    < appender name = "TWO" class = "com.log.utils.LogTwoAppender" >
      < errorHandler class = "org.apache.log4j.helpers.OnlyOnceErrorHandler" />
   </ appender >
  
   <!-- =============== -->
   <!-- Loggers         -->
   <!-- =============== -->
   < logger name = "com.log.one" >
     < level value = "DEBUG" />
     < appender-ref ref = "ONE" />
      < appender-ref ref = "CONSOLE" />
   </ logger >
  
    < logger name = "com.log.two" >
     < level value = "DEBUG" />
     < appender-ref ref = "TWO" />
      < appender-ref ref = "CONSOLE" />
   </ logger >
  
   < root >
       < priority value = "INFO" />
       < appender-ref ref = "FILE" />
   </ root >
</ log4j:configuration >
这里除常规的 CONSOLE FILE appender ,增加两个 appender ONE TWO ,分别通过自建类 LogOneAppender LogTwoAppender 定义。
public class LogOneAppender extends AppenderSkeleton{
    public LogOneAppender() {}
    protected void append(LoggingEvent event) {
       LogUI.log(event);
    }
    public void close() {}
    public boolean requiresLayout() {
       return false ;
    }
}
 
public class LogTwoAppender extends AppenderSkeleton{
    public LogTwoAppender() {}
    protected void append(LoggingEvent event) {
       LogUI.log(event);
    }
    public void close() {}
    public boolean requiresLayout() {
       return false ;
    }
}
logger 中通过 logger name,com.log.one com.log.two 指定到上述的 appender
7 .主界面设计 LogUI.java
主面板为 frame ,其中嵌入 LogPanel log 类的实体是一个 Log4Jmonitor 类的实例,通过它的 addLogArea 方法可以添加日志模块,其中的第二个参数对应 log4j 配置文件中的 logger name 。这里还提供一个 Cache 功能,即如果在主类 (LogUI) 或日志类 (Log4Jmonitor) 还没有实例化之前,已经有日志信息,则进行缓存。
public class LogUI {
    private static LogUI instance ;
    private static JFrame frame ;
    private Log4JMonitor logMonitor ;
    private static List<Object> logCache = new ArrayList<Object>();
    public LogUI() {
       instance = this ;
    }
    ///////////////////////UI
    private void buildUI() {
       frame .addWindowListener( new WindowAdapter() {
           public void windowClosing(WindowEvent e) {
              System.exit(0);
           }
       });
       frame .getContentPane().add(buildContentPanel(), BorderLayout. CENTER );
       frame .setDefaultCloseOperation(JFrame. DO_NOTHING_ON_CLOSE );
       frame .setSize(100, 75);
    }
 
    private Component buildContentPanel() {
       JSplitPane contentSplit = new JSplitPane();
       contentSplit.setTopComponent( new JTextArea( "The Main Text" ));
       contentSplit.setBottomComponent(buildLogPanel());
       contentSplit.setDividerLocation(550);
       contentSplit.setResizeWeight(1);
       return contentSplit;
    }
 
    private Component buildLogPanel() {
       logMonitor = new Log4JMonitor();
       logMonitor .addLogArea( "log one" , "com.log.one" , true ).setLevel(
              Level. DEBUG );
       logMonitor .addLogArea( "log two" , "com.log.two" , true ).setLevel(
              Level. DEBUG );
       for (Object message : logCache ) {
           logMonitor .logEvent(message);
       }
       return logMonitor ;
    }
 
    public void show() {
       buildUI();
       frame .setVisible( true );
    }
    ////////////////////Log
    public static synchronized void log( final Object msg) {
       if ( instance == null || instance . logMonitor == null ) {
           logCache .add(msg);
           return ;
       }
       if (SwingUtilities.isEventDispatchThread()) {
           instance . logMonitor .logEvent(msg);
       } else {
           SwingUtilities.invokeLater( new Runnable() {
              public void run() {
                  instance . logMonitor .logEvent(msg);
              }
           });
       }
    }
    //////////////////Test Cases
    public void doTests(){
       LogTestOne one= new LogTestOne();
       one.doLog();
       LogTestTwo two= new LogTestTwo();
       two.doLog();
    }
   
    public static void main(String[] args) throws Exception {
       frame = new JFrame( "LogUI " );
       LogUI logUi = new LogUI();
       logUi.show();
       logUi.doTests();
    }
}
8 log 类的实体 Log4Jmonitor
通过此类来建立日志模块。其中用到的 JlogList.java (见附件)提供对日志模块的所有基本功能。 addLogArea 方法增加日志模块。 logEvent 方法对输出的日志事件类型做出判断,对该日志所属的日志模块(本实例为 com.log.one com.log.two )做出判断。
public class Log4JMonitor extends JTabbedPane {
    private JLogList defaultLogArea ;
    public Log4JMonitor() {
       super (JTabbedPane. BOTTOM , JTabbedPane. SCROLL_TAB_LAYOUT );
    }
    public JLogList addLogArea(String title, String loggerName,
           boolean isDefault) {
       JLogList logArea = new JLogList(title);
       logArea.addLogger(loggerName, !isDefault);
       addTab(title, logArea);
       if (isDefault)
           defaultLogArea = logArea;
       return logArea;
    }
    public void logEvent(Object msg) {
       if (msg instanceof LoggingEvent) {
           LoggingEvent event = (LoggingEvent) msg;
           String loggerName = event.getLoggerName();
           for ( int c = 0; c < getTabCount(); c++) {
              Component tabComponent = getComponentAt(c);
              if (tabComponent instanceof JLogList) {
                  JLogList logArea = (JLogList) tabComponent;
                  if (logArea.monitors(loggerName)) {
                     logArea.addLine(msg);
                  }
              }
           }
       } else if ( defaultLogArea != null ) {
           defaultLogArea .addLine(msg);
       }
    }
    public boolean hasLogArea(String loggerName) {
       for ( int c = 0; c < getTabCount(); c++) {
           Component tabComponent = getComponentAt(c);
           if (tabComponent instanceof JLogList) {
              JLogList logArea = (JLogList) tabComponent;
              if (logArea.monitors(loggerName)) {
                  return true ;
              }
           }
       }
       return false ;
    }
}
 

你可能感兴趣的:(log4j,职场,appender,休闲)