如何自建appender扩展Log4j框架

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介:
  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象征性的表示主应用程序的所有操作。
图二
 
图三
 
图四
 
同时在控制台输出所有日志信息。(图五)
图五
 
    同时在文本文件中输出所有日志信息。(图六)
图六
6log4j.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 >
这里除常规的CONSOLEFILE appender,增加两个appenderONETWO,分别通过自建类LogOneAppenderLogTwoAppender定义。
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.onecom.log.two指定到上述的appender
7.主界面设计LogUI.java
主面板为frame,其中嵌入LogPanellog类的实体是一个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();
    }
}
8log类的实体Log4Jmonitor
通过此类来建立日志模块。其中用到的JlogList.java(见附件)提供对日志模块的所有基本功能。addLogArea方法增加日志模块。logEvent方法对输出的日志事件类型做出判断,对该日志所属的日志模块(本实例为com.log.onecom.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 ;
    }
}
 

本文转自zhangjunhd51CTO博客,原文链接:http://blog.51cto.com/zhangjunhd/48895,如需转载请自行联系原作者
相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
19天前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
156 30
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
1月前
|
XML JSON Java
Logback 与 log4j2 性能对比:谁才是日志框架的性能王者?
【10月更文挑战第5天】在Java开发中,日志框架是不可或缺的工具,它们帮助我们记录系统运行时的信息、警告和错误,对于开发人员来说至关重要。在众多日志框架中,Logback和log4j2以其卓越的性能和丰富的功能脱颖而出,成为开发者们的首选。本文将深入探讨Logback与log4j2在性能方面的对比,通过详细的分析和实例,帮助大家理解两者之间的性能差异,以便在实际项目中做出更明智的选择。
245 3
|
29天前
|
Java 程序员 API
Android|集成 slf4j + logback 作为日志框架
做个简单改造,统一 Android APP 和 Java 后端项目打印日志的体验。
99 1
|
2月前
|
设计模式 SQL 安全
PHP中的设计模式:单例模式的深入探索与实践在PHP的编程实践中,设计模式是解决常见软件设计问题的最佳实践。单例模式作为设计模式中的一种,确保一个类只有一个实例,并提供全局访问点,广泛应用于配置管理、日志记录和测试框架等场景。本文将深入探讨单例模式的原理、实现方式及其在PHP中的应用,帮助开发者更好地理解和运用这一设计模式。
在PHP开发中,单例模式通过确保类仅有一个实例并提供一个全局访问点,有效管理和访问共享资源。本文详细介绍了单例模式的概念、PHP实现方式及应用场景,并通过具体代码示例展示如何在PHP中实现单例模式以及如何在实际项目中正确使用它来优化代码结构和性能。
49 2
|
1月前
|
SQL XML 监控
SpringBoot框架日志详解
本文详细介绍了日志系统的重要性及其在不同环境下的配置方法。日志用于记录系统运行时的问题,确保服务的可靠性。文章解释了各种日志级别(如 info、warn、error 等)的作用,并介绍了常用的日志框架如 SLF4J 和 Logback。此外,还说明了如何在 SpringBoot 中配置日志输出路径及日志级别,包括控制台输出与文件输出的具体设置方法。通过这些配置,开发者能够更好地管理和调试应用程序。
|
2月前
|
Java
日志框架log4j打印异常堆栈信息携带traceId,方便接口异常排查
日常项目运行日志,异常栈打印是不带traceId,导致排查问题查找异常栈很麻烦。
|
2月前
|
运维 NoSQL Java
SpringBoot接入轻量级分布式日志框架GrayLog技术分享
在当今的软件开发环境中,日志管理扮演着至关重要的角色,尤其是在微服务架构下,分布式日志的统一收集、分析和展示成为了开发者和运维人员必须面对的问题。GrayLog作为一个轻量级的分布式日志框架,以其简洁、高效和易部署的特性,逐渐受到广大开发者的青睐。本文将详细介绍如何在SpringBoot项目中接入GrayLog,以实现日志的集中管理和分析。
252 1
|
3月前
|
XML Java Maven
Spring5入门到实战------16、Spring5新功能 --整合日志框架(Log4j2)
这篇文章是Spring5框架的入门到实战教程,介绍了Spring5的新功能——整合日志框架Log4j2,包括Spring5对日志框架的通用封装、如何在项目中引入Log4j2、编写Log4j2的XML配置文件,并通过测试类展示了如何使用Log4j2进行日志记录。
Spring5入门到实战------16、Spring5新功能 --整合日志框架(Log4j2)
|
3月前
|
Java 数据库连接 数据库
后端框架的学习----mybatis框架(6、日志)
这篇文章介绍了如何在MyBatis框架中使用日志功能,包括配置MyBatis的日志实现、使用log4j作为日志工具,以及如何通过配置文件控制日志级别和输出格式。
|
3月前
|
存储 缓存 监控
【嵌入式SD NAND】基于FATFS/Littlefs文件系统的日志框架实现
综上所述,构建一个基于FATFS/Littlefs文件系统的日志框架需要对文件系统的操作有深入理解,并以此为基础设计一套完整的日志处理机制。这样的框架不仅能够确保日志数据的完整性和系统的鲁棒性,同时还能够满足嵌入式系统对于性能和资源使用的严格要求。
138 4
下一篇
无影云桌面