`
george.gu
  • 浏览: 73853 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

log4j source code analyze

 
阅读更多

org.apache.log4j.LogManager.java

A singleton class implemented by a set of "static" properties and methods.

 

/**
 * Use the <code>LogManager</code> class to retreive {@link Logger}
 * instances or to operate on the current {@link
 * LoggerRepository}. When the <code>LogManager</code> class is loaded
 * into memory the default initalzation procedure is inititated. The
 * default intialization procedure</a> is described in the <a
 * href="../../../../manual.html#defaultInit">short log4j manual</a>.
 *
 * @author Ceki G&uuml;lc&uuml; */
public class LogManager {

  /**
   * @deprecated This variable is for internal use only. It will
   * become package protected in future versions.
   * */
  static public final String DEFAULT_CONFIGURATION_FILE = "log4j.properties";
  
  static final String DEFAULT_XML_CONFIGURATION_FILE = "log4j.xml";  
   
  /**
   * @deprecated This variable is for internal use only. It will
   * become private in future versions.
   * */
  static final public String DEFAULT_CONFIGURATION_KEY="log4j.configuration";

  /**
   * @deprecated This variable is for internal use only. It will
   * become private in future versions.
   * */
  static final public String CONFIGURATOR_CLASS_KEY="log4j.configuratorClass";

  /**
  * @deprecated This variable is for internal use only. It will
  * become private in future versions.
  */
  public static final String DEFAULT_INIT_OVERRIDE_KEY = 
                                                 "log4j.defaultInitOverride";


  static private Object guard = null;
  static private RepositorySelector repositorySelector;

  static {
    // By default we use a DefaultRepositorySelector which always returns 'h'.
    Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));  //#1
    repositorySelector = new DefaultRepositorySelector(h);

    /** Search for the properties file log4j.properties in the CLASSPATH.  */
    String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY,
						       null);

    // if there is no default init override, then get the resource
    // specified by the user or the default config file.
    if(override == null || "false".equalsIgnoreCase(override)) { //#2

      String configurationOptionStr = OptionConverter.getSystemProperty(
							  DEFAULT_CONFIGURATION_KEY, 
							  null);

      String configuratorClassName = OptionConverter.getSystemProperty(
                                                   CONFIGURATOR_CLASS_KEY, 
						   null);

      URL url = null;

      // if the user has not specified the log4j.configuration
      // property, we search first for the file "log4j.xml" and then
      // "log4j.properties"
      if(configurationOptionStr == null) {	//#3
	url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
	if(url == null) {
	  url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
	}
      } else {
	try {
	  url = new URL(configurationOptionStr);
	} catch (MalformedURLException ex) {
	  // so, resource is not a URL:
	  // attempt to get the resource from the class path
	  url = Loader.getResource(configurationOptionStr); 
	}	
      }
      
      // If we have a non-null url, then delegate the rest of the
      // configuration to the OptionConverter.selectAndConfigure
      // method.
      if(url != null) {
	LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");      
	OptionConverter.selectAndConfigure(url, configuratorClassName, 
					   LogManager.getLoggerRepository()); //#4
      } else {
	LogLog.debug("Could not find resource: ["+configurationOptionStr+"].");
      }
    }  
  } 

  /**
     Sets <code>LoggerFactory</code> but only if the correct
     <em>guard</em> is passed as parameter.
     
     <p>Initally the guard is null.  If the guard is
     <code>null</code>, then invoking this method sets the logger
     factory and the guard. Following invocations will throw a {@link
     IllegalArgumentException}, unless the previously set
     <code>guard</code> is passed as the second parameter.

     <p>This allows a high-level component to set the {@link
     RepositorySelector} used by the <code>LogManager</code>.
     
     <p>For example, when tomcat starts it will be able to install its
     own repository selector. However, if and when Tomcat is embedded
     within JBoss, then JBoss will install its own repository selector
     and Tomcat will use the repository selector set by its container,
     JBoss.  */
  static
  public
  void setRepositorySelector(RepositorySelector selector, Object guard) 
                                                 throws IllegalArgumentException {
    if((LogManager.guard != null) && (LogManager.guard != guard)) {
      throw new IllegalArgumentException(
           "Attempted to reset the LoggerFactory without possessing the guard.");
    }

    if(selector == null) {
      throw new IllegalArgumentException("RepositorySelector must be non-null.");
    }

    LogManager.guard = guard;
    LogManager.repositorySelector = selector;
  }

  static
  public
  LoggerRepository getLoggerRepository() {
    return repositorySelector.getLoggerRepository(); //#5
  }

  /**
     Retrieve the appropriate root logger.
   */
  public
  static 
  Logger getRootLogger() { //#6
     // Delegate the actual manufacturing of the logger to the logger repository.
    return repositorySelector.getLoggerRepository().getRootLogger();
  }
...
}
 

 

#1: static uniqic Hierarchy objec to make sure all the Loggers hierarchies managed in same Hierarchy instance. 

#1: root Logger will be also initialized in thise step.

 

#2: Override/Ignore default log4jInt or

log4j.defaultInitOverride=true will cause LoggerManager ignore all the source code after #2.

Then your project should provide customized Configurator to configure log4j. This will be discussed later.

 

(To be updated)

 

org.apache.log4j.PropertyConfigurator.java

All the existing appenders related to root logger will be closed during configuration

void configureRootCategory(*):

  void configureRootCategory(Properties props, LoggerRepository hierarchy) {
    String effectiveFrefix = ROOT_LOGGER_PREFIX;
    String value = OptionConverter.findAndSubst(ROOT_LOGGER_PREFIX, props);

    if(value == null) {
      value = OptionConverter.findAndSubst(ROOT_CATEGORY_PREFIX, props);
      effectiveFrefix = ROOT_CATEGORY_PREFIX;
    }

    if(value == null)
      LogLog.debug("Could not find root logger information. Is this OK?");
    else {
      Logger root = hierarchy.getRootLogger();
      synchronized(root) {
	parseCategory(props, root, effectiveFrefix, INTERNAL_ROOT_NAME, value); //#1
      }
    }
  }

 

 

void parseCategory(*):

 

  /**
     This method must work for the root category as well.
   */
  void parseCategory(Properties props, Logger logger, String optionKey,
		     String loggerName, String value) {

    LogLog.debug("Parsing for [" +loggerName +"] with value=[" + value+"].");
    // We must skip over ',' but not white space
    StringTokenizer st = new StringTokenizer(value, ",");

    // If value is not in the form ", appender.." or "", then we should set
    // the level of the loggeregory.

    if(!(value.startsWith(",") || value.equals(""))) {

      // just to be on the safe side...
      if(!st.hasMoreTokens())
	return;

      String levelStr = st.nextToken();
      LogLog.debug("Level token is [" + levelStr + "].");

      // If the level value is inherited, set category level value to
      // null. We also check that the user has not specified inherited for the
      // root category.
      if(INHERITED.equalsIgnoreCase(levelStr) || 
 	                                  NULL.equalsIgnoreCase(levelStr)) {
	if(loggerName.equals(INTERNAL_ROOT_NAME)) {
	  LogLog.warn("The root logger cannot be set to null.");
	} else {
	  logger.setLevel(null);
	}
      } else {
	logger.setLevel(OptionConverter.toLevel(levelStr, (Level) Level.DEBUG));
      }
      LogLog.debug("Category " + loggerName + " set to " + logger.getLevel());
    }

    // Begin by removing all existing appenders.
    logger.removeAllAppenders(); //#1

    Appender appender;
    String appenderName;
    while(st.hasMoreTokens()) {
      appenderName = st.nextToken().trim();
      if(appenderName == null || appenderName.equals(","))
	continue;
      LogLog.debug("Parsing appender named \"" + appenderName +"\".");
      appender = parseAppender(props, appenderName); //#2
      if(appender != null) {
	logger.addAppender(appender); //#3
      }
    }
  }

 

#1: remove all existing Appenders for the logger to configure.

If same logger are configured twice in different Configurators, some Appender could be closed. This is why sometimes log4j raise error:

 

log4j:ERROR Attempted to append to closed appender named [*]

 

 

#2: parse Appender from configuration file.

PropertyConfigurator will create the Appender instance once in its range. There is a static Hashtable to keep Appender instances:

 

  /**
     Used internally to keep track of configured appenders.
   */
  protected Hashtable registry = new Hashtable(11);

 

 But the exceptional case is: even the same appender existing in another Configurator, PropertyConfigurator will creae the same instance again.

 

#3: Add new Appender to logger

 

To be done: see more details on how Logger manage its Appender list.

 

org.apache.log4j.xml.DOMConfigurator.java

Configure Loggers in main Hierarchy

 

  /**
     A static version of {@link #doConfigure(String, LoggerRepository)}.  */
  static
  public
  void configure(String filename) throws FactoryConfigurationError {
    new DOMConfigurator().doConfigure(filename, 
				      LogManager.getLoggerRepository());
  }
 

 

 

Remove and re-configure Appenders list

 

  /**
     Used internally to parse the children of a category element.
  */
  protected
  void parseChildrenOfLoggerElement(Element catElement,
				      Logger cat, boolean isRoot) {
    
    PropertySetter propSetter = new PropertySetter(cat);
    
    // Remove all existing appenders from cat. They will be
    // reconstructed if need be.
    cat.removeAllAppenders();//#1


    NodeList children 	= catElement.getChildNodes();
    final int length 	= children.getLength();
    
    for (int loop = 0; loop < length; loop++) {
      Node currentNode = children.item(loop);

      if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
	Element currentElement = (Element) currentNode;
	String tagName = currentElement.getTagName();
	
	if (tagName.equals(APPENDER_REF_TAG)) {
	  Element appenderRef = (Element) currentNode;
	  Appender appender = findAppenderByReference(appenderRef);
	  String refName =  subst(appenderRef.getAttribute(REF_ATTR));
	  if(appender != null)
	    LogLog.debug("Adding appender named ["+ refName+ 
			 "] to category ["+cat.getName()+"].");
	  else 
	    LogLog.debug("Appender named ["+ refName + "] not found.");
	    
	  cat.addAppender(appender);
	  
	} else if(tagName.equals(LEVEL_TAG)) {
	  parseLevel(currentElement, cat, isRoot);	
	} else if(tagName.equals(PRIORITY_TAG)) {
	  parseLevel(currentElement, cat, isRoot);
	} else if(tagName.equals(PARAM_TAG)) {
          setParameter(currentElement, propSetter);
	}
      }
    }
    propSetter.activate();
  }
 

 

#1: remove existing Appenders before re-configure

 

To be updated later.

 

 

分享到:
评论

相关推荐

    uCOS_code & analyze

    《uCOS_code & analyze》是关于嵌入式实时操作系统uCOS的源代码解析与学习资料。这个资源包包含了对uCOS II(MicroC/OS-II)的深入剖析文档以及源代码,旨在帮助开发者理解和掌握这款小巧而强大的实时操作系统。 ...

    measurements on source code in C, C++

    program exists to analyze and report measurements on source code in C, C++ and Java. The languages Ada83 and Ada95, which were supported in previous versions are presently not supported, although ...

    Redis-Source-Code-Analyze:Redis原始阅读和分析(Redis-3.2.5)-redis source code

    本自述文件只是一个快速入门文档。 您可以在找到更多详细的文档。 什么是Redis? Redis通常被称为数据结构服务器。 这意味着Redis通过一组命令提供对可变数据结构的访问,这些命令是使用带有TCP套接字和简单协议的...

    vue-source-code-analyze:vue源代码分析-vue source code

    准备 [] .slice.call(lis):将伪整数转换为真数组 node.nodeType:得到例程类型 Object.defineProperty(obj,propertyName,{}):给对象添加/修改属性(指定引用)数据可配置:true / false是否可以重新定义...

    source-analyze:原始码分析

    在“source-analyze”这个主题下,我们将探讨源代码分析的重要性和实践方法,以及如何利用开源工具和技术来提升代码质量。 首先,源代码分析是软件开发过程中的关键环节,它能够帮助开发者在代码部署之前找出并修复...

    APE Codec( Monkey Audio) SDK Source Code

    Monkey's Audio Codec SDK Source Code 提供了用于开发与Monkey Audio格式交互的软件开发工具包,允许程序员创建自己的支持APE格式的应用程序或插件。 在压缩包子文件的文件名称列表中,我们可以看到以下几个关键...

    Windows2016 EventLog Analyzer安装部署.pptx

    Windows2016 EventLog Analyzer安装部署 1.产品概览 2.功能介绍 ...4.硬件要求 5.操作系统要求 6.安装Windows Server 2016 7.EventLog Analyzer使用的端口 8.部署EventLog Analyzer 9.应用EventLog Analyzer

    linux-source-code-analyze:Linux原始码分析

    4. **文件系统**:Linux支持多种文件系统,如EXT2、EXT3、EXT4、FAT、NTFS等。文件系统管理磁盘上的数据组织,执行文件的读写操作,处理挂载和卸载等任务。VFS(虚拟文件系统)提供了一致的接口,使不同类型的文件...

    java_collection_source_code_analyze:Java集合部分源码分析-Source code collection

    本项目"java_collection_source_code_analyze"专注于对Java集合框架的源代码进行深入分析,帮助开发者理解其内部机制,从而更好地利用这些工具。下面我们将详细探讨Java集合框架中的主要类、接口以及它们的实现和...

    EventLog_Analyzer.zip

    Eventlog Analyzer日志管理系统、日志分析工具、日志服务器的功能及作用  Eventlog Analyzer是用来分析和审计系统及事件日志的管理软件,能够对全网范围内的主机、服务器、网络设备、数据库以及各种应用服务系统等...

    mybatis_source_analyze:Mybatis源码分析

    在这个名为"mybatis_source_analyze"的压缩包文件中,很显然,作者提供了一个对Mybatis源码的详细分析。这份分析可能是对Mybatis内部工作原理的深入探究,包括其核心组件、执行流程、SQL映射机制等关键部分。 首先...

    jquery_source_analyze:jq原始代码分析

    jquery_source_analyze:jq原始代码分析

    饿了么-source code analyzer based on Clang

    饿了么是一家知名的在线外卖平台,其开发团队利用开源代码分析工具Clang构建了一个定制化的静态代码分析器,用于分析Objective-C语言编写的源代码。这个分析器通过Clang提供的强大功能来增强代码审查和质量保证流程...

    用source insight 阅读matlab 文件的方法

    Source Insight还可以帮助进行代码分析,通过“Analyze”功能检查代码质量,如检查未使用的变量、未定义的函数等。此外,它还支持代码重构,比如重命名变量或函数,所有相关的引用都会自动更新。 8. **版本控制...

    How to analyze Force close_crash from log

    4. 分析异常信息,理解错误原因。 5. 依据日志中的详细信息,定位问题代码。 6. 调整代码或配置,尝试解决问题。 在整个过程中,熟练掌握日志分析技巧对于开发者来说至关重要,因为它可以帮助快速定位和修复应用中...

    ANALYZE FORMAT 文档资料~

    ### Analyze Format:一种用于MRI图像存储的专用格式 #### 一、概述 Analyze Format是一种专门用于存储医学影像数据的文件格式,特别是在磁共振成像(MRI)领域有着广泛的应用。该格式由美国梅奥诊所(Mayo Clinic...

    SharpDevelop Reports 3.0.0.616 Source ,SharpDevelop analyze SharpPad_Ext

    4. **错误检测与标记**:SharpPad_Ext可能会实时分析代码,找出潜在的编译错误或警告,并在编辑器中以行号或下划线的形式显示出来。源码分析将揭示这个过程的实现细节。 5. **扩展接口**:SharpDevelop鼓励用户...

    wireshark analyze

    By Wireshark analyze a ‘ping’ commond Open wireshark select our network In order to analyze ping commond, usually select wlan use filter : icmp(Internet Control Message Protocol), because ICMP...

    vss批量analyze,很好用的!

    - 第四步:将文件扩展名由 `.txt` 改为 `.bat`,例如 `analyze.bat`。 - 第五步:双击运行批处理文件 `analyze.bat`。 2. **批处理文件执行流程**: - 当运行批处理文件时,首先会切换到指定的 VSS 安装目录下。...

Global site tag (gtag.js) - Google Analytics