因为项目中用到 SpringBoot,看到官方文档中提及默认的日志实现是 logback,因此就通过阅读手册和结合实践学习了下相关的知识,记录下以备查阅。

1. logback 是什么?

logback 是 log4j 创始人 重新发起的一个开源日志组件,他总结了 log4j 开发和实践中的经验教训后再开发的日志组件,性能优越,功能丰富。
 
相比log4j,它经过了充分的测试,性能有较大提升;logback-classic(logback一个模块)实现了slf4j接口,支持快速切换到其他日志组件;有强大的过滤器,支持日志级别单独配置;支持自动压缩日志、自动删除过期日志等。(这里的有点写的只是我目前认知到的,我看到有他人总结过更多更唬人的优点,因为理解不是特别深刻,所以没随便复制粘贴。)

2. lobback 的简单使用

首先是配置文件,如果是 SpringBoot 开发,那么 logback 支持默认命名的配置文件,logback.groovy、logback.xml、logback-test.xml等。这里采用第二个,简单配置一个控制台输出和日志文件输出。(如果不配置的话,SpringBoot 也会有个默认实现,前提是使用 spring-boot-starter-parent 作为父类依赖)

其次是需要添加到 classpath 的 jar 包。除了自身的 logback-classic.jar 和 logback-core.jar 之外,还需要 slf4j.jar 组件。(SpringBoot默认也添加了,同上)
 
一般情况下,开发代码中都看不到 logback 相关的类,只需要使用 slf4j 的接口就行了。(slf4j 简介在第4部分)
 
我们通过使用 org.slf4j.LoggerFactory 类的 getLogger()方法,把类名或者类的 class 文件作为参数就可以创建一个可以使用的 org.slf4j.Logger。
 
Logger 的打印方法有 debug()、info)()、warn()、error()等,参数就是要打印的内容。
<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} L:%L -%msg%n
</pattern>
</encoder>
</appender> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>
/app/jar/logs/${hostname}/wp2.%d{yyyy-MM-dd}.log
</fileNamePattern>
<maxHistory>
30
</maxHistory>
<!-- log file total size limit, lower privilege than maxHistory -->
<totalSizeCap>
2GB
</totalSizeCap>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} L:%L -%msg%n
</pattern>
</encoder>
</appender> <root level="INFO">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
</configuration>
 

3. 查看 logback 的内部状态

使用 IDE 启动项目的时候,我们会看到日志系统在背后做了一些工作,打印出了内部的工作状态,这个是怎么做到的呢?这里简单记录下。
 
ch.qos.logback.core.util.StatusPrinter 可以访问到 logback 生命周期内的所有事件,这些事件可以通过 ch.qos.logback.classic.LoggerContext 得到,方法如下:
 
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
StatusPrinter.print(lc);

4. slf4j 简介

它是 java 日志组件的门面,支持 log4j1(2)、logback、java.util.logging 等日志组件,使用方式就是把 slf4j.jar 和对应日志组件的 jar 以及一个 slf4j 提供的绑定对应日志组件的 jar 放到 classpath 中即可。
 
绑定组件有 log4j-over-slf4j.jar(log4j)、jul-to-slf4j.jar(java.util.logging)、jcl-over-slf4j.jar(commons-logging)。
 
但是也有例外,比如 logback 由于它自己就实现了 slf4j 的接口,所以它不需要专门的绑定jar包。
 
门面是一种设计模式,强调外部客户端和子系统通信必须通过统一的门面进行,门面提供统一的高层次接口,可以将子系统的复杂接口简单化,帮助外部客户端与子系统解耦。
 

5.  logback的架构 详解

  • logback-core 核心包,基础功能

  • logback-classic 可以看做改进版的 log4j,同时实现了 slf4j 接口。

  • logback-access 集成了 Servlet 容器,提供了日志的 HTTP 访问功能。

接下来我们关注具体实现。

首先三个类,Logger、Appender 和 Layout。这三个类相互配合完成了根据消息类型和级别来记录日志的功能,并且能够决定具体汇报日志的格式。

Logger 在 logback-classic 包内, Appender 和 Layout 两个接口在 logback-core 中,logback-core 作为抽象模块,没有任何引用 logger 的地方。
 
一般而言,Logger 负责分级和具体输出日志,Appender 决定日志输出的目的地,Layout 决定日志输出的格式等信息。那么什么是日志分级以及如何实现分级输出的?我们来看下 Logger 的相关信息。
 
在 logback-classic 中,每一个 logger 都天生具有分级规则,这个分级是跟名字有关的,且大小写敏感,所有的 logger 能够组成一个树状结构,并由 LoggerContext 管理。每个 logger 的名字都是跟包名相关联的,包名的父子关系就对应 logger 的父子关系,比如 com.foo 是 com.foo.bar 的父目录,对应的 logger 也具有相同的父子关系。
 
这个父子关系意味着如果子类 logger 没有设定日志级别,那么它将继承父类的日志级别,而如果子类有日志级别,就按照子类的配置生效,不用管父类的日志级别是比子类的高还是低。
 
日志级别按照优先级从低到高的顺序排列为 TRACE < DEBUG < INFO < WARN < ERROR
 
父子间的日志级别只在子类没配置的时候才继承,否则没直接关系。而设定的日志级别就严格按照日志级别起作用。比如 com.foo的日志级别时 INFO,对应的 logger 名为 fooLogger,那么 fooLogger.debug("sth"); 是无法输出的,因为 DEBUG 级别低于 INFO。
 
还有一点,既然是树状结构那么必有一个根元素,作为所有下层 logger 的共同父类,这个就是 root,它默认的日志级别时 debug。
 
接下来看看 Appender 的相关信息。
 
logger 的树形层级结构影响的是日志输出的级别,而 appender 则直接影响的是日志输出的目的地。具体来说,多个 appender 可以依附在同一个 logger 上,它们分别代表不同的输出目的地,比如控制台和文件,表示 logger 的日志是既在控制台打印,又在文件输出。
 
除此之外,appender 还有一个特性,就是 默认 appender 输出的内容会在更高层次 logger 的 appender 中输出(因此这个也可以说是 logger 的特性,因为他们共享树形层次结构)。这个特性在 logback 文档中称之为 “appender additivity”,有翻译为“输出源的附加特性”不是很好懂。log4j 也有这个属性。可以设置 additivity = false 来将输出停在这一层,不上报。
 
接下来是 layout,常用的是 PatternLayout,决定的是日志的格式,输出格式类似 C 语言的 prinf 方法。
  • %relative 是项目已启动的毫秒数
  • %thread 线程名
  • %level是日志级别
  • %msg是日志信息

6. 优化日志输出

不管是否输出,debug的参数都要进行String拼接操作,有些时候造成资源浪费。
logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));

加上是否允许debug的判断,确实不错,因为这个判断耗时占据日志打印的1%左右。

if(logger.isDebugEnabled()) {
logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
}

最佳实践如下:可以看到优点是代码简洁,并且在判断了不输出的话就不会转换成Stirng,效率提高。方式就是{}替换,可以有多个参数,也可以用数组的方式存参数。

Object entry = new SomeObject();
logger.debug("The entry is {}.", entry);

Logback 学习指南 一的更多相关文章

  1. 写给大忙人的spring cloud 1.x学习指南

    这几天抽空搞了下spring cloud 1.x(2.0目前应该来说还不成熟),因为之前项目中使用dubbo以及自研的rpc框架,所以总体下来还是比较顺利,加上spring boot,不算笔记整理,三 ...

  2. spring boot 1.x完整学习指南(含各种常见问题servlet、web.xml、maven打包,spring mvc差别及解决方法)

    spring boot 入门 关于版本的选择,spring boot 2.0开始依赖于 Spring Framework 5.1.0,而spring 5.x和之前的版本差距比较大,而且应该来说还没有广 ...

  3. Civil 3D API二次开发学习指南

    Civil 3D构建于AutoCAD 和 Map 3D之上,在学习Civil 3D API二次开发之前,您至少需要了解AutoCAD API的二次开发,你可以参考AutoCAD .NET API二次开 ...

  4. 笔记——shell脚本学习指南

    <shell脚本学习指南>机械工业出版 ISBN 987-7-111-25504-8 第2章 2.4 初级陷阱 1.当今的系统,对#!这一行的长度限制从63到1024个字符都有,尽量不要超 ...

  5. 《Spring MVC学习指南》怎么样?答:书名具有很大的欺骗性

    2016年6月21日 最近,因为工作需要,我从网上买了一本<Spring MVC学习指南>,ISBN编号: 978-7-115-38639-7,定价:49.00元.此书是[美]Paul D ...

  6. [go语言学习指南]

    内部分享,根据自己的经验,收集汇总的go语言学习指南. 适合新手入门. 可以通过这里进行下载.

  7. Oracle学习指南

    Oracle学习指南 你走的那天,我决定不落泪,迎着风撑着眼帘用力不眨眼 创建数据库.创建用户.创建表空间.创建表.插入数据..... 1.用系统用户登录,任选系统用户 代码: >>sql ...

  8. 推荐10个很棒的AngularJS学习指南

    AngularJS 是非常棒的JS框架,能够创建功能强大,动态功能的Web app.AngularJS自2009发布以来,已经广泛应用于Web 开发中.但是对想要学习Angular JS 的人而言,只 ...

  9. 项目管理之道--纪我的新书《PMP项目管理认证学习指南(第4版)》出版并预祝大卖!

    新年伊始,我最新的项目管理书籍——<PMP项目管理认证学习指南(第4版)>也出版了,真是新年新气象啊!翻译英文书籍是一件任重道远的工作,除了要具备扎实的基本功,熟悉相关的领域外,还需要细致 ...

随机推荐

  1. 微信服务号获得openid 跟用户信息

    https://open.weixin.qq.com/connect/oauth2/authorize?appid=xxxxxxxxxxxxx&redirect_uri=http://www. ...

  2. qt 中lineEdit->setText()输出double

    在qt中需要将获取到的double 值在ui界面上显示出来,便于观察.但是lineEdit控件的setText()要求的参数是string. 所以我们先要进行转化,将double 转化为string. ...

  3. 从零学React Native之06flexbox布局

    前面我们接触了好多React Native代码, 并没有介绍RN中的组件具体是如何布局的,这一篇文章,重点介绍下flexbox布局. 什么是flexbox布局 React中引入了flexbox概念,f ...

  4. part10.3-字符驱动访问揭秘

  5. 禁用gpu首选

    import osos.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"os.environ["CUDA_VIS ...

  6. hdu 1358 Period (KMP求循环次数)

    Problem - 1358 KMP求循环节次数.题意是,给出一个长度为n的字符串,要求求出循环节数大于1的所有前缀.可以直接用KMP的方法判断是否有完整的k个循环节,同时计算出当前前缀的循环节的个数 ...

  7. HDU 1251 裸的字典树、入门题

    裸的字典树还是挺简单的. 四个基本操作建立.查找.插入.删除 建立新结点我是用的c++中 new操作.当然也可以用malloc,都方便 不过指针阿.地址阿.这其中关系什么的我貌似还不是很清楚阿. 因为 ...

  8. HDU 2546 01背包问题

    这里5元是个什么意思呢.差不多就是特殊情况了. 就是说最贵的那个东西先不买.并且最后要留下5元去买那个最贵的. 也就是说对现在金钱-5 拿剩下的钱去对减去最贵的商品后的商品dp.看这些剩下的钱能买多少 ...

  9. 2019-1-29-win10-uwp-使用-Microsoft.Graph-发送邮件

    title author date CreateTime categories win10 uwp 使用 Microsoft.Graph 发送邮件 lindexi 2019-01-29 16:36:3 ...

  10. [转]React入门看这篇就够了

    摘要: 很多值得了解的细节. 原文:React入门看这篇就够了 作者:Random Fundebug经授权转载,版权归原作者所有. React 背景介绍 React 入门实例教程 React 起源于 ...