一、日志框架类型
- log4j1
- log4j2
- java util logging
- commons logging
- slf4j(门面模式)
二、日志系统的分类
日志系统可分为两类。
- 一类只提供接口不提供实现,如 Apache Commons Logging 和 slf4j。这类日志系统需要和具体的日志系统一起使用,优点是可以自由切换不同的日志实现系统。(桥接模式)
- 一类是具体的日志系统实现。如 log4j1.x、logback、log4j2.x、java.util.logging 等
三、slf4j和其他日志系统的关系
二、日志框架的优点
1、logback相比与log4j1的优点
- 性能的提升。Logback 的内核重写了,在某些特定的场景上性能提升 10 倍以上,同时所需的内存更加少。
- 非常充分的测试。Logback经过了几年,数不清小时的测试,与log4j1的测试相比不在同一个级别,因此 logback 更稳定可靠。
- 非常自然的实现了slf4j。而log4j1 和 slf4j 一起使用需要适配层。
- 自动重新加载配置文件。当配置文件修改了,Logback-classic能自动重新加载配置文件,不需要重启服务器。
- 优雅地从I/O错误中恢复。如果一个文件服务器临时宕机,你不需要重启应用,日志功能就能正常工作。
- 配置文件可适应多环境。通常在开发、测试、生产环境,需要变换日志的配置文件。而在不同环境下,配置文件只有一些很小的不同,为了避免重复,logback支持使用,和进行条件处理,同一个配置文件就可以在不同的环境中使用了。
- 过滤器。生产环境中,有时需要低级别的日志来查明问题,在log4j1 中,只有降低日志级别,这样的话会打出大量的日志而影响性能。而 logback 中,你可以继续保持那个日志级别而除掉某种特殊情况。
- 自动压缩归档日志文件。压缩通常是异步执行的,所以即使是很大的日志文件,你的应用都不会因此而被阻塞。
- 通过配置自动去除旧的日志文件。
log4j2的优点
- 可配置的审计型日志。log4j1和logback在重新配置的时候会丢失之前的日志文件,log4j2不会。log4j2自身内部报的exception会被发现,但是log4j1和logback不会。
- 下一代异步logger。log4j 2是基于LMAX Disruptor库的(一个用于在线程间通信的高效低延迟且简单的框架),在多线程场景下,它的日志吞吐量比其他框架多出10倍以上。
- 可运行在免垃圾收集模式。这样可以减少垃圾收集器的压力和提供更好的响应时间性能。
- 插件式结构。可根据自己的需要扩展框架,可以实现自己的logger、appenders、filters、layouts、lookups 和pattern converters,而无需对log4j2做任何更改。
- Java 5的并发性。log4j2利用Java 5中的并发特性支持,尽可能地执行最低层次的加锁,log4j1中存留的死锁问题,很多已经在logback中解决,但logback的很多类仍然保持着较高层次的同步。如果你的程序仍然饱受内存泄漏的折磨,请毫不犹豫地试一下log4j2。
三、log4j2框架的结构
1、 LoggerContext(日志上下文)
LoggerContext在日志系统中扮演锚点的角色。依赖于具体环境,在一个应用程序中有多个活动的loggercontext是有可能的。在同一LoggerContext下,log system是互通的。
2、 Configuration(配置)
一个LoggerContext关联一个Configuration,Configuration包含了所有的Appenders(输出器)、上下文范围内的Filter(过滤器)、LoggerConfigs以及StrSubstitutor的引用。在重配置期间,新与旧的Configuration将同时存在。当所有的Logger对象都被重定向到新的Configuration对象后,旧的Configuration对象将被停用和丢弃。
3、 Logger(日志记录器)
程序中记录日志时,首先需要获取一个日志记录器对象。如前所述,Logger 是通过调用LogManager.getLogger方法获得的。记录器对象通常有一个name并和一个LoggerConfig 相关联。当Configuration改变时,Logger将会与另外的LoggerConfig相关联,从而改变这个Logger的行为。
一般使用当前 java 类的名称或所在包的名称作为记录器对象的名称。这是一个很有用且很直接的Logger命名方式,使用这种方式命名可以很容易的定位这个log message产生的类的位置。当然,log4j也支持任意String的命名方式以满足开发者的需要。不过,使用类名来定义Logger名仍然是最为推崇的一种Logger命名方式。
获得Logger时,使用相同的名称参数调用getLogger方法将获得同一个Logger对象的引用。
4、 LoggerConfig(日志配置器)
LoggerConfig是Logger的配置对象,一个LoggerConfig可以绑定多个不同的Appender。只有定义了LoggerConfig并引入的appender,appender才会生效。LoggerConfig包含了一组过滤器,LogEvent在被传往Appender之前将先经过这些过滤器。
LoggerConfig有级别配置,低于配置级别的日志消息将不会记录下来。Log4j2中,级别由高到低如下所列:
- FATAL:用于立马要被注意的情形。
- ERROR:通用的 bug。
- WARN:不一定是 bug ,但想要知道的这个情况。
- INFO:一般的诊断信息。
- DEBUG:低层次的调试信息。
- TRACE:展现程序执行轨迹。
LoggerConfig有自己的名称,root LoggerConfig除外。名称有层次结构,与包层次结构相对应,存在着继承关系。如“com.myapp”是 “com.myapp.action”的父包。若 “com.myapp.action”没有设定级别,则按照层次关系往上查找,直到找到一个设置了级别的LoggerConfig,继承其级别。如果没有找到,则使用根LoggerConfig(root)配置的级别。root LoggerConfig 是 LoggerConfig 层次结构的最顶层。
5、 Filter(过滤器)
与防火墙过滤的规则相似,log4j2的过滤器也将返回三类状态:Accept(接受), Deny(拒绝) 或Neutral(中立)。其中,Accept意味着不用再调用其他过滤器了,这个LogEvent将被执行;Deny意味着忽略这个event,并将此event的控制权交还给过滤器的调用者;Neutral则意味着这个event应该传递给别的过滤器,如果再没有别的过滤器可以传递了,那么就由现在这个过滤器来处理。
6、 Layout(格式化器)
对记录器所记录的文本进行格式化。
7、 Appender(输出器)
日志输出目的地。如控制台、文件、远程socket server、数据库等。
四、log4j2框架启动
1、加载到org.apache.logging.log4j.LogManager的静态块初始化org.apache.logging.log4j.spi.LoggerContextFactory
(1)通过spi机制加载多个备选项,通过org.apache.logging.log4j.util.ProviderUtil类加载文件META-INF/log4j-provider.properties 【当存在多个factory时基于优先级确定使用哪个】
LoggerContextFactory = org.apache.logging.log4j.core.impl.Log4jContextFactory
Log4jAPIVersion = 2.1.0
FactoryPriority= 10
View Code
- 如果未加载配置文件,则默认初始化为:org.apache.logging.log4j.simple.SimpleLoggerContextFactory
- 如果加载多个配置文件,则选择优先级最高的那个配置,作为LoggerContextFactory的实现类
2、org.apache.logging.log4j.core.impl.Log4jContextFactory的初始化过程
- log4j2.component.properties该配置文件是通过org.apache.logging.log4j.util.LoaderUtil类从项目的resources目录下查找配置的
- 初始化:org.apache.logging.log4j.core.selector.ContextSelector接口实现。 也是基于配置文件 log4j2.component.properties 查找是否存在自定义的配置组件(组件名:Log4jContextSelector)。如果不存在,默认实现为:org.apache.logging.log4j.core.selector.ClassLoaderContextSelector
- 初始化:org.apache.logging.log4j.core.util.ShutdownCallbackRegistry接口实现。也是基于配置文件log4j2.component.properties 查找是否存在自定义的配置组件(组件名:log4j.shutdownCallbackRegistry)。如果不存在,默认实现为:org.apache.logging.log4j.core.util.DefaultShutdownCallbackRegistry
- ContextSelector作用:
- ShutdownCallbackRegistry的作用:
3、Logger logger= LogManager.getLogger(LogManagerTest.class); 时,会初始化LoggerContext对象。LoggerContext会执行start方法。start方法,会重新按配置生成org.apache.logging.log4j.core.config.Configuration
- org.apache.logging.log4j.core.config.ConfigurationFactory会初始化Configuration对象
- 基于配置文件 log4j2.component.properties 查找是否存在自定义的配置组件(组件名:log4j.configurationFactory)。
- 通过org.apache.logging.log4j.core.config.plugins.util.PluginManager加载项目jar包中所有factory对象。
org.apache.logging.log4j.core.config.json.JsonConfigurationFactory
org.apache.logging.log4j.core.config.xml.XmlConfigurationFactory
org.apache.logging.log4j.core.config.yaml.YamlConfigurationFactory
org.apache.logging.log4j.core.config.properties.PropertiesConfigurationFactory
org.springframework.boot.logging.log4j2.SpringBootConfigurationFactory
com.meituan.inf.xmdlog.config.XMDConfigurationFactory