slf4j即Simple logging facade for Java,其作用类似于JDBC,作为一个日志抽象层,它允许你在后台使用任意一个日志类库,比如log4j。如果是在编写供内外部都可以使用的API或者通用类库,那么你真不会希望使用你类库的客户端必须使用你选择的日志类库。常用的日志类库有log4j、logback等,本文就来深入了解一下log4j。
开发代码中,我们只需要在src下放上log4j.xml或log4j.properties,log4j就能自动找到该配置文件,web工程在spring环境下,我们还可以在web.xml中自定义上述配置文件的路径。
<context-param> <param-name>log4jConfigLocation</param-name> <param-value>WEB-INF/log4j.properties</param-value> </context-param> <context-param> <param-name>log4jRefreshInterval</param-name> <param-value>6000</param-value> </context-param> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener>
那么log4j默认是怎么加载配置文件的呢?每一个Logger实例在log里是怎么安排存放的呢?
Log4j由三个重要的组成构成:日志记录器(Loggers),输出端(Appenders)和日志格式化器(Layout)。
1.日志记录器(Loggers):控制要输出哪些日志记录语句,对日志信息进行级别限制。
2.输出端(Appenders):指定了日志将打印到控制台还是文件中。
3.日志格式化器(Layout):控制日志信息的显示格式。
log4j初始化
从架构上我们可以看出logger的实现是从logManager来具体完成的,因此初始化在logManager的static块中,如下:
static { // By default we use a DefaultRepositorySelector which always returns 'h'. Hierarchy h = new Hierarchy(new RootLogger(Level.DEBUG)); 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)) { 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) { 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."); try { OptionConverter.selectAndConfigure(url, configuratorClassName, LogManager.getLoggerRepository()); } catch (NoClassDefFoundError e) { LogLog.warn("Error during default initialization", e); } } else { LogLog.debug("Could not find resource: ["+configurationOptionStr+"]."); } } else { LogLog.debug("Default initialization of overridden by " + DEFAULT_INIT_OVERRIDE_KEY + "property."); } }
让我们深入进去看看是怎么初始化的?
第一步:创建一个默认的RepositorySelector,RepositorySelector在logManager中使用,它的实现类对特定的应用上下文提供了一个LoggerRespository。LoggerRespository的实现类负责追踪应用上下文。ResponsitorySelector提供了一个方法:
public LoggerRepository getLoggerRepository();
LoggerRepository从字面上理解,它是一个Logger的容器,它会创建并缓存Logger实例,从而具有相同名字的Logger实例不会多次创建,以提高性能。它的这种特性有点类似Spring的IOC概念。Log4J支持两种配置文件:properties文件和xml文件。Configurator解析配置文件,并将解析后的信息添加到LoggerRepository中。LogManager最终将LoggerRepository和Configurator整合在一起。
LoggerRepository同时它也维护了Logger之间的关系,因为在Log4J中,所有Logger都组装成以RootLogger为根的一棵树,树的层次由Logger的Name来决定,其中以’.’分隔。
除了作为一个Logger容器,它还有一个Threshold属性,用于过滤所有在Threshold级别以下的日志。以及其他和Logger操作相关的方法和属性。
public interface LoggerRepository { public void addHierarchyEventListener(HierarchyEventListener listener); boolean isDisabled(int level); public void setThreshold(Level level); public void setThreshold(String val); public void emitNoAppenderWarning(Category cat); public Level getThreshold(); public Logger getLogger(String name); public Logger getLogger(String name, LoggerFactory factory); public Logger getRootLogger(); public abstract Logger exists(String name); public abstract void shutdown(); public Enumeration getCurrentLoggers(); public abstract void fireAddAppenderEvent(Category logger, Appender appender); public abstract void resetConfiguration(); }
Hierarchy类
Hierarchy是Log4J中默认对LoggerRepository的实现类,它用于表达其内部的Logger是以层次结构存储的。在对LoggerRepository接口的实现中,getLogger()方法是其最核心的实现,因而首先从这个方法开始。Hierarchy中用一个Hashtable来存储所有Logger实例,它以CategoryKey作为key,Logger作为value,其中CategoryKey是对Logger中Name字符串的封装,之所以要引入这个类是出于性能考虑,因为它会缓存Name字符串的hash code,这样在查找过程中计算hash code时就可以直接取得而不用每次都计算。
第二步:从classpath路径查找log4j.properties属性配置文件。
1. 判断配置文件有没有重写?
/** Search for the properties file log4j.properties in the CLASSPATH. */ String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY,null); //public static final String DEFAULT_INIT_OVERRIDE_KEY = "log4j.defaultInitOverride";
publicstatic String getSystemProperty(String key, String def) { try { return System.getProperty(key, def); } catch(Throwable e) { // MS-Java throws com.ms.security.SecurityExceptionEx LogLog.debug("Was not allowed to read system property \""+key+"\"."); return def; } }
2. override为null或者为false时没有重写,然后从系统属性中查找key:log4j.configuration和log4j.configuratorClass属性。如果没有设置log4j.configuration属性,就查找log4j.xml,然后查找log4j.properties文件。使用方法:
if(configurationOptionStr == null) { url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE); if(url == null) { url = Loader.getResource(DEFAULT_CONFIGURATION_FILE); }
使用java2的线程上下文类加载器来查找资源,如果查找失败,则使用加载该类(loader)的类加载器来加载资源。
3.如果设置了log4j.configuration属性,则使用url形式读取,如果资源不是url,则从classpath获取资源:
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); }
4. 如果log4j.configuration属性为url形式:
// 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."); try { OptionConverter.selectAndConfigure(url, configuratorClassName, LogManager.getLoggerRepository()); } catch (NoClassDefFoundError e) { LogLog.warn("Error during default initialization", e); } } else { LogLog.debug("Could not find resource: ["+configurationOptionStr+"]."); }
参考文献:
1. http://www.2cto.com/kf/201207/139798.html - 深入Log4j源码之LoggerRepository和Configurator
2. http://logging.apache.org/log4j/1.2/manual.html
3. whatsmars.com
相关推荐
在深入学习Log4j源码时,我们可以看到以下几个关键部分: - **Logger类**:它是整个日志系统的主要入口,负责创建、获取和管理日志器实例。 - **Hierarchy类**:在Log4j 1.x中,Hierachy类负责管理Logger的层次结构...
《深入解析Log4j 2.11.0源码》 Log4j,作为Java领域最常用的日志框架之一,其2.11.0版本的发布为开发者提供了更加强大、高效和灵活的日志处理能力。源码包的获取,对于开发者深入理解其工作原理、定制化需求以及...
《深入解析log4j 1.2.15源码》 在软件开发领域,日志记录是一个不可或缺的环节,而log4j作为Java平台上最广泛使用的日志框架之一,其重要性不言而喻。本文将深入探讨log4j 1.2.15的源码,帮助开发者更好地理解其...
本教程将通过源码分析,深入讲解log4j的工作原理和使用方法。 **1. log4j的基本概念** - **Logger**: 日志记录器,是log4j的核心接口,用于生成不同级别的日志事件。 - **Level**: 日志级别,包括DEBUG、INFO、...
《深入理解Log4j 1.2.17:源码与JAR包解析》 在软件开发领域,日志记录是一项至关重要的任务,它帮助开发者跟踪程序运行状态,定位和解决问题。Log4j作为Apache组织的一个开源项目,是Java平台上最常用的日志框架之...
3. **在Eclipse中使用Log4j源码** - **导入源码**: 解压文件后,在Eclipse中选择“File” -> “Import” -> “Existing Projects into Workspace”,然后浏览到解压后的目录,导入项目。 - **编译与构建**: 确保...
Log4j是Apache组织开发的一款广泛使用的Java日志框架,版本1.2.15是其历史的一个稳定版本。这个源码包包含了Log4j的核心组件和相关配置,便于...对于Java开发者来说,理解并能灵活运用Log4j源码是一项重要的技能。
在深入研究`log4net`的源码之前,我们首先了解其基本架构和工作原理。 1. **日志层次结构** `log4net`遵循了日志记录的层次结构,定义了不同级别的日志事件,如DEBUG、INFO、WARN、ERROR和FATAL。源码中,这些级别...
《深入解析log4j-1.2.13源码》 Apache Log4j是Java平台上广泛使用的日志记录框架,其1.2.13版本的源码为我们提供了深入了解这个强大工具的机会。本文将围绕log4j的核心概念、设计模式、主要组件以及其实现细节进行...
**Log4j 1.2.8 源码解析** Log4j 是一个广泛使用...通过深入研究 Log4j 1.2.8 的源码,开发者不仅可以更好地掌握日志管理,还可以提升对 Java 多线程、反射、配置解析等技术的理解,为今后的软件开发提供强大的支持。
在深入分析`apache-log4j-1.2.17`源码之前,我们需要了解日志框架在软件开发中的基本作用和Log4j的一些核心特性。 1. **日志框架的作用** - 错误跟踪:记录程序运行过程中的异常信息,帮助开发者快速定位问题。 -...
本文将深入探讨如何进行`log4j`的源码二次开发,实现通过`DatagramSocket`发送日志消息,以及如何构建一个集中式的日志中心来收集和处理来自多个应用或模块的日志信息。 首先,我们需要了解`log4j`的基本架构。`log...
根据提供的文件信息,我们可以提炼出以下关于Log4j的详细知识点: 1. Log4j的版本兼容性 本手册适用的Log4j版本为1.2及之后的版本...如需深入掌握Log4j的使用和配置,建议阅读完整的《The Complete Log4j Manual》。
- **阅读源码**:通过阅读和理解测试源码,可以深入掌握Log4j2的工作原理和性能调优技巧。 - **动手实践**:自己编写测试用例,模拟不同的日志场景,对比不同配置下的性能差异。 通过这份"Log4j2效率测试源码",...
本文主要探讨Log4j2异步写日志的效率,通过源码分析和测试来展示其优势。首先,我们要理解Log4j2中的异步日志工作原理。默认情况下,Log4j2使用同步模式记录日志,即每个日志事件都会阻塞直到写入完成。然而,通过...
通过阅读源码,可以深入了解Log4j的工作原理,如何配置和定制日志系统,以及如何解决特定问题。源码中还包含了单元测试,这些测试可以作为使用Log4j功能的实例,帮助理解其内部机制。 使用Log4j的主要优点包括: 1...
【标题】"mybatis源码+练习代码+插件+log4j2+maven" 提供的资源包是一个综合的学习资料集合,旨在帮助用户深入理解MyBatis这一流行持久层框架,同时涵盖日志管理工具Log4j2和项目构建工具Maven。以下是这些组件的...
深入研究Log4j 1.2.16的源代码,你可以了解到如何实现日志事件的线程安全处理,以及如何优化日志性能,比如通过缓存日志输出格式来减少不必要的字符串连接操作。此外,源码中还包含了一些关键的类,如Category...
标题中的"SSH2+log4j源码"指的是在Java开发中常用的三个开源框架——Spring、Struts2和Hibernate的源代码,以及日志记录工具log4j的源码。这些框架是Java企业级应用开发的核心组件,对于理解Java Web应用的运行机制...
在《Log4j将System.out搞到log4j中输出四》这篇博文中,作者可能详细讨论了这些步骤,并可能分享了一些实战经验。通过学习这篇博文,读者可以更深入地了解如何在实际项目中实现这一转换,提升日志管理的效率。 总结...