Log4j2使用手册
一.Log4j2介绍
Log4j1.x 被广泛应用于应用程序,但是近年发展明显放缓,因为要维持较老java版本的使用,使得log4j1.x 的发展更困难。而作为其代替品, slf4j/logback 做出了许多必要改进,为什么还需要log4j2? 主要有以下几个原因 :
(1)Log4j2被设计用作审计日志框架, log4j 和logback 在重载配置时,都会丢失日志时间,而log4j2不会。Logback中appenders中的异常对于应用来说是不可见的,log4j2可以配置异常向应用渗透。
(2)Log4j2 包含基于 LMAX Disruptor library 的下一代无锁 Asynchronous Loggers ,在多线程环境下, Asynchronous Loggers 相比slf4j / logback 提高了10倍以上的吞吐量,并且有着更低的延时。
(3)Log4j2的插件机制,使得在不需要修改框架的情况下,通过添加 Appenders, Filters, Layouts, Lookups 轻松扩展框架。
(4)简单的插件配置,无需指定具体类名即可在configuration 中配置插件。
(5)支持自定义日志级别,可以在代码或者 configuration 中自定义日志级别。
(6)支持lambda表达式,java8的应用可以在请求日志级别启用时使用 lambda表达式懒构建一个日志消息,不需要显示的日志级别检查,使得代码更简洁。
(7)支持消息对象,消息允许支持有趣和复杂的结构,传递到日志记录系统,并且可以高效的操作。用户可以自由创建消息类型和 编写Layouts, Filters and Lookups 来操作这些消息。
(8)Log4j1在Appenders 上支持 Filters 。 logback增加了 TurboFilters ,允许在日志事件在处理前进行过滤。Log4j2可以配置 Filters 在Logger后者Appender 前运行。
(9)许多Logback的Appenders 不接受Layout,并且只能按照固定格式发送日志数据。大部分 log4j2 接收Layout配置,允许日志数据按照任何所需格式传输。
(10)Log4j1与logback 的 Layouts 是返回一个String 类型,这可能导致一些编码问题。Log
4j2使用了简单的方式:返回一个 byte 数组。这以为着Layouts 可以用在几乎任何appenders ,而不仅仅是 写入OutputStream。
(11)Syslog appender 支持 TCP与UDP,以及BSD syslog 和 RFC5424格式。
(12)Log4j2 得益于java5的并发支持,将锁的可能降到最低水平。Log4j1 有已知的死锁问题,Logback也需要使用synchronization 来保持在相当高的锁级别。
(13)Apache 开源
二.Log4j2架构
1.Log4j2类图
应用程序调用Log4j API 时需要向LogManager 传入一个特定的名称来获取一个Logger实例。LogManager 会定位一个合适的 LoggerContext然后从中获取 Logger 。如果 Logger必须新建,那么与之关联的 LoggerConfig 遵守如下规则 : (1)与Logger名称完全相同。(2)父Logger 的名称。(3)Root LoggerConfig 。LoggerConfig 对象是根据 configuration 配置中的Logger 声明创建的。LoggerConfig 又与处理LogEvents 的 LoggerConfig 关联。
2.日志层次
logging API 相比于 纯粹的System.out.println 最重要的不同是 : logging API 可以禁用一些log语句输出的同时允许其他一些语句块输出。这种能力建立在开发者按照一定规则将日志分类的基础上。
Log4j1.x 的层次关系是通过 Loggers 之间的关系保持的。而 Log4j2.x 是通过 LoggerConfig 梅津美治郎对象来维持这种层次关系的。
Loggers 与 LoggerConfigs 都是带名称的实体。Logger名称是大小写敏感的,并且符合如下命名层级规则:
一个LoggerConfig 的名字是另外一个 LoggerConfig 名字 加上 . 和一些后缀字符。 那么这个 LoggerConfig 是另外的 LoggerConfig 的子类。 类似于 java 的 package回车键符号 路径。 例如 : 一个 名称为 "com.foo"的 LoggerConfig 是 一个名称为 "com.foo.Bar" 的LoggerConfig 的父类。类似的, “java” 是"java.util"的父类和 "java.util.Vector" 的祖先类 。 开发人员对这样的命名方案应该很熟悉。
Root LoggerConfig 居于 LoggerConfig 分层的顶层。Root LoggerConfig 总是存在于每个 LoggerConfig的层次中 。任何一个与root LoggerConfig相关联的Logger可以通过如下方式获得:
Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
也可以用如下简便方式:
Logger logger = LogManager.getRootLogger();
其他的 Logger 可以使用 的静态方法根据传入的名称获得。
3.LoggerContext
LoggerContext 作为日志系统的锚点(用于根据日志名称定位日志输出信息的Logger),在不同的环境中,一个应用系统中可能存在多个有效的 LoggerContexts ,
4.Configuration
每个 LoggerContext 有一个有效的Configuration 。 Configuration 包括所有的 Appenders,上下文过滤器,LoggerConfigs 与 包含StrSubstitutor的引用信息。在配置重载期间,两个Configuration 共存,一旦所有的 Logger重定向到新的Configuration ,旧的Configuration 将停用和丢弃。
5.Logger
Loggers 是调用 静态方法创建的。Logger 本身不直接执行动作。它只有一个名称,并于一个LoggerConfig相关联。它继承自 AbstractLogger ,当 configuration 被修改时,Loggers 将关联修改后的 LoggerConfig,从而改变这个 Loggers 尿酸为什么会高的行为。
获取Loggers:
使用相同的名称调用 Logger 方法,总是返回完全相同的Logger 对象。
例如:
Logger x = LogManager小学五年级日记.getLogger("wombat");
Logger y = 示波器维修LogManager.getLogger("wombat");
涕零如雨X和y 指向完全相同的 Logger 对象。
Log4j 配置环境通常是在应用程序初始化时完成的。最好的方式是读取配置文件。
Log4j很容易通过类名来命名,这可以在每个类初始化的时候完成Logger 的初始化,Logger 的名称就等于类的完整路径,这是一个定义Logger的简单有效的方式。当为日志文件输出具有 Logger 名称的日志时,这种命名策略可以很容易看出一个 日志消息的来源。当然这只是一种比较常见的日志命名方式,log4j并没有对此进行限制,开发人员可以按照需求进行命名。
因为使用类名命名 Logger是一个习惯用法。一个便利的方法是使用Logger() 来获取类的全路径名称的 Logger。
目前为止,使用类名来作为Logger 的名称是最好的方式。
6.LoggerConfig
当Logger对象在 logging configuration 中被定义时, LoggerConfig对象同时被创建。LoggerConfig 包含一组Filters 来过滤传递到 Appenders 的LogEvent 。LoggerConfig使用一组Appenders 用来处理这些事件。
Log Levels
LoggerConfigs 被分配一个日志级别,包括 : TRACE, DEBUG, INFO, WARN, ERROR, FATAL 。 Log4j 2 也支持自定义日志级别,另一种获得更多日志粒度的方式是使用 Markers 。
Log4j1 与logback 都有日志级别继承的概念。在Log4j2中,因为 Loggers 和LoggerConfigs是2个不同的对象,所以这个概念的实现有所不同。但是因为每个Loggers都关联一个相应的 LoggerConfig, 所以最终效果是相同的。
如果一个 root LoggerConfig 没有配置日志级别,将分配一个默认级别。
Logger Name | Assigned LoggerConfig | LoggerConfig Level | Logger Level |
root | root | DEBUG | DEBUG |
X | root | DEBUG | DEBUG |
X.Y | root | DEBUG | DEBUG |
X.Y.Z | root | | |
Example 1 |
| | | |
在 Example1 中, 仅配置了root logger 与其日志级别,所有的Loggers 都会引用 root LoggerConfig ,并使用其日志级别。
垂柳简笔画
Logger Name | Assigned LoggerConfig | LoggerConfig Level | Level |
root | root | DEBUG | DEBUG |
X | X | ERROR | ERROR |
X.Y | X.Y | INFO | INFO |
X.Y.Z | X.Y.Z | WARN | WARN |
Example 2 |
| | | |
在Example2中, 每个Logger 都有其对应的 LoggerConfig 和相应的日志级别。
Logger Name | Assigned LoggerConfig | LoggerConfig Level | Level |
root | root | DEBUG | DEBUG |
X | X | ERROR | ERROR |
X.Y | X | ERROR | ERROR |
X.Y.Z | X.Y.Z | WARN | WARN |
Example 3 |
| | | |
在 Example3 中,Logger root, X 和X.Y.Z 都有与名称完全匹配的LoggerConfig 配置,而 Logger X.Y 没有与其命名匹配的 LoggerConfig 现代诗手抄报,所以使用拥有最长匹配度的 X 的LoggerConfig 。