Logback源码分析

在日常开发中经常通过打印日志记录程序执行的步骤或者排查问题,如下代码类似很多,但是,它是如何执行的呢?

package chapters; import org.slf4j.Logger; import org.slf4j.LoggerFactory; // 省略... Logger logger = LoggerFactory.getLogger(LogbackTest.class); logger.info(" {} is best player in world", "Greizmann");

本文以Logback日志框架来分析以上代码的实现。

slf4j

如今日志框架常用的有log4j、log4j2、jul(common-log)以及logback。假如项目中用的是jul,如今想改成用log4j,如果直接引用java.util.logging包中Logger,需要修改大量代码,为了解决这个麻烦的事情,Ceki Gülcü 大神开发了slf4j(Simple Logging Facade for Java) 。slf4j 是众多日志框架抽象的门面接口,有了slf4j 想要切换日志实现,只需要把对应日志jar替换和添加对应的适配器。

Logback源码分析

图片来源: 一个著名的日志系统是怎么设计出来的?

从图中就可以知道我们开始的代码为什么引 slf4j 包。在阿里的开发手册上一条

强制:应用中不可直接使用日志系统(log4j、logback)中的 API ,而应依赖使用日志框架 SLF4J 中的 API 。使用门面模式的日志框架,有利于维护和各个类的日志处理方式的统一。

Logback 实现了 SLF4J ,少了中间适配层, Logback也是Ceki Gülcü 大神开发的。

Logger & Appender & Layouts

Logback 主要的三个类 logger,appender和layouts。这三个组件一起作用可以满足我们开发中根据消息的类型以及日志的级别打印日志到不同的地方。

Logger

ch.qos.logback.classic.Logger类结构:

Logback源码分析

Logger 依附在LoggerContext上,LoggerContext负责生产Logger,通过一个树状的层次结构来进行管理。Logger 维护着当前节点的日志级别及level值。logger按 "." 分代(层级),日志级别有继承能力,如:名字为 chapters.LogbackTest 如果没有设置日志级别,会继承它的父类chapters 日志级别。所有日志的老祖宗都是ROOT名字的Logger,默认DEBUG级别。当前节点设置了日志级别不会考虑父类的日志级别。Logger 通过日志级别控制日志的启用和禁用。日志级别 TRACE < DEBUG < INFO < WARN < ERROR

接下来我们结合配置文件看一下Logger属性对应的配置标签:

<configuration> <turboFilter> <MDCKey>username</MDCKey> <Value>sebastien</Value> <OnMatch>ACCEPT</OnMatch> </turboFilter> <appender> <file>/Users/wolf/study/logback/logback-examples/myApp.log</file> <encoder> <pattern>%msg%n</pattern> </encoder> </appender> <logger level="DEBUG"></logger> <root> <appender-ref ref="FILE"/> </root> </configuration>

name:logger 标签中 name 属性值。

level:logger 标签中 level 属性值。

parent:封装了父类 "chapters",以及"chapters"的父类“ROOT”的logger对象。

aai:appender-ref 标签,及这里对应 FileAppender 的实现类对象。如果没有appender-ref标签该值为null。

loggerContext:维护着过滤器,如 turbo 过滤器等。

Appender

Appender 作用是控制日志输出的目的地。日志输出的目的地是多元化,你可以把日志输出到console、file、remote socket server、MySQL、PostgreSQL、Oracle 或者其它的数据库、JMS、remote UNIX Syslog daemons 中。一个日志可以输出到多个目的地。如

<configuration> <appender> <file>/Users/wolf/study/logback/logback-examples/myApp.log</file> <encoder> <pattern>%msg%n</pattern> </encoder> </appender> <appender> <encoder> <pattern>%msg%n</pattern> </encoder> </appender> <root> <appender-ref ref="STDOUT" /> <appender-ref ref="FILE"/> </root> </configuration>

该xml配置把日志输出到了myApp.log文件和console中。

Layouts/Encoder

有上面Logger和Appender两大组件,日志已经输出到目的地了,但是这样打印的日志对我们这种凡人不太友好,读起来费劲。凡人就要做到美观,那就用Layouts或Encoder美化一下日志输出格式吧。Encoder 在 logback 0.9.19 版本引进。在之前的版本中,大多数的 appender 依赖 layout 将日志事件转换为 string,然后再通过 java.io.Writer 写出。在之前的版本中,用户需要在 FileAppender 中内置一个 PatternLayout。在 0.9.19 之后的版本中,FileAppender 以及子类需要一个 encoder 而不是 layout。

源码 Logger创建 Logger logger = LoggerFactory.getLogger(LogbackTest.class);

接下来我们根据源码分析一下logger的初始化。分析源码之前还是按照老规矩来一张接口调用时序图吧。

Logback源码分析

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyyxxx.html