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:

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

例2:

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

例3:

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

例4:

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

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

1.日志打印方法

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

打印方法类别如下:

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

实例1:

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

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

2.日志基本选择规则

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

基本选择规则:

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

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

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

5.获取logger对象

用同一名字作为参数调用 LoggerFactory.getLogger 方法所得到的永远都是同一个 logger 对象的引用。

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:

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.原理流程图

10.性能

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

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

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

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

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

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

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

java日志框架系列(2):logback框架详解的更多相关文章

  1. Java容器解析系列(10) Map AbstractMap 详解

    前面介绍了List和Queue相关源码,这篇开始,我们先来学习一种java集合中的除Collection外的另一个分支------Map,这一分支的类图结构如下: 这里为什么不先介绍Set相关:因为很 ...

  2. 深入理解JAVA I/O系列二:字节流详解

    流的概念 JAVA程序通过流来完成输入/输出.流是生产或消费信息的抽象,流通过JAVA的输入输出与物理设备链接,尽管与它们链接的物理设备不尽相同,所有流的行为具有相同的方式.这样就意味一个输入流能够抽 ...

  3. Java容器解析系列(5) AbstractSequentialList LinkedList 详解

    AbstractSequentialList为顺序访问的list提供了一个骨架实现,使实现顺序访问的list变得简单; 我们来看源码: /** AbstractSequentialList 继承自 A ...

  4. 《手把手教你》系列技巧篇(四十二)-java+ selenium自动化测试 - 处理iframe -下篇(详解教程)

    1.简介 经过宏哥长时间的查找,终于找到了一个含有iframe的网页.所以今天这一篇的主要内容就是用这个网页的iframe,宏哥给小伙伴或者童鞋们演示一下,在处理过程中遇到的问题以及宏哥是如何解决的. ...

  5. logback的使用和logback.xml详解,在Spring项目中使用log打印日志

    logback的使用和logback.xml详解 一.logback的介绍 Logback是由log4j创始人设计的另一个开源日志组件,官方网站: http://logback.qos.ch.它当前分 ...

  6. ORM框架对比以及Mybatis配置文件详解

    ORM框架对比以及Mybatis配置文件详解 0.数据库操作框架的历程 (1) JDBC ​ JDBC(Java Data Base Connection,java数据库连接)是一种用于执行SQL语句 ...

  7. Django框架 之 ORM查询操作详解

    Django框架 之 ORM查询操作详解 浏览目录 一般操作 ForeignKey操作 ManyToManyField 聚合查询 分组查询 F查询和Q查询 事务 Django终端打印SQL语句 在Py ...

  8. laravel框架的中间件middleware的详解

    本篇文章给大家带来的内容是关于laravel框架的中间件middleware的详解,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. laravel中间件是个非常方便的东西,能将一些逻辑 ...

  9. 数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解

    数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解 对数组有不了解的可以先看看我的另一篇文章,那篇文章对数组有很多详细的解析,而本篇文章则着重讲动态数组,另一篇文章链接 ...

  10. 《手把手教你》系列技巧篇(五十)-java+ selenium自动化测试-字符串操作-上篇(详解教程)

    1.简介 自动化测试中进行断言的时候,我们可能经常遇到的场景.从一个字符串中找出一组数字或者其中的某些关键字,而不是将这一串字符串作为结果进行断言.这个时候就需要我们对字符串进行操作,宏哥这里介绍两种 ...

随机推荐

  1. java集合类-集合框架体系

    集合框架体系 集合框架体系是由Collection.Map和 Iterator(迭代器) 实线边框的是实现类,折线边框的是抽象类,而点线边框的是接口 Collection体系 Set接口:元素无序且不 ...

  2. Integer int auto-boxing auto-unboxing ==

    Auto-boxing 自动装箱 Auto-unboxing 自动拆箱 == 相等 1.new出来的对象,除非遇到了拆箱的情况,肯定不相等. 因为new对象之前需要在JVM堆中提供空间,所以new出来 ...

  3. Ubuntu 14.04 更换为阿里云源

    #备份sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak#编辑sudo vim /etc/apt/sources.list,清空后,加入以下 ...

  4. 十六、程序包管理之 rpm

    c语言程序的构建过程 1.程序源代码 --> 预处理 --> 编译 --> 汇编 --> 链接--> 可执行程序 开放源码:就是程序码,文本格式的源代码,写给人类看的程序 ...

  5. NTP 协议介绍

    NTP协议 NTP(Network Time Protocol,网络时间协议)是由RFC 1305定义的时间同步协议,用来在分布式时间服务器和客户端之间进行时间同步.NTP基于UDP报文进行传输,使用 ...

  6. django中安装pillow ValueError: zlib is required unless explicitly disabled using --disable-zlib, aborting

    在windows系统上,使用  pip install pillow安装pillow时 报错 在使用 easy_install Pillow 方式安装成功,默认是最高版本 如果需要在安装时,指定安装版 ...

  7. sql注入笔记-sqlite

    1. SQLite 1. 常用语句及基本结构 (1)sqlite因为其比较简易每个db文件就是一个数据库,所以不存在information_schema数据库,但存在类似作用的表sqlite_mast ...

  8. vagrant系列三:vagrant搭建的php7环境

    原文:https://blog.csdn.net/hel12he/article/details/51107236 前面已经把vagrant的基础知识已经基本过了一遍 了,相信只要按着教程来,你已经搭 ...

  9. HRNET网络结构简单分析

    hrnet相关的两篇文章 CVPR2019   Deep High-Resolution Representation Learning for Human Pose Estimation High- ...

  10. List和Set 总结

    一 List三个子类的区别和应用场景 Vector:底层是数组,查询快,增删慢 Arraylist:底层是数组,查询块,增删慢 LinkedList:底层是链表,查询慢,增删快 效率: Vector: ...