`
red_xie
  • 浏览: 25508 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

Log4j的Logger创建

阅读更多
一般使用Logger.getLogger(String name)取得logger,

LogManager.getLogger()---->getLoggerRepository().getLogger(name)

getLoggerRepsitory()函数返回一个LoggerRepository()对象,LoggerRepository是一个接口,

其实现者是Hierarahy


static  public  Logger getLogger(String name) {
    return LogManager.getLogger(name);
  }



public  static   Logger getLogger(final String name) {
     // Delegate the actual manufacturing of the logger to the logger repository.
    return getLoggerRepository().getLogger(name);
  }


static  public  LoggerRepository getLoggerRepository() {
    if (repositorySelector == null) {
        repositorySelector = new DefaultRepositorySelector(new NOPLoggerRepository());
        guard = null;
        LogLog.error("LogMananger.repositorySelector was null likely due to error in class reloading, using NOPLoggerRepository.");
    }
    return repositorySelector.getLoggerRepository();
  }



public
  LoggerRepository getLoggerRepository() {
    return repository;
  }
}


下面是Hierarchy类getLogger方法
public
  Logger getLogger(String name, LoggerFactory factory) {
    //System.out.println("getInstance("+name+") called.");
    CategoryKey key = new CategoryKey(name);
    // Synchronize to prevent write conflicts. Read conflicts (in
    // getChainedLevel method) are possible only if variable
    // assignments are non-atomic.
    Logger logger;

    synchronized(ht) {
      Object o = ht.get(key);
      if(o == null) {
	logger = factory.makeNewLoggerInstance(name);
	logger.setHierarchy(this);
	ht.put(key, logger);
	updateParents(logger);
	return logger;
      } else if(o instanceof Logger) {
	return (Logger) o;
      } else if (o instanceof ProvisionNode) {
	//System.out.println("("+name+") ht.get(this) returned ProvisionNode");
	[color=red]logger = factory.makeNewLoggerInstance(name);[/color]
	logger.setHierarchy(this);
	ht.put(key, logger);
	updateChildren((ProvisionNode) o, logger);
	updateParents(logger);
	return logger;
      }
      else {
	// It should be impossible to arrive here
	return null;  // but let's keep the compiler happy.
      }
    }
  }



下面是找到一篇非常好的文章~因为还没有概览到这个程度所以只能转载了

一、Log4j中Logger的层次结构
  Log4j中的Logger是以一个双向树的结构来组织的,但是Log4j却不是用通常使用的叶子结点和树枝结点来组织的。Log4j中使用了虚拟结点(ProvisionNode)和Logger(Logger)结点两种组织树的结构。
  用户真正创建的Logger结点用真正的Logger结点表示,而Logger结点的祖先却可能不是真正的Logger,为了提升Log4j的效率这里用一个简单的Vector来代替。
  ProvisionNode继承至Vector,并提供了一个接受一个Logger的构造方法。在Log4j的层次结构中仅仅是一个站位符。注意:ProvisionNode保存所有子Logger的实例。
  如果一个Logger的父Logger为虚拟结点(ProvisionNode),则其父Logger为RootLogger。
  二、Log4j中层次结构的作用
  1、使每一个层次中确定的结点只有一个Logger实例,减少Logger的内存消耗。
  2、使层次底层的Logger可以基层其祖先的等级。不用每个Logger都设置等级,并在底层Logger没有设置等级的情况下,可以一次性从祖先Logger中直接将Logger关闭(将祖先Logger的等级设为OFF)。
  实现方法:从自己开始向祖先方法访问各Logger的等级,直到访问到一个不为空的。如果父Logger为虚拟结点(ProvisionNode),则其父Logger为RootLogger。
  3、使层次底层的Logger可以基层其祖先的Appender。不用每个Logger都设置Appender,并在底层Logger没有设置Appender的情况下,可以一次性从祖先Logger中直接将更换Logger的Appender。
  实现方法:从自己开始向祖先方法访问各Logger的Appenders。如果继承属性(additive)为false,则在调用了自己所有的Appender后,就直接跳出循环。
  4、
  三、Log4j中Logger的创建
  1、所有Logger的创建最总都会发送到接口LoggerRepository的getLogger()方法中。Log4j中对此接口的实现是Hierarchy。Hierarchy中提供的创建过程如下:
  2、判断在Logger容器中是否已经存在此名称的Logger。可能有如下三种情况
  1)、不存在,已用工厂方法创建一个新Logger,设置Logger的repository属性,将Logger放入Logger容器中,调用updateParents()方法更新Logger的层次结构。
  2)、存在且类型为Logger,直接返回该Logger。
  3)、存在且类型为ProvisionNode,设置Logger的repository属性,将Logger放入Logger容器中,调用updateChildren()方法和updateParents()方法更新Logger的层次结构。
  3、updateParents(Logger)方法。更新父Logger的层次结构。
  尝试取得祖先Logger的实例,可能存在如下情况
  1)、如果父Logger存在,且类型为Logger,则设置为本Logger的父Logger。跳出循环。
  2)、如果父Logger存在,且类型为ProvisionNode,则将本Logger添加到ProvisionNode中,然后继续循环。
  3)、如果父Logger不存在,就创建相应的ProvisionNode,则将本Logger添加到ProvisionNode中,然后继续循环。
  注意:当时2、3情况时继续循环非常重要,这是维系Logger等级的一个重要方法。这样的结果是“ProvisionNode保存所有子Logger的实例。”
  4、updateChildren(ProvisionNode,Logger)方法。
  遍历ProvisionNode中所有的Logger,将所有没有正常连接到自己真正的父Logger上的Logger的父Logger设置为新建的用以替代ProvisionNode的Logger。
  5、
  四、Log4j中Log层次总揽
  1、如果一个Logger的所有父Logger类型为Logger:本Logger的父Logger直接指向父Logger。
  2、如果一个Logger的所有父Logger类型为ProvisionNode:本Logger的父Logger指向RootLogger。
  3、如果一个Logger的父Logger类型为ProvisionNode,但是祖先Logger中存在Logger。本Logger的父Logger指向所有祖先中最近的一个Logger。
  五、Log4j中Log的打印过程
  以Info()方法解析Log的打印过程。使用ConsoleAppender和PatternLayout。
  1、首先调用LoggerRepository接口的isDisabled()方法,通过和设置的Threshold等级比较,判断本层次的Log等级(在Info()方法中是Level.INFO_INT)能否打印。如果不可以就直接退出。
  2、调用getEffectiveLevel()方法遍历Logger的等级结构,找出本Logger的等级。并和本层次的Log等级(在Info()方法中是Level.INFO)比较,判断本Logger能否打印这个层次的Log。如果可以打印就调用forcedLog()方法。forcedLog()方法通过传入得参数生成一个LoggingEvent实例,然后调用callAppenders()方法。
  3、callAppenders(LoggingEvent)方法通过AppenderAttachableImpl类,先遍历本Logger中所有的Appender并调用相应的doAppend()方法。如果本Logger关闭了继承开关,就直接退出循环,否则依次遍历所有祖先的Appender。最后判断写Log的次数,如果等于0就打印没有Appender错误履历。
  4、AppenderAttachableImlp类实现了AppenderAttachable接口,并提供了一个Appender的聚集,和遍历聚集的方法appendLoopOnAppenders(LoggingEvent)。通过调用该方法可以以LoggingEvent为参数调用聚集中所有的Appender的doAppend方法打印履历。
  5、ConsoleAppender的doAppend()方法的实现在其祖先类AppenderSkeleton上,在doAppend()方法中,首先判断Appender是否已经关闭,如果已经关闭就打印一条错误履历并返回。然后比较Appender的Threshold等级,如果不通过就直接返回。调用Filter对象进行Log过滤。如果不通过就直接放回。然后调用append()方法。
  6、append()方法在ConsoleAppender的父类WriterAppender类中实现,它调用了本地的两个方法,checkEntryCoditions()判断Appender是否关闭,是否有Layout,输出的字符串是否为空。subAppned()方法实现真正的打印。
  7、subAppend()方法首先调用Layout格式化输出字符串,然后输出。在判断Layout是否忽略Throwable,如果不忽略掉用event.getThrowableStrRep()方法获取堆栈信息,然后答应。最后判断Appender是否要立即刷新输入,如果是就刷新输出。
  8、Over,结束一次完整的Log打印过程。不过怎么少了解释器的调用????
  9、原来,还有Layout没有看。在PatternLayout类的format()方法中,PatternLayout类会将LoggingEvent交给PatternConverter抽象类的format()方法来处理。这个抽象类的format方法中,调用了抽象方法convert(),这个方法最简单的实现时在PatternParser.java的BasicPatternConverter类中。在BasicPatternConverter的convert方法的末尾调用了LoggingEvent的getRenderedMessage()方法,看名字就知道了,在这里进行对象的解释。
  10、在LoggingEvent.getRenderedMessage()方法中,首先判断message是否是个字符串,如果是就直接返回String,如果不是就判断Logger的容器是否实现了RendererSupport接口。如果Logger容器实现了RendererSupport接口,就调用接口的getRendererMap()方法获取Renderer的一个聚集RendererMap,并调用他的findAndRender()方法。
  11、RendererMap中的findAndRender()方法中,用message的class对象去掉用get()方法,以获取也这个类对应的Renderer。get()方法会从下向上依次查找RendererMap中是否有对应的Renderer,如果有就直接退出,否则返回defaultRenderer实例(调用对象的toString()方法)。
  12、获取Renderer实例后,根据“面对抽象编程,而不面对实现编程。”显然我们使用ObjectRenderer接口,调用方法doRender(),解析对象,并返回一个String对象。
  13、over!


13点为转载内容,其中似乎有几个错别字,基层?继承?
有个问题,在"写"这篇文章时候突然明白了,使用provisionNode的好处,例如:

x.y.z

我们这里假设xweirootlogger下面的一个子节点,x.y是一个不存在的节点。

这样我们创建x.y.z时候,如果不使用provisionNode节点,我们一个比较好的方法是把其挂在

在x的下面,然而这样做的缺点是,当我有一天要使用x.y时候,我要创建x.y。这个时候情况

会怎样,x.y.z和x.y同级了。
分享到:
评论

相关推荐

    Log4j简介 介绍log4j的原理和用法

    log4j的使用习惯,让每个类都拥有一个private static的...注意:在一个项目中,log4j环境只需要被配置一次,而不是在每个使用了logger的类里都需要调用一次 ,用MyClass.class作为参数创建该类的静态Logger对象 。

    log4j使用实战

    log4j.rootLogger=INFO,CONSOLE log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender INFO是日志记录的最低等级,必须写,它和比它高的等级会进入日志,如WARN、ERROR、FATAL、OFF。 关于8个日志等级,参考:...

    Log4j学习和详细配置

    name : 这个那么就是你配置文件中对应的 log4j.logger. 后面的字符串  通过指定的名字获得记录器,如果必要的话,则为这个名字创建一个新的记录器。Name一般取本类的名字,比如:  static Logger logger = ...

    Tomcat使用Log4j输出catalina.out日志

    Tomcat默认的日志是用java.util.logging,有几点不足,文件catalian.out不能像log4j一样按天生成,将越来越大。日志格式和项目中用log4j打出来的不一致,不利于解析。...log4j.rootLogger = INFO, CAT

    javalog4j源码-SLF4J-Migrator:这是一个Python脚本,可让您将Java源代码中的JakartaCommonsLogg

    org.apache.log4j.Logger ; + import org.slf4j.Logger ; + import org.slf4j.LoggerFactory ; 2.日志实例将使用SLF4J创建 - private final static Logger log = Logger . getLogger( UserSessionFilter . class); +...

    log4j-2-elastic:Appender for Elasticsearch,具有所有Log4j 2功能的支持

    log4j-2-弹性 我创建了这个项目,以共享和增强附加程序,该附加程序将消息直接记录到集群中。 在某些特定情况下,这种将日志聚合到Elasticsearch中的方法可以很好地替代Elastic Beats。特征该产品包括一些标准和某些...

    logging:基于Java的log4j库的设计,可在Ruby程序中使用的灵活日志记录库

    日志记录是一个灵活的日志记录库,可根据Java的log4j库的设计在Ruby程序中使用。 它具有分层的日志记录系统,自定义级别名称,每个日志事件多个输出目标,自定义格式等。 安装 gem install logging 例子 本示例将...

    log4js-lw:Log4js 的轻量级分支

    Log4JS 库的这个派生提供了一个简单的类似 Log4j 的界面,用于在浏览器中进行登录。 这个项目的启动是为了降低复杂性,去除繁重的遗留支持,并为 stritti 创建和维护的添加模块化。 用法 初始化记录器: # init ...

    azkaban-3.38安装包(已编译)

    log4j.logger.azkaban=INFO, server log4j.appender.server=org.apache.log4j.RollingFileAppender log4j.appender.server.layout=org.apache.log4j.PatternLayout log4j.appender.server.File=logs/azkaban-...

    plsql_logger:用于Oracle数据库的PLSQL记录器

    plsql_logger英语: 基于 log4j 的 PL/SQL 记录器,但具有按上下文的级别日志,不像 log4j 那样全局。 所以你可以做一个上下文记录调试消息,另一个只记录错误消息。 一些想法来自 有关 proc 示例,请参见examples...

    Activiti-rest所有接口描述

    研究其功能可以知道,activiti-explorer这...我们把activiti-rest.war也部署到一个单独的tomcat中,修改WEB-INF/classes/log4j.properties文件,向其中加入以下内容,并将log4j.rootLogger=INFO, CA 后面添加一个“,D ”

    spark-with-request-logger

    如何使用包含log4j请求记录器的嵌入式Jetty服务器创建Spark实例 使用请求记录器创建嵌入式Jetty服务器 Spark 2.6.0引入了提供可配置的嵌入式Jetty服务器的选项。 本教程说明如何使用此功能来配置支持使用log4j记录...

    kotlin_project:kotlin框架

    本项目中使用log4j2,也可以排除掉,用其他日志框架替换掉。并且可以根据@KtLogger注解,来选择使用特定的Logger,避免无意义的多个相似Logger对象的创建。 // logging 抽象类 abstract class Logging { val log = ...

    Tomcat Session Logger-开源

    该项目旨在提供一种工具,可以从TOMCAT上下文中收集信息,特别是有关活动会话的信息。 我们将使用Log4j保留此信息,这将创建一个文件,该文件将存储收集的信息。

    NCMoney:MS Money的免费替代品-开源

    logger.properties现在替换了旧的log4j.properties。3. .bat(Windows用户)和.command(Mac用户)命令行也进行了相应更新。 当然,如果您覆盖dist.zip文件,则无需执行任何操作。 (如果您需要一些新功能或遇到...

    LBLogger java日志记录信息

    java已经有很多的logger jar,但是使用和配置起来都存在一定复杂性,不适合程序的调试和开发 本人在实际的工作根据实际需要提供以下简便的...建议大家使用 nsf4j 加 log4j,我算是重复发明轮子了。供大家学习吧!

    hadoop-2.6.0-hadoop.dll-winutils.exe

    log4j:WARN No appenders could be found for logger (org.apache.hadoop.metrics2.lib.MutableMetricsFactory). log4j:WARN Please initialize the log4j system properly. log4j:WARN See ...

    nuun-log-plugin:Nuun IO日志插件

    此Nuun插件提供了一种轻松的方式来注入SLF4J记录器,或创建自己的记录器注释。 如何使用它 将依赖项添加到您的pom.xml中: < groupId>io.nuun < artifactId>nuun-log-plugin < version>1.0.M2-SNAPSHOT 然后...

    telegram-log:当脚本触发异常或完成执行时,发送Telegram消息

    Telegram-Log是一种从多种编程语言到Telegram Bot进行交互的简单方法。 它是根据Apache License 2.0发布的。 一切之前:创建机器人 按照,创建机器人的第一步是开始与BotFather进行新的对话。 使用它,使用/newbot...

    《程序天下:J2EE整合详解与典型案例》光盘源码

    6.2 建立Log4j的开发环境 6.2.1 下载Log4j 6.2.2 配置Log4j 6.3 Log4j的使用方法 6.3.1 配置Log4j 6.3.2 配置根Logger 6.3.3 指定日志输出位置 6.3.4 指定日志输出格式 6.3.5 指定日志输出优先级 6.3.6 在代码中使用...

Global site tag (gtag.js) - Google Analytics