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的相关基础介绍。
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;
    }
}
 

如何自建appender扩展Log4j框架的更多相关文章

  1. 002 使用Appender扩展logger框架

    这个地方,在看公司的源代码的时候,写的知识点: 现在再看,竟然不是太懂,重新写一份新的文档,外加示例说明. 一:说明 1.log4j 环境的三个主要组件: logger(日志记录器):控制要启用或禁用 ...

  2. log4j框架logger的继承关系以及使用场景

    log4j框架logger的继承关系以及使用场景 log4j日志框架logger是存在继承关系的,我们一般都会在log4j.properties文件中定义log4j.rootLogger.其他所有lo ...

  3. Log4j框架

    一.Log4j基本使用方法 Log4j由三个重要的组件构成:日志信息的优先级 Loggers,日志信息的输出目的地 Appenders,日志信息的输出格式 Layouts .日志信息的优先级从高到低 ...

  4. Log4J Appender - 将Log4J的日志内容发送到agent的source

    项目中使用log4j打印的内容同时传输到flume 1.flume端 flume的agent配置内容如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 a1.sour ...

  5. 扩展Log4j支持JNDI数据源

    log4j.properties配置文件: log4j.rootLogger=INFO,db #使用log4j扩展支持JNDI数据源 log4j.appender.db=com.qdgswx.log4 ...

  6. Kotlin的扩展函数:扩展Android框架(KAD 08)

    作者:Antonio Leiva 时间:Jan 11, 2017 原文链接:https://antonioleiva.com/extension-functions-kotlin/ 扩展函数是Kotl ...

  7. 架构探险笔记3-搭建轻量级Java web框架

    MVC(Model-View-Controller,模型-视图-控制器)是一种常见的设计模式,可以使用这个模式将应用程序进行解耦. 上一章我们使用Servlet来充当MVC模式中的Controller ...

  8. Robot Framework(十四) 扩展RobotFramework框架——创建测试库

    4.1创建测试库 Robot Framework的实际测试功能由测试库提供.有许多现有的库,其中一些甚至与核心框架捆绑在一起,但仍然经常需要创建新的库.这个任务并不复杂,因为正如本章所示,Robot ...

  9. Robot Framework(十五) 扩展RobotFramework框架——远程库接口

    4.2远程库接口 远程库接口提供了在运行Robot Framework本身的机器上运行测试库的方法,以及使用除本机支持的Python和Java之外的其他语言实现库的方法.对于测试库,用户远程库看起来与 ...

随机推荐

  1. Java中的函数对象

    初次听说java中的函数对象可能,比较的陌生.可以类比着来理解一下,人们常说java中没有了指针,殊不知,java中的对象引用就是指针,有时候我们说一个对象往往指的就是这个对象的引用,也就是说基本上把 ...

  2. angular element()

    使用angular.element()获取一个dom的方法. 1.可以使用jquery的选择器 2.可以使用javascript的原生的的查找元素的方法 下面是angular.element()提供的 ...

  3. 《用Python做HTTP接口测试》学习感悟

    机缘巧合之下,报名参加了阿奎老师发布在"好班长"的课程<用Python做HTTP接口测试>,报名费:15rmb,不到一杯咖啡钱,目前为止的状态:坚定不移的跟下去,自学+ ...

  4. Windows 10 Creaters Update 画中画模式和窗口高斯模糊

    在Windows 10 Creaters Update中,可以给窗口设置高斯模糊了,只要几行代码! <Grid Loaded="Grid_Loaded"> <Gr ...

  5. 谈谈在DevOps实践中,感觉最重要的这三个技术……

    从国内众多DevOps实践中,我们能看到下面三个技术尤其重要和火热: 容器:容器从根本上解决了软件对环境的依懒性,解决了各个环境之间的差异问题:它可以加速部署的速度,提高部署的效率:降低部署的成本.容 ...

  6. 深入浅出分析MySQL MyISAM与INNODB索引原理、优缺点、主程面试常问问题详解

    本文浅显的分析了MySQL索引的原理及针对主程面试的一些问题,对各种资料进行了分析总结,分享给大家,希望祝大家早上走上属于自己的"成金之路". 学习知识最好的方式是带着问题去研究所 ...

  7. 实时消息传输协议(RTMP)详解

    一.概念与摘要 RTMP协议从属于应用层,被设计用来在适合的传输协议(如TCP)上复用和打包多媒体传输流(如音频.视频和互动内容).RTMP提供了一套全双工的可靠的多路复用消息服务,类似于TCP协议[ ...

  8. MySQL大数据量分页查询

    mysql大数据量使用limit分页,随着页码的增大,查询效率越低下. 测试实验 1.   直接用limit start, count分页语句, 也是我程序中用的方法: select * from p ...

  9. 读Zepto源码之代码结构

    虽然最近工作中没有怎么用 zepto ,但是据说 zepto 的源码比较简单,而且网上的资料也比较多,所以我就挑了 zepto 下手,希望能为以后阅读其他框架的源码打下基础吧. 源码版本 本文阅读的源 ...

  10. WPF自定义控件(1)——仪表盘设计[1]

    0.小叙闲言 又接手一个新的项目了,再来一次上位机开发.网上有很多控件库,做仪表盘(gauge)的也不少,功能也很强大,但是个人觉得库很臃肿,自己就计划动手来写一个控件库,一是为学习,二是为了项目.下 ...