logback那些事

发布时间:2017-3-25 15:42:45 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"logback那些事",主要涉及到logback那些事方面的内容,对于logback那些事感兴趣的同学可以参考一下。

logback: logback可以认为是log4j的升级版,依然出自Ceki Gülcü,使用简单,只需要在你的classpath里包含slf4j-api.jar、logback-core.jar以及logback-classic.jar即可。 简单代码示例如下: import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.core.util.StatusPrinter; public class LogTest {     public static void main(String[] args) {         Logger logger = LoggerFactory                 .getLogger(LogTest .class.getName());         logger.debug("Hello world."); } 其中的logger对象和LoggerFactory都来自slf4j项目,slf4j是一个很好的facade,包装了接口,就像之前写的一篇文章中的提到的commons-logging框架。 同样也可以认为logback+slf4j是log4j+commons-logging的升级版吧。 logback的架构: logback包含3个子工程——classic、core和access。core是其他两个的基础,也是logback的核心;classic扩展了core,内置了slf4j,但也支持各种其他log门面。同log4j一样,logback的主要构成也是Logger、Appender和Layout。Logger是核心控制器及调用入口,Appender主管配置和写日志实际process,Layout控制日志样式,是Appender的重要配置。值得注意的是,3个基本核心居然不都在core模块中,Logger是在classic里的。 对于Logger来讲,和Log4j一样,Logger是一个层次结构,每个logger都有一个name属性在LoggerFactory中被一个map管理着。对于Logback来说,这个factory就是classic下的LoggerContext。这里插一段自我理解,在做facade模式的时候,代码结构可能会引入一个占位性质的类,就像slf4j中的StaticLoggerBinder,这个类在org.slf4j.impl包下,是一个单例,但是私有构造函数却抛出了一个异常,这个在不熟悉这种写法时会产生困惑。其实这是很合理的,logback的classic中也有org.slf4j.impl这个包,其中也有StaticLoggerBinder这个类,但是内容完整了许多。这就完成了slf4j的任务,同时解除了耦合。我认为这种解耦合方式非常好,plugin的感觉。 再回来说LoggerContext,这个对应了log4j的LogManager和Hierarchy,用一个hashtable来维护logger的cache。代码真的是简洁了很多,再回头看看log4j中LogManager的getLogger方法,就知道logback的简洁了,一个while遍历省去了一个hierarchy。当然这里得补充一句,log4j包括logback的整个日志框架对于logger对象,是一个层次结构,这也是为什么log4j中有个Hierarchy的东西的原因。是一个层次的话,对于通过包名来管理日志记录等级的管理方式来说,就存在着level的控制,也就是说,你某个包名的类被设定了日志级别是什么,那么对应级别以下的日志才会被打印出来。有这样一个规则,logger的日志记录有效level由hierarchy中离它最近且方向向上(upwards)的一个logger的级别决定。如官网上的例子:   这里有4个logger,但是只有root被设定了level是DEBUG,其他几个logger由于没有被设定,依照规则,就都是root的level了。   第二个例子中,每个logger都自己设定了level,那么依据规则,离它最近的被使用,当然自己离自己最近了。   第三个例子里,X.Y没有设定level,那么离它最近且upwards的一个是X,那么X.Y的level就和X的一样。    level控制是日志框架的基础,什么样的日志在什么环境下被打印出来,这种设定可以配置才是一个合理的日志系统。一贯的level控制规则如下显示:   appender这个东西,和log4j是一样的,支持一个logger有多个appender,在AppenderAttachableImpl里会维护一个CopyOnWriteArrayList来存放一个logger的appender。每次log的时候都会遍历这个list里的appender然后调用对应的doAppend方法。我们在配置的时候每个logger的配置上有个additivity属性,默认为true。appender这个东西同logger一样有继承性。additivity属性就是控制这种继承的,true代表开启,false代表关闭,一般使用都会设置false,因为如果是true,那么如果appender比较多的话可能日志打的就有点太离谱了。    Layout和log4j一样,我没有细研究过,但是我认为这是控制输出的一大法宝,下次研究layout的时候做一个详细的分享,一般大家都使用patternLayout,写个表达式足以。 在之前的那篇写log的文章中,提到过一个优化写法,就是不要直接写出这样的代码: logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i])); 构造string参数是复杂且耗时的。要用if判断一下。而slf4j提供了比较合适的解决方法: Object entry = new SomeObject(); logger.debug("The entry is {}.", entry); 这样的代码就更符合程序设计人员的编写习惯,而且可读性我认为要远远高于用+号连接。但是遗憾的是,这种编码风格作者并没有持续贯彻下去,没有用变长参数,而是用的object[]终止了参数的个数。也就是说,你对于多个变量的log的话,只能这么写: Object[] paramArray = {newVal, below, above};logger.debug("Value {} was inserted between {} and {}.", paramArray); 在执行log的时候,会有一个判断流程,依据官网上的介绍,我简要翻译一下: 1,Get the filter chain decision:如果存在,尝试调用TurboFilter ,TurboFilter 会设置一个整个上下文范围的阈值或者过滤掉每个log请求的相关参数。如果这个filter返回的参数是FilterReply.DENY ,那么log结束;如果FilterReply.NEUTRAL返回,则进入第2步,如果FilterReply.ACCEPT ,直接第3步。 2, Apply the basic selection rule,如果log请求的阈值和高于配置的阈值,那么放弃处理该log。 3, Create a LoggingEvent object,logback会构建一个LoggingEvent对象,包含了所有的请求参数。其中有些参数可能是延迟加载的。 4, Invoking appenders,logback调用doAppend方法。 5, Formatting the output,layout会把LoggingEvent对象按固定格式格式化并返回字符串形式,像SocketAppender这样的方法不会返回字符串,相似的只会把它序列化。 6,  Sending out the LoggingEvent,把最终形式打印到对应的目的地址。 流程图见这里http://logback.qos.ch/manual/underTheHood.html 最后还是通过性能讨论结束这篇短文,性能的东西,我们不去看代码的话,是无法估计复杂度的变化的。那么就官网上给出的3条提示,第一点针对参数构建,第二点针对level的定位,这个在看过代码后,发现确实精简了,尤其是那种复杂的hierarchy结构没有了,线性的链条运行起来明显会快,算是去除冗余做了优化吧。第3条针对说format和write会快,尤其是format被大力投入改进,这个在看过代码后,可以做个比较。 本文算是一篇半自主半翻译的文章吧,重在学习。 参考文献: http://logback.qos.ch/manual/introduction.html

上一篇:平衡二叉树
下一篇:UVa:10534 Wavio Sequence

相关文章

关键词: logback那些事

相关评论

本站评论功能暂时取消,后续此功能例行通知。

一、不得利用本站危害国家安全、泄露国家秘密,不得侵犯国家社会集体的和公民的合法权益,不得利用本站制作、复制和传播不法有害信息!

二、互相尊重,对自己的言论和行为负责。

好贷网好贷款