`
stone2oo6
  • 浏览: 25970 次
社区版块
存档分类
最新评论

Log4J日志分级应用

阅读更多

本文主要讲述一个日志分级应用的模型和如何利以及扩展Log4J来达到目的,关于Log4J的配置说明和基础应用就不再累述,详情可参见官方文档http://logging.apache.org/log4j/1.2/manual.html

 

另外3篇比较详细的博文:

首先我们来看一个模型:


 

KernelApplications都运行于同一个JVM中,且Applications运行于Kernel之上。JVM启动时依次会创建Bootstrap ClassLoader, Extension ClassLoaderAppClassLoader,分别会去加载JRE/lib,JRE/lib/ext下的核心包和kernel以及相关依赖的classes,jars等,之后由kernel创建并加载各个application,整个过程和一般的java web服务器启动比较类似(tomcat)

 

自然而然就有了这样的日志分级需求:

 

  • Kernel的日志记录到kernel.log文件中
  • 各个Application的日志分别记录到各自的文件中,如BBS的日志记录到bbs.logMails的日志记录到mails.log文件中
  • 其它日志(所有非kernelapplication中所关心的日志)记录到root.log中,以备不时之需

 

那么接下我们就要考虑log4j的配置问题了?——在这里我使用的配置文件是log4j.properties

 

  1. log4j.properties文件的位置?
  2. log4j.properties文件的内容?

对于问题1,从2个方面考虑:

 

  1. kernel中有使用log4j,并且可以kernel独立,所以log4j.properties需要在kernel中存在
  2. kernel并不知将来有多少applications,所以关于application日志的配置信息可以:
    •  采用默认机制创建,即在kernel加载application时创建
    • application中也加入log4j的配置信息,加载时读取

此外我们已经分析了整个模型的类加载机制,很显然log4j.jar也只会被kernel加载一次。看过log4j1.2.16)源代码的同学都知道log4j的初始化是在静态块中进行的,也就是说log4j.properties只会被加载一次,那么对于application中的配置文件就需要我们自己用log4j提供的APIkernel加载application时进行初始化了。

 

 

有了问题1的分析,我们可以把模型稍微简化成下图后再来分析问题2


 

依然是要求app1包下的日志写到app1.log文件中,app2包下的日志写到app2.log文件中,kernel包下的日志写到kernel.log文件中,其余的日志则写到root.log文件中。

 

log4.properties则如下所示


 

运行得到了以下日志输出:

 

不同package下的日志输出到了不同的日志文件中,看起来目的达到了,不过还是存在问题——即便rootlog级别设置为了error,但kernelapplication中的info信息还是会被输出到root.log中。大家可以想一下这是为什么?

 

 

如何避免写到kernelapplication中的日志重复被写到root中呢?——关键是org.apache.log4j.Category中的方法callAppenders

 /**
     Call the appenders in the hierrachy starting at
     <code>this</code>.  If no appenders could be found, emit a
     warning.

     <p>This method calls all the appenders inherited from the
     hierarchy circumventing any evaluation of whether to log or not
     to log the particular log request.

     @param event the event to log.  */
  public
  void callAppenders(LoggingEvent event) {
    int writes = 0;

    for(Category c = this; c != null; c=c.parent) {
      // Protected against simultaneous call to addAppender, removeAppender,...
      synchronized(c) {
	if(c.aai != null) {
	  writes += c.aai.appendLoopOnAppenders(event);
	}
	if(!c.additive) {
	  break;
	}
      }
    }

    if(writes == 0) {
      repository.emitNoAppenderWarning(this);
    }
  }
 

我们最终的目的就是阻止其输出日志后还继续上溯输出,因此需做如下修改:

if(c.aai != null) {
	  writes += c.aai.appendLoopOnAppenders(event);
          break;
	}
 

 

除了修改log4j其原生代码外,我们还可以通过继承和扩展的手段实现,下面便是所有实现代码。

  • 扩展org.apache.log4j.Logger和DefaultLoggerFactory如下
package com.xxx.cases
public class DefaultLoggerFactory implements org.apache.log4j.spi.LoggerFactory {

  public DefaultLoggerFactory() {
  }

  public Logger makeNewLoggerInstance(String name) {
    return new Logger(name);
  }
}

 

 

package com.xxx.cases;

import org.apache.log4j.Appender;
import org.apache.log4j.helpers.AppenderAttachableImpl;
import org.apache.log4j.spi.LoggingEvent;

public class Logger extends org.apache.log4j.Logger{
    private static final DefaultLoggerFactory defaultFactory = new DefaultLoggerFactory();

    private AppenderAttachableImpl aai;

    protected Logger(String name) {
        super(name);
    }

    @Override
    public void callAppenders(LoggingEvent event) {
        if (this.aai == null && !(this.getParent() instanceof Logger)) {
            super.callAppenders(event);
        } else {
            int writes = 0;

            for (Logger c = this; c != null; c = (Logger) c.getParent()) {
                // Protected against simultaneous call to addAppender, removeAppender,...
                synchronized (c) {
                    if (c.aai != null) {
                        writes += c.aai.appendLoopOnAppenders(event);
                        break;
                    }
                    if (!c.getAdditivity()) {
                        break;
                    }
                }
            }

            if (writes == 0) {
                repository.emitNoAppenderWarning(this);
            }
        }
    }

    public synchronized void addAppender(Appender newAppender) {
        if (aai == null) {
            aai = new AppenderAttachableImpl();
        }
        aai.addAppender(newAppender);
        repository.fireAddAppenderEvent(this, newAppender);
    }

    public static Logger getLogger(Class clazz){
        return (Logger)org.apache.log4j.Logger.getLogger(clazz.getName(), defaultFactory);
    }
}
  • 修改log4j.properties配置文件,增加loggerFactory配置项

 

  • 新Logger的应用(如在kernel中)

package com.xxx.cases.kernel;

import com.xxx.cases.Logger;

public class KernelBean {
    private static Logger logger = Logger.getLogger(KernelBean.class);

    public void testMethod(){
        logger.info("in kernel bean test method");
    }
}

 

后记:经朋友提醒,还有一种更加简便的方式,只需要修改log4.properties配置信息——其目的和原理是一样的。



 注意黄色高亮的部分。

 

 

——结束

  • 大小: 44 KB
  • 大小: 18.4 KB
  • 大小: 34.1 KB
  • 大小: 17 KB
  • 大小: 2 KB
  • 大小: 38.3 KB
0
1
分享到:
评论

相关推荐

    log4j简单范例 日志文件是相对路径的

    Log4j是一款广泛使用的日志记录框架,尤其在Java应用程序中。它允许开发者灵活地控制日志信息的输出,提供了一种分级的日志记录机制,便于调试、性能分析和问题排查。这个“log4j简单范例 日志文件是相对路径的”...

    用到的两个log4j日志架包

    本话题将深入探讨"用到的两个log4j日志架包"——`android-logging-log4j-1.0.3.jar`和`log4j-1.2.15.jar`。 首先,`android-logging-log4j-1.0.3.jar`是专门为Android平台设计的日志库,它是Log4j的一个变种,使得...

    log4j详细配置说明

    - **复制 JAR 文件**:解压后,将 `jakarta-log4j-1.2.8\dist\lib` 目录下的 `log4j-1.2.8.jar` 文件复制到 Tomcat 的 `common\lib` 目录下或其他应用程序的 `lib` 盏录下。 - **配置 web.xml**:在应用的 `web.xml`...

    Log4J应用技术.PPT

    Log4J的实现原理是通过提供分级的日志记录方法,允许开发者在代码中嵌入日志记录语句,这些语句具有多种输出格式和多个输出级别。这与传统的在代码中插入`System.out.println`或其他输出语句的方式不同,后者往往...

    Log4j实例

    Log4j是一款广泛应用于Java平台的日志记录框架,它提供了灵活且强大的日志记录功能,使得开发者能够方便地控制日志信息的输出级别、格式以及目的地。本实例将深入探讨Log4j的基本使用方法和配置。 一、Log4j的核心...

    log4j使用配置方法及项目中的应用

    ### log4j使用配置方法及项目中的应用 #### 概述与背景 在软件开发过程中,日志记录是一项至关...通过以上配置,Log4j能够按照预设规则高效、准确地记录和输出日志信息,极大提升了应用程序的可观测性和可维护性。

    关于Log4j的Demo

    这个“关于Log4j的Demo”是帮助开发者更好地理解和应用Log4j的一个实例。Log4j不仅提高了代码的可读性和可维护性,还允许开发者根据需要调整日志输出的级别,从而实现不同环境下的日志管理。 **Log4j的基本组件** ...

    Strtus2.3升级2.5(包含log4j升级log4j2)所需jar,和相关资料

    例如,你可以配置日志分级(DEBUG, INFO, WARN, ERROR等),并实现日志分片以方便日志管理和分析。 6. **测试和调试**:升级后,全面测试应用程序以确保所有功能正常工作。如果遇到错误,检查日志输出,这通常是...

    一种基于Log4J的日志输出组件的设计

    - **应用**:Log4J广泛应用于Java应用程序中,用于记录程序运行时的重要信息,以便于后续的问题定位、性能优化及审计等目的。 #### 3. 日志输出组件的设计思路 - **背景**:本文介绍的LogUtil组件是针对一款中型...

    log4j的jar包和配置文件

    Log4j是Apache组织提供的一款开源日志框架,它具有高效、灵活、可扩展的特点,广泛应用于各种Java项目中,包括Mybatis这样的持久层框架。 ### 1. Log4j的基本组件 - **Logger**: 日志记录器是Log4j的核心组件,...

    log4j-1.3alpha-7.jar

    通常建议使用更稳定、经过充分测试的正式版本,比如`apache-log4j-2.0-beta3-bin`,它是Log4j 2.0的早期版本,带来了更多改进和新特性,如异步日志处理器、更丰富的日志级别(如TRACE)以及日志分级配置。...

    log4j-1.2.17

    log4j是Apache组织开发的一款开源日志记录工具,主要服务于Java应用程序。它的设计目标是提供一个灵活、高效的日志记录框架,允许开发者定制日志级别,选择不同的日志输出格式,甚至配置日志存储位置。log4j-1.2.17...

    log4j-1.2.14.jar1

    四、使用Log4j 在Java代码中,通过`Logger`类获取logger实例,然后调用相应的方法进行日志记录: ```java import org.apache.log4j.Logger; public class MyClass { private static final Logger logger = ...

    Log4j使用手册

    以下是Log4j的核心组成部分、使用方法以及日志分级的详细解释。 1. **LOG4J组成**: - **Logger**:是Log4j的核心,负责决定哪些日志信息应该被记录和哪些应该被忽略。它根据预定义的级别来过滤日志,由`org....

    log4j-core-2.5

    5. **日志分级**:遵循日志级别的标准(TRACE、DEBUG、INFO、WARN、ERROR、FATAL、OFF),Log4j-core-2.5可以方便地控制不同级别日志的输出。 二、SLF4J接口的集成 SLF4J(Simple Logging Facade for Java)是一个...

    Log4jAPI 应用案例 配置说明 log4jjar包

    Log4j是Java平台上广泛使用的日志记录框架,它的全称是Apache Log4j,它为应用程序提供了灵活的日志记录功能。在Java开发中,日志记录是非常关键的一部分,可以帮助开发者跟踪程序运行状态,定位错误,进行性能分析...

    log4j使用手册和配置文件实例

    Log4j是Apache组织提供的一款开源的日志记录工具,广泛应用于Java开发中。它提供了灵活的日志记录功能,帮助开发者跟踪程序运行状态,调试问题,以及收集运行数据,对系统的监控和维护起着至关重要的作用。本手册将...

    log4j 使用介绍

    log4j 是一个广泛使用的 Java 日志框架,它提供了一种高效、灵活的方式来记录应用程序中的事件。这篇介绍旨在帮助初学者理解 log4j 的核心概念和使用方法。 **1. 简介** 日志记录在软件开发中扮演着重要角色,因为...

    log4j-2.0-alpha2

    Log4j 2.0 Alpha2支持多种应用程序框架,如Spring、Struts等,并且与Log4j 1.x和Logback等其他日志框架具有良好的兼容性,方便迁移和集成。 **8. XML配置** 在"apache-log4j-2.0-alpha2-bin"压缩包中,包含的XML...

Global site tag (gtag.js) - Google Analytics