log4j源码阅读
基于log4j1.2.17的源代码阅读
org.apache.log4j.xml.DOMConfigurator 类是log4j的xml配置文件初始化类
org.apache.log4j.PropertyConfigurator 类是log4j的properties形式配置文件的初始化类
今天看的是前者
/**
A static version of {@link #doConfigure(String, LoggerRepository)}. */
static
public
void configure(String filename) throws FactoryConfigurationError {
new DOMConfigurator().doConfigure(filename,
LogManager.getLoggerRepository());
}
一般我们都是讲log4j.xml配置文件放到与src同目录下,方便在class path 的当前路径进行查找(不能放置到src目录里面,不然打包之后也会被打包到类目录下)
public
void doConfigure(final String filename, LoggerRepository repository) {
ParseAction action = new ParseAction() {
public Document parse(final DocumentBuilder parser) throws SAXException, IOException {
return parser.parse(new File(filename));
}
public String toString() {
return "file [" + filename + "]";
}
};
doConfigure(action, repository);
}
repositroy的作用目前还没有看到
先看下是如何解析xml和初始化相关对象的。
最终会调用DOMConfigurator 类当中的方法
/**
Used internally to configure the log4j framework by parsing a DOM
tree of XML elements based on <a
href="doc-files/log4j.dtd">log4j.dtd</a>. */
protected
void parse(Element element) { String rootElementName = element.getTagName(); if (!rootElementName.equals(CONFIGURATION_TAG)) {
if(rootElementName.equals(OLD_CONFIGURATION_TAG)) {
LogLog.warn("The <"+OLD_CONFIGURATION_TAG+
"> element has been deprecated.");
LogLog.warn("Use the <"+CONFIGURATION_TAG+"> element instead.");
} else {
LogLog.error("DOM element is - not a <"+CONFIGURATION_TAG+"> element.");
return;
}
} String debugAttrib = subst(element.getAttribute(INTERNAL_DEBUG_ATTR)); LogLog.debug("debug attribute= \"" + debugAttrib +"\".");
// if the log4j.dtd is not specified in the XML file, then the
// "debug" attribute is returned as the empty string.
if(!debugAttrib.equals("") && !debugAttrib.equals("null")) {
LogLog.setInternalDebugging(OptionConverter.toBoolean(debugAttrib, true));
} else {
LogLog.debug("Ignoring " + INTERNAL_DEBUG_ATTR + " attribute.");
} //
// reset repository before configuration if reset="true"
// on configuration element.
//
String resetAttrib = subst(element.getAttribute(RESET_ATTR));
LogLog.debug("reset attribute= \"" + resetAttrib +"\".");
if(!("".equals(resetAttrib))) {
if (OptionConverter.toBoolean(resetAttrib, false)) {
repository.resetConfiguration();
}
} String confDebug = subst(element.getAttribute(CONFIG_DEBUG_ATTR));
if(!confDebug.equals("") && !confDebug.equals("null")) {
LogLog.warn("The \""+CONFIG_DEBUG_ATTR+"\" attribute is deprecated.");
LogLog.warn("Use the \""+INTERNAL_DEBUG_ATTR+"\" attribute instead.");
LogLog.setInternalDebugging(OptionConverter.toBoolean(confDebug, true));
} String thresholdStr = subst(element.getAttribute(THRESHOLD_ATTR));
LogLog.debug("Threshold =\"" + thresholdStr +"\".");
if(!"".equals(thresholdStr) && !"null".equals(thresholdStr)) {
repository.setThreshold(thresholdStr);
} //Hashtable appenderBag = new Hashtable(11); /* Building Appender objects, placing them in a local namespace
for future reference */ // First configure each category factory under the root element.
// Category factories need to be configured before any of
// categories they support.
//
String tagName = null;
Element currentElement = null;
Node currentNode = null;
NodeList children = element.getChildNodes();
final int length = children.getLength(); for (int loop = 0; loop < length; loop++) {
currentNode = children.item(loop);
if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
currentElement = (Element) currentNode;
tagName = currentElement.getTagName(); if (tagName.equals(CATEGORY_FACTORY_TAG) || tagName.equals(LOGGER_FACTORY_TAG)) {
parseCategoryFactory(currentElement);
}
}
} for (int loop = 0; loop < length; loop++) {
currentNode = children.item(loop);
if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
currentElement = (Element) currentNode;
tagName = currentElement.getTagName(); if (tagName.equals(CATEGORY) || tagName.equals(LOGGER)) {
parseCategory(currentElement);
} else if (tagName.equals(ROOT_TAG)) {
parseRoot(currentElement);
} else if(tagName.equals(RENDERER_TAG)) {
parseRenderer(currentElement);
} else if(tagName.equals(THROWABLE_RENDERER_TAG)) {
if (repository instanceof ThrowableRendererSupport) {
ThrowableRenderer tr = parseThrowableRenderer(currentElement);
if (tr != null) {
((ThrowableRendererSupport) repository).setThrowableRenderer(tr);
}
}
} else if (!(tagName.equals(APPENDER_TAG)
|| tagName.equals(CATEGORY_FACTORY_TAG)
|| tagName.equals(LOGGER_FACTORY_TAG))) {
quietParseUnrecognizedElement(repository, currentElement, props);
}
}
}
}
通过分析这个方法我们可以看到
1)log4j.xml 中的根tag必须开头是log4j:configuration
如果不是,将会返回错误,并且同时检查是否是老的标签
OLD_CONFIGURATION_TAG ------configuration 如果是的话就打出warn日志,不是打出error日志
2)
在Log4j的源代码当中我们也发现了很多Log日志 ,在Log4j还没有加载完成的时候,利用的是什么打印的呢?
import org.apache.log4j.helpers.LogLog; 利用的就是这个内部帮助类,当我们在log4j.xml的根tag上标注debug=“true”的时候,就会发现这些log日志也打出了,主要是log4j的初始化日志,在quartz当中也可以看到类似的初始化日志
log4j源码阅读的更多相关文章
- Flink源码阅读(一)——Flink on Yarn的Per-job模式源码简析
一.前言 个人感觉学习Flink其实最不应该错过的博文是Flink社区的博文系列,里面的文章是不会让人失望的.强烈安利:https://ververica.cn/developers-resource ...
- 搭建 Spring 源码阅读环境
前言 有一个Spring源码阅读环境是学习Spring的基础.笔者借鉴了网上很多搭建环境的方法,也尝试了很多,接下来总结两种个人认为比较简便实用的方法.读者可根据自己的需要自行选择. 方法一:搭建基础 ...
- 【原】FMDB源码阅读(三)
[原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...
- 【原】FMDB源码阅读(二)
[原]FMDB源码阅读(二) 本文转载请注明出处 -- polobymulberry-博客园 1. 前言 上一篇只是简单地过了一下FMDB一个简单例子的基本流程,并没有涉及到FMDB的所有方方面面,比 ...
- 【原】FMDB源码阅读(一)
[原]FMDB源码阅读(一) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 说实话,之前的SDWebImage和AFNetworking这两个组件我还是使用过的,但是对于 ...
- 【原】AFNetworking源码阅读(六)
[原]AFNetworking源码阅读(六) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这一篇的想讲的,一个就是分析一下AFSecurityPolicy文件,看看AF ...
- 【原】AFNetworking源码阅读(五)
[原]AFNetworking源码阅读(五) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇中提及到了Multipart Request的构建方法- [AFHTTP ...
- 【原】AFNetworking源码阅读(四)
[原]AFNetworking源码阅读(四) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇还遗留了很多问题,包括AFURLSessionManagerTaskDe ...
- 【原】AFNetworking源码阅读(三)
[原]AFNetworking源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇的话,主要是讲了如何通过构建一个request来生成一个data tas ...
随机推荐
- Foundation与coreFoundation的相互转换
今天在整理以前的一些琐碎知识,今天就分享一个Foundation与coreFoundation的相互转换细节问题,其中的引用计数器是需要考虑的方面. ARC 环境下,CoreFoundation框 ...
- windows 下一个 easy_install 设备
下载安装python安装工具 1,方法是下载ez_setup.py后 2,在cmd下运行 python ez_setup.py.就可以自己主动安装setuptools 3,环境变量设置将 C:\Pro ...
- Mysql参数详解
1.配置参数 MySQL有两种途径途径了解其的配置参数,一个是MySQL交互模式下的命令SHOW VARIABLES,一个使用mysqladmin variables 查询. MySQL的配置参数分 ...
- kafka Windows客户端Linux服务器---转
原文:http://blog.csdn.net/jingshuigg/article/details/25001979 一.对于服务器端的搭建可以参考上一篇文章:kafka单机版环境搭建与测试 服务器 ...
- GUI编程笔记(java)06:GUI窗体添加按钮并对按钮添加事件案例
1.需求:把按钮添加到窗体,并对按钮添加一个点击事件. 步骤: (1)创建窗体对象(2)创建按钮对象(3)把按钮添加到窗体(4)窗体显示 2.编写程序思路: 窗体布局:窗体中组件的排列方式 布局分类 ...
- 【Oracle】INSERT INTO SELECT语句和SELECT INTO FROM语句的区别
>>>>>>>>>>>>>>>>>>>>>>>>> ...
- HTML之<!DOCTYPE> 标签介绍
实例: <!DOCTYPE html> <html> <head> <title>文档的标题</title> </head> & ...
- 规划收发你的邮件,使用qq邮箱接收阿里云企业邮邮件
使用qq邮箱接收阿里企业邮 首先管理员开通企业邮后会发来激活短信 根据短信提示打开https://qiye.aliyun.com企业邮登陆地址 使用短信提供的密码登陆邮箱 首次登陆时会让我们重设密码 ...
- Android开发手记(18) 数据存储三 SQLite存储数据
Android为数据存储提供了五种方式: 1.SharedPreferences 2.文件存储 3.SQLite数据库 4.ContentProvider 5.网络存储 SQLite 是以嵌入式为目的 ...
- Android Studio美化之优雅的logcat
博客: 安卓之家 微博: 追风917 CSDN: 蒋朋的家 简书: 追风917 博客园: 追风917 先来个图,图样吐sexy: 很简单,跟我走吧,两步: 1. 引入Logger库 首先,这个sexy ...