java日志框架系列(2):logback框架详解

1.logback介绍

1.什么是logback

Logback 为取代 log4j 而生。

Logback 由 log4j 的创立者 Ceki Gülcü设计。以十多年设计工业级记录系统的经验为基础,所创建的 logback 比现有任何记录系统更快、占用资源更少,有时差距非常大。
Logback 提供独特而实用的特性,比如 Marker、参数化记录语句、条件化堆栈跟踪和强 大的事件过滤功能。以上列出的仅仅是 logbook 实用特性的一小部分。
对于自身的错误报告,logback 依赖状态(Status)对象,状态对象极大地简化了故障查找。你也许想在上下文中使用状态对象而不是记录。
Logback-core 附带了 Joran,Joran 是个强大的、通用的配置系统,你可以在自己的项目里使用 Joran 以获得巨大的作用。

2.logback组成部分

logback由3个模块组成:core、classic、access。
这三个模块分别对应3个jar:logback-core.jar、logback-class.jar、logback-access.jar。
core模块:是classic模块与access模块的基础。
classic模块: 直接实现了slf4j框架的API,因此你可以在logback与其他日志系统如log4j之间进行相互切换;扩展了core模块,classic模块相当于log4j的显著改进版。
access模块:该模块与Servlet容器集成,提供http访问记录功能。
在结合slf4j与logback时,logback只需要core与classic模块。

3.Logger、Appender和Layout

Logback建立在3个主要的类之上:Logger、Appender、Layout。这三个组件协同工作,使开发者可以按照消息类型 和级别来记录消息,还可以在程序运行期内控制消息的输出格式和输出目的地。

Logger类是logback-classic模块的一部分,而Appender和Layout接口来自于logback-core。作为一个多用途模块,logback-core不包含任何logger。

slf4j框架的logger接口(slf4j.Logger)只有一些获取logger属性及打印的方法;而logback框架的Logger类(ch.qos.logback.classic.Logger)实现了slf4j.Logger接口并且添加了一些可以设置logger属性的方法(比如设置有效级别setLevel方法)。

因此,如果你想通过代码设置Logger的属性,请使用logback-classic.jar文件中的ch.qos.logback.classic.Logger类,否则使用slf4j-api.jar文件中的org.slf4j.Logger

 

1.logger上下文LoggerContext

日志系统重要的优点是:禁用特定记录语句的同时却不妨碍输出其他语句。这个优点源于记录隔离

记录隔离:所有各种记录语句的隔离,是根据开发者选择的条件而进行分类的。在logback-classic中,这种分类是logger固有的。各个 logger 都被关联到一个 LoggerContext, LoggerContext 负责制造logger,也负责以树结构排列各 logger

2.logger命名规则

logger命名层次:如果 logger 的名称带上一个点号后是另外一个 logger 的名称的前缀,那么,前者就被称为后者的祖先。如果 logger 与其后代 logger 之间没有其他祖先,那么,前者就被称为子logger 之父。
实例:
 名为“com.foo”的logger是名为“com.foo.bar”之父。
根logger位于logger等级最顶端,根logger的特别之处是它是每个层次等级的共同始祖。如同其他logger一样,根logger可以通过其名称取得,代码如下:
Logger rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);

3.Logger的有效级别(Level)

有效级别就是继承级别

Logger 可以被分配级别。 级别包括:TRACE、DEBUG、INFO、WARN 和 ERROR,定义于 ch.qos.logback.classic.Level 类。注意在 logback 里,Level 类是 final 的,不能被继承,Marker 对象提供了更灵活的方法。
注意如果logger没有被分配级别,那么它将从有被分配级别的最近的祖先那里继承级别。更正式的说:名称为L的logger的有效级别等于其层次等级里的第一个非null级别,顺序是从L开始,向上直至根logger。
强烈注意:为确保所有 logger 都能够最终继承一个级别,根 logger 总是有级别,默认情况下,这个级别是 DEBUG。
下面通过4个实例来理解级别继承的规则:
下面的4个例子包含各种分配级别值和根据级别继承规则得出的最终有效(继承)级别。
例1:
java日志框架系列(2):logback框架详解_第1张图片

 在例1中,仅根logger被分配了级别。级别值DEBUG被其他logger(比如X、X.Y、X.Y.Z)继承。

例2:

java日志框架系列(2):logback框架详解_第2张图片

在例2中,所有级别都被分配了级别,因此级别继承不发挥作用。

例3:
java日志框架系列(2):logback框架详解_第3张图片

在例 3 中,根 logger、X 和 X.Y.Z 分别被分配了 DEBUG、INFO 和 ERROR 级别。X.Y 从其父 X 继承级别。

例4:
java日志框架系列(2):logback框架详解_第4张图片

在例4中,根 logger 和 X 分别被分配了 DEBUG 和 INFO 级别。X.Y 和 X.Y.Z 从其最近的父 X 继承级别,因为 X 被分配了级别。

 4.日志打印方法和基本选择规则

1.日志打印方法

根据定义,打印方法决定记录请求级别

打印方法类别如下:

java日志框架系列(2):logback框架详解_第5张图片

接下来通过实例 1来理解“打印方法决定记录请求级别”这句话。

实例1:

如果L是一个logger实例,那么语句L.info("message")是一条级别为INFO的记录语句。

注意:记录请求的级别在高于或等于其 logger 的有效级别时被称为被启用,否则,称为被禁用。

2.日志基本选择规则

级别排序:TRACE < DEBUG < INFO < WARN < ERROR

基本选择规则:

如果记录请求级别为p,其logger的有效级别为q,那么只有当p>=q时,该请求才会被执行。

记录请求级别就是指调用logger的打印方法的类别(比如debug方法、info方法等);有效级别是在配置文件中设置的级别。

下表显示了选择规则是如何工作的:

java日志框架系列(2):logback框架详解_第6张图片

 5.获取logger对象

用同一名字作为参数调用 LoggerFactory.getLogger 方法所得到的永远都是同一个 logger 对象的引用。
java日志框架系列(2):logback框架详解_第7张图片

 logback可以以任何顺序创建和配置logger。特别注意的是即使“父”logger是在其后代初始化之后才初始化的,它仍将查找并链接到其后代们

通常是在程序初始化时对logback环境进行配置。推荐用配置文件类进行配置。

Logback 简化了 logger 命名,方法是在每个类里初始化 logger,以类的全限定名作为logger 名。这种定义 logger 的方法即有用又直观。由于记录输出里包含 logger 名,这种命名方法很容易确定记录消息来源。Logback 不限制 logger 名,你可以随意命名 logger。然而, 目前已知最好的策略是以logger所在类的名字作为logger的名称

6.Appender(输出目的地)

 logback允许打印记录请求到多个目的地。在logback中,一个输出目的地成为一个Appender。

Appender分类:控制台、文件、远程套接字服务器、mysql、PostreSQL、Oracle和其他数据库、JMS和远程UNIX Syslog守护进程等。

一个logger可以被关联多个appender。

方法 addAppender 为指定的 logger 添加一个 appender。 对于 logger 的每个启用了的记录请求,都将被发送到 logger 里的全部 appender 更高等级的 appender。换句话说,appender叠加性地继承了logger 的层次等级。例如,如果根 logger 有一个控制台 appender,那么所有启用了的请求都至少会被打印到控制台。如果 logger L 有额外的文件 appender,那么,L 和L 后代的所有启用了的请求都将同时打印到控制台和文件。设置 logger 的 additivity 为 false,则可以取消这种默认的 appender 累积行为。
上述所讲的内容就是appender叠加性,简单概括如下:
Appender叠加性:名为L的Logger的记录语句的输出会发送给L及其祖先的全部appender。这就是“appender叠加性”的含义。
然而,如果 logger L 的某个祖先 P 设置叠加性标识为 false,那么,L 的输出会发送给L 与 P 之间(含 P)的所有 appender,但不会发送给 P 的任何祖先的 appender。
注意:Logger的叠加性默认为true。
下面通过实例讲解一下Appender的叠加性:
实例1:
java日志框架系列(2):logback框架详解_第8张图片

 7.Layout(输出信息的格式)

有些用户希望不仅可以定制输出目的地,还可以定制输出格式。这时为 appender 关联一个 layout 即可。Layout 负责根据用户意愿对记录请求进行格式化,appender 负责将格式化后的输出发送到目的地。PatternLayout 是标准 logback 发行包的一部分,允许用户按照类似于 C 语言的 printf 函数的转换模式设置输出格式。
例如,转换模式"%-4relative [%thread] %-5level %logger{32} - %msg%n"在 PatternLayout里会输出形如:

 

 

8.参数化记录

因为 logback-classic 里的 logger 实现了 SLF4J 的 Logger 接口,某些打印方法可接受多个参数。这些不同的打印方法主要是为了在提高性能的同时尽量不影响代码可读性。

 特别强调:在logback中允许在记录请求方法中使用大括号“{}”作为占位符

 下面通过一个实例1讲解一下:

实例1:

假设entry是一个对象,而你需要使用记录请求输出这个对象的信息,那么你可以这样写:

在评估是否作记录后,仅当需要作记录时,logger 才会格式化消息,用 entry 的字符串值替换"{}"。换句话说,当记录语句被禁用时,这种方法不会产生参数构造所带来的性能消耗。
 

 9.工作原理

 logback框架在用户调用了logger对象的记录请求方法时会做哪些事情呢?

1.logback执行的相应操作:

步骤一:取得过滤链(filter chain)的判定结果
  如果 TurboFilter 链存在,它将被调用。Turbo filters 能够设置一个上下文范围内的临界值,这个临界值或者表示过滤某些与信息有关(比如 Marker、级别、Logger、消息)的特定事件,或者表示与每个记录请求相关联的 Throwable。 如果过滤链的结果是 FilterReply.DENY,则记录请求被抛弃。如果结果是 FilterReply.NEUTRAL,则继续下一步,也就是第二步。如果结果是 FilterReply.ACCEPT,则忽略过第二步,进入第三步
步骤二:应用基本选择规则
  Logback 对 logger 的有效级别与请求的级别进行比较。如果比较的结果是记录请求被禁用,logback 会直接抛弃请求,不做任何进一步处理。否则,继续下一步。
步骤三:创建LoggingEvent对象
  记录请求到了这一步后,logback 会创建一个 ch.qos.logback.classic.LoggingEvent 对象,该对象包含所有与请求相关的参数,比如请求用的 logger、请求级别、消息、请求携带的异常、当前时间、当前线程、执行记录请求的类的各种数据,还有 MDC。注意有些成员是延迟初始化的,只有当它们真正被使用时才会被初始化。MDC 用来为记录请求添加额外的上下文信息。之后的章节会讨论 MDC。
步骤四:调用appender
  创建了 LoggingEvent 对象后,logback 将调用所有可用 appender 的 doAppend()方法,这就是说,appender 继承 logger 的上下文。所有 appender 都继承 AppenderBase 抽象类,AppenderBase 在一个同步块里实现了doAppend 方以确保线程安全。AppenderBase 的 doAppender()方法也调用 appender关联的自定义过滤器,如果它们存在的话。自定义过滤器能被动态地关联到任何appender,另有章节专门讲述它。
步骤五:格式化输出
  那些被调用了的 appender 负责对记录事件(LoggingEvent)进行格式化。然而,有些但不是全部 appender 把格式化记录事件的工作委托给 layout。Layout 对LoggingEvent 实例进行格式化,然后把结果以字符串的形式返回。注意有些appender,比如 SocketAppender,把记录事件进行序列化而不是转换成字符串,所以它们不需要也没有 layout。
步骤六:发送记录事件
  记录事件被格式化后,被各个 appender 发送到各自的目的地。

2.原理流程图

java日志框架系列(2):logback框架详解_第9张图片

 

10.性能

我们还是要注意记录对程序的一些性能影响的。

1.记录被关闭时的记录性能

  可以将根logger的级别设为最高级的Level.OFF,就可以彻底关闭记录。

2.当记录启用时,判断是否进行记录的性能

  在 logback 中,logger 在被创建时就明确地知道其有效级别(已经考虑了级别继承)。当父 logger 的级别改变时,所有子 logger 都会得知这个改变。因此,在根据有效级别去接受或拒绝请求之前,logger 能够作出准即时判断,不需要咨询其祖先。

3.实际记录(格式化和写入输出设备)

  性能消耗包括格式化输出和发送到目的地。

 

你可能感兴趣的:(java日志框架系列(2):logback框架详解)