官方文档: http://logback.qos.ch/manual/index.html

一、简介

Java 开源日志框架,以继承改善 log4j 为目的而生,是 log4j 创始人 Ceki Gülcü 的开源产品。

它声称有极佳的性能,占用空间更小,且提供其他日志系统缺失但很有用的特性。

其一大特色是,在 logback-classic 中本地(native)实现了 SLF4J API(也表示依赖 slf4j-api)

二、架构 / Logback知识

1. 项目分为三个模块:

  • logback-core:其他俩模块基础模块,作为通用模块 其中没有 logger 的概念
  • logback-classic:日志模块,完整实现了 SLF4J API
  • logback-access:配合Servlet容器,提供 http 访问日志功能

2. 在 logback 中主要概念(Logger、Appender、Layout、Encoder)

· Logger

日志记录器,logback-classic 的部分

每个 Logger 都附加到一个 LoggerContext 上,该 Context 负责构造 Logger 以及将其安排在层级结构中。

  1. 命名及层级关系

    Logger 名称区分大小写,并遵循层级命名规则。

    层级关系用 "." 表示,如:"com.foo" 是 "com.foo.Bar" 的父Logger

    且所有 Logger 都可通过LoggerFactory#getlogger(String name)来获取,且相同名称返回的实例相同

  2. 根 Logger

    是所有层级结构的顶部Logger,可通过名称检索获取

    Logger rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);

  3. Level 与 继承关系

    Logger 可以被分配级别(TRACE、DEBUG、INFO、WARN、ERROR),可在 ch.qos.logback.classic 中查看

    若没有给 Logger 分配级别,则它将从最近的分配了等级的祖先处继承等级

    例:

    Logger name Assigned level Effective level
    root DEBUG DEBUG
    X INFO INFO
    X.Y none INFO
    X.Y.Z ERROR ERROR
  4. Level 与 log 规则(basic selection rule)

    Logger 只会启用等级 ≥ Logger等级的日志请求

    等级排序(严重程度,而非优先级):TRACE < DEBUG < INFO < WARN < ERROR

    如:

    Logger logger = LoggerFactory.getLogger("com.foo");
    logger.setLevel(Level. INFO); // 启用,因为 WARN >= INFO
    logger.warn("Low fuel level.");
    // 禁用, 因为 DEBUG < INFO.
    logger.debug("Starting search for nearest gas station.");

· Appender

Logback 通过Appender#doAppend(E event)将日志事件打印到目的地(允许附加多个Appender即即多个目的地

目前官方已提供 console、文件、远程socket服务、JMS、远程UNIX Syslog进程、MySQL/PostgreSQL/Orcale等数据库的 appender 支持.

注意:

  • 一个 Logger 可以通过Logger#addAppender方法可被附加多个 appender
  • appender 同样适用于继承结构,且是以追加的方式而非覆盖;

    但继承行为可被 Logger 的 additivity 标志影响是否继承(通过Logger#setAdditive设置)
  • additivity 标志本身也是可继承的

继承示例如下:

Logger Name Attached Appenders Additivity Flag Output Targets
root A1 not applicable A1
x A-x1, A-x2 true A1, A-x1, A-x2
x.y none true A1, A-x1, A-x2
x.y.z A-xyz1 true A1, A-x1, A-x2, A-xyz1
security A-sec false A-sec
security.access none true A-sec

· Layout

表示日志输出格式,其通过接口ch.qos.logback.core#doLayout(E event): String将日志事件格式化为String 返回。

Logback 官方提供 PatternLayout,允许以类似c语言printf来指定输出格式。

可通过将 layout 与 appender 关联,来实现自定义输出格式和目的地;但并不是每个 appender 都需要 layout,比如负责序列化的 SocketAppender 自然不需要 doLayout 转字符串

· Encoder

Encoder的概念在 Logback 0.9.19 中被引入,通过Encoder#encode可将 LoggingEvent 转为 byte[]

目前 Logback 仅提供了 PatternLayoutEncoder 这一个可用的实现,其逻辑很简单:内部构造/包装了 PatternLayout 实例,调用PatternLayout#doLayout得到格式化字串后,再调用String#getBytes返回 byte[]

引入原因:因为Layout#doLayout接口只能将 LoggingEvent 转为 String,这在某些情况下不太灵活,而现在 Encoder 能完全控制字节格式。

比如,在以前的版本中常在FileAppender中嵌套PatternLayout来使用,但现在仅需依赖Encoder

三、使用

1.logback 配置

Logback 初始化时,根据以下顺序尝试配置:

  1. 类路径下尝试寻找 logback-test.xml
  2. 若没有,类路径下尝试寻找 logback.groovy
  3. 若没有,类路径下尝试寻找 logback.xml
  4. 若没有,尝试基于 Java SPI 机制寻找 com.qos.logback.classic.spi.Configurator 接口的实现
  5. 若以上都没有,Logback 会使用最基本的 BasicConfigurator 配置自己。

    这将使用 TTLLLayout(类似 PatternLayout) 以"%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"模式格式化日志,并将 ConsoleAppender 附加到 root Logger,这会输出到控制台,且 root 被指定为 DEBUG 等级。

    默认配置等效为以下xml配置:
    <configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <!-- encoders are assigned the type
    ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
    <encoder>
    <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
    </appender> <root level="debug">
    <appender-ref ref="STDOUT" />
    </root>
    </configuration>

可通过以下代码打印当前配置:StatusPrinter.print((LoggerContext) LoggerFactory.getILoggerFactory())

输出:

15:25:46,635 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml]
15:25:46,635 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy]
15:25:46,636 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.xml]
15:25:46,647 |-INFO in ch.qos.logback.classic.BasicConfigurator@5f16132a - Setting up default configuration.

2.log 整体流程

  1. 获取 filter 链决策
  2. 应用 basic selection rule
  3. 创建 LoggingEvent 对象
  4. 调用 appenders
  5. 调 Layout 格式化
  6. 输出到目的地

四、配置详解

1.配置文件

一些写法/背景知识:

  1. 可在值中以 ${KEY:-defaultValue} 的形式引入属性,查找顺序如下:

    • 首先在本地作用域查找(详见<property>
    • 若没有,在上下文作用域查找
    • 若没有,在JVM系统属性查找
    • 最后,在系统环境变量中查找

    既支持名称(KEY)中的嵌套,也支持值/默认值的嵌套引用

  2. 预定义属性:

    • HOSTNAME:系统hostname,是配置时在 context 域中被定义被定义
    • CONTEXT_NAME:上下文名
  3. 一些标签涉及到类的标签(如<definer>、<appender>、<encoder>),其子标签除了规定之外,还可定义与 JavaBean 属性同名,这将调用相应setter注入。

顶级标签

<configuration>

属性:

  • debug:获知 Logback 内部状态,官方推荐在<configuration>上设置debug属性,而非在代码中调用 StatusPrinter。例:<configuration debug="true">

    这也等同于设置状态监听器 OnConsoleStatusListener

    例:
    <configuration>
    <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />
    <!-- … -->
    </configuration>
  • scan / scanPeriod:可定期扫描配置文件的更改,并在更改时自动应用。默认每分钟一次

    例:<configuration scan="true" scanPeriod="30 seconds" >
  • packagingData:可令每一行StackTrace输出其对应jar包。需注意,其计算成本高昂

    例:<configuration packagingData="true">

    输出示例:
    14:28:48.835 [btpool0-7] INFO  c.q.l.demo.prime.PrimeAction - 99 is not a valid value
    java.lang.Exception: 99 is invalid
    at ch.qos.logback.demo.prime.PrimeAction.execute(PrimeAction.java:28) [classes/:na]
    at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:431) [struts-1.2.9.jar:1.2.9]
    at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:236) [struts-1.2.9.jar:1.2.9]
    at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432) [struts-1.2.9.jar:1.2.9]

<configuration>子标签

  • <include>:从另外的文件引入配置,目标文件必须将其标签放入<included>下。(SpringBoot基础配置便是如此,可参考spring-boot:2.4.0包中base.xml)

    • file
    • resource
    • url
    • optional:[true | false],默认若找不到目标文件,将输出警告;可设置为可选避免该行为
  • <contextName>:设置上下文名称,可作为区分不同多个应用程序到同一target的区分,默认为"default"

    示例:

<contextName>myAppName</contextName>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d %contextName [%t] %level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
  • <property>:配置或引入外部属性,别名

    • name
    • value
    • file:引用文件系统的 .properties 文件
    • resource:引用类路径上的 variables.properties 文件
    • scope:
      • local:默认,会在配置解释时定义,并在结束后清除。
      • context:上下文作用域,属性将插入到LoggerContext中直到LoggerContext被清除,因此在所有日志事件中都可用。
      • system:系统作用域,属性将插入到JVM系统属性中
  • <define>:代码动态定义属性,以 PropertyDefiner#getPropertyValue 方法返回其值

    • name
    • class:PropertyDefiner实现全类名
  • <conversionRule>:自定义转换词

    • conversionWord:转换词
    • converterClass:ClassicConverter 实现类全类名
  • <appender>

    • *name:声明Appender名称
    • *class:要使用的Appender的完全限定名
    • <appender>、<layout>子标签:
      • <layout>:0或1个

        • class:若未声明,表示 PatternLayout
      • <encoder>:0或多个
        • class:若未声明,表示 PatternLayoutEncoder
      • <filter>:0或多个
  • <logger>:0或多个,配置 Logger

    • name(必须)
    • level:[TRACE | DEBUG | INFO | WARN | ERROR | ALL | OFF],或者 INHERITED / NULL 表示从上级继承。
    • additivity:[true | false]
    • 子标签:
      • <appender-ref> :0或多个,表附加appender

        • ref:指定先前的名称
  • <root>:配置根Logger

    • level:根Logger级别不能设置为 INHERITED / NULL
    • 子标签:
      • <appender-ref>

2.JVM系统属性

  • logback.configurationFile:指定配置文件位置,可以是 URL、类路径资源或外部文件系统。也可以在代码中设置(System#setProperty),但必须在创建任意Logger实例之前。

    文件扩展名必须是 .xml 或 .groovy
  • logback.statusListenerClass:可设置为希望注册的 StatusListener 名称

3. PatternLayout 的格式化消息编写规则

基础规则

  • 转换符 '%' 可后跟规定的word,来获取数据字段,如 logger名称,日期,线程名等

  • 转换符可后接格式修饰符(Format modifiers)来指定每个字段最小、最大宽度 以及 是否左对齐

    示例:

    写法 左对齐 最小宽度 最大宽度
    %20logger false 20 none
    %.30logger NA none 30
    %-20.30logger true 20 30
  • 括号"()" 可将部分内容分组,常配合格式修饰符使用

    如:

    %d{HH:mm:ss.SSS} [%thread]

    输出:
    13:09:30 [main] DEBUG c.q.logback.demo.ContextListener - Trying platform Mbean server
    13:09:30 [pool-1-thread-1] INFO ch.qos.logback.demo.LoggingTask - Howdydy-diddly-ho - 0

    %-30(%d{HH:mm:ss.SSS} [%thread])

  • 一些关键词可使用转义符\来输出

常用转换词

  • 日志事件的消息:m / msg / messages

  • 日志级别:p / le / level

  • Logger 名

    语法:

    c{length}
    lo{length}
    logger{length}

    含义/示例: length表示推荐最大长度,logback会根据该长度适当缩写Logger名,但始终会保证最右段不会缩写

    示例 Logger原名称 打印结果
    %logger mainPackage.sub.sample.Bar mainPackage.sub.sample.Bar
    %logger{0} mainPackage.sub.sample.Bar Bar
    %logger{5} mainPackage.sub.sample.Bar m.s.s.Bar
    %logger{16} mainPackage.sub.sample.Bar m.sub.sample.Bar
  • 上下文名:contextName

  • 日志事件的线程名: t / thread

  • 从"应用启动"到"产生该日志事件"经过的毫秒数:r / relative

  • 日期

    语法:

    d{pattern}
    date{pattern}
    d{pattern, timezone}
    date{pattern, timezone}

    含义/示例:输出日志事件的日期,其 pattern 语法与 java.text.SimpleDateFormat 格式兼容

    在没有 timezone 的情况下,使用 Java 平台默认时区

    示例 结果
    %d 2006-10-20 14:06:49,812
    %date{HH:mm:ss.SSS} 14:06:49.812
    %date{dd MMM yyyy;HH:mm:ss.SSS} 20 oct. 2006;14:06:49.812
    %date{HH:mm:ss.SSS, Australia/Perth}
  • 换行符:n

  • 异常:

    语法:

    ex{depth}
    exception{depth}
    throwable{depth} ex{depth, evaluator-1, ..., evaluator-n}
    exception{depth, evaluator-1, ..., evaluator-n}
    throwable{depth, evaluator-1, ..., evaluator-n}

    含义/示例:输出与日志事件关联的异常的stacktrace信息,默认输出完整的stacktrace

  • 属性:property{key}

  • 正则替换:replace(p){r,t} 将消息模式p中的r替换为t

    如:%replace(%logger %msg){'\.', '/'}将所有"."替换为"/"

  • MDC(Mapped Diagnostic Contex)字段:%X{filedName}

  • 自定义转换词:

    1. 自定义实现 ClassicConverter,重写 convert(ILoggingEvent) 方法
      public class MySampleConverter extends ClassicConverter {
      long start = System.nanoTime(); @Override
      public String convert(ILoggingEvent event) {
      long nowInNanos = System.nanoTime();
      return Long.toString(nowInNanos-start);
      }
      }
    2. 声明转换词
      <configuration>
      <conversionRule conversionWord="nanos" converterClass="chapters.layouts.MySampleConverter" />
      <!-- … -->
      </configuration>

性能考虑,应避免使用的转换词

  • 类名:C{length} / class{length}
  • 文件名:F / file
  • 行号:L / line
  • 方法名:M / method
  • 包含jar包信息的异常stacktrace:xEx{depth} / xException{depth}…

    及root异常顺序反转的 rEx{depth} / rootException{depth}…

4. 着色(Coloring)

基于ANSI颜色代码,Logback可使用颜色关键词来为分组设置颜色。内置了:"%highlight","%black", "%red", "%green","%yellow","%blue", "%magenta","%cyan", "%white", "%gray", "%boldRed","%boldGreen", "%boldYellow", "%boldBlue", "%boldMagenta""%boldCyan", "%boldWhite"

例:

<pattern>%d ${HOSTNAME} [%t] %highlight(%level) %logger{36} - %msg%n %ex{full}</pattern>

踩坑:官方说明使用 jansi 可以做到兼容不兼容ANSI的终端,但 Windows 下始终报错,即便引入了推荐版本 仍然报错

<dependency>
<groupId>org.fusesource.jansi</groupId>
<artifactId>jansi</artifactId>
<version>1.17</version>
</dependency>

5.异步Appender

可通过声明AsyncAppender来执行异步日志打印,它只进行日志事件分发,因此必须引用另一个实际Appender才有意义

五、常见需求

  1. 根据环境变量动态附加Appender

    参考:How to select Logback appender based on property file or environment variable

    1. 使用 logback 官方支持的 语法,但同样需要引入 Janino library。参考:configuration
    2. Appender 设置 <filter>,并使用环境变量语法动态配置Filter的Level【有些曲线救国,应该仍有性能损耗
    3. 使用 SpringProfile

      例:
      application.yaml
      spring:
      profiles:
      active:
      - ${ENV:classiclogs}
      logback.xml
      <configuration>
      <!-- appender conf…-->
      <springProfile name="jsonlogs">
      <root level="info">
      <appender-ref ref="stdout-json" />
      </root>
      </springProfile>
      <springProfile name="classiclogs">
      <root level="info">
      <appender-ref ref="stdout-classic" />
      </root>
      </springProfile>
      </configuration>

六、踩坑

  1. 对于嵌套 .xml 配置文件,默认域"local"重复声明的话是无效的,不会覆盖。

    比如在我的logback.xml中声明,无法覆盖Spring自带的配置。

撰文参考:

http://logback.qos.ch/manual/index.html

最新文章

  1. C#实现微信开发前奏
  2. jquery.validate.js表单验证
  3. 11、Linq的使用
  4. PHP Header下载文件在IE文件名中文乱码问题
  5. html中input文本框,初始里边有文字提示,当点击时,文字消失,怎么设置?
  6. 【转】Java日期计算之Joda-Time
  7. spark Mllib基本功系列编程入门之 SVM实现分类
  8. PC-PC-单片机(Arduino)通信实例
  9. ural 1268. Little Chu
  10. StackOverflowError 和 OutOfMemoryError
  11. 如何理解这段代码:void (*signal (int sinno,void(*func)(int)))(int)
  12. www.chenbowenblog.com 博客地址转移
  13. java开发之基础篇2
  14. 修改wampsever默认密码
  15. form表单参数传递和url参数传递的区别
  16. ReactNative(三)——WebStorm的基本配置
  17. Nginx与PHP-FPM运行原理详解
  18. DIY——自制吸烟仪
  19. JS 日期补0
  20. Travel notes in Vietnam

热门文章

  1. explicit 关键字 禁止隐式转换
  2. 8、ITSM基本概念(2)
  3. 15、oracle多表查询
  4. Java数据库开发(二)之——DBCP连接数据库
  5. HDU 4292 Food 多源多汇入门题
  6. 17 shell break与continue
  7. centos安装报错:license information (license not accepted)
  8. Ionic命令笔记
  9. java+selenium UI自动化001
  10. [刘阳Java]_SpringMVC与Struts2的对比_第12讲