花几分钟看懂logback

前言

我们开发项目过程中,日志是必不可少的,但是我们一直在使用,却很少考虑其原理,本文就是填补此项空白。

介绍

日志框架通常采用门面模式来设计,也就是说开发在使用时直接使用api,而不关心具体实现细节,在java项目中,主要有以下对应产品:

门面实现
jcl/SLF4j/jboss-loggingLog4j JUL(java.util.logging) Log4j2 Logback

本文主要介绍slf4j+logback这个主流的日志搭档。

使用

slf4j-api

上文我们说到slf4j-api是门面,也就是它不是具体的实现,我们来测试下看看是否如此。
创建空工程,maven添加依赖

<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>slf4j-api</artifactId>
	<version>2.0.0-alpha1</version>
</dependency>

编写代码

	static final Logger logger = LoggerFactory.getLogger(Demo.class);
	public static void main(String[] args) {
		logger.info("测试");
	}

我们会发现控制台报错:

SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#noProviders for further details.

这个就是因为日志工程无法找到实现。下面我们先通过添加一个简单的实现(slf4j-simple)来查看运行情况。

slf4j-simple

maven依赖:

<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>slf4j-simple</artifactId>
	<version>2.0.0-alpha1</version>
</dependency>

代码保持不变,我们可以发现控制台输出变了:

[main] INFO com.zlqian.slf4j.demo.Demo - 测试

我们打开slf4j-simple的jar包,可以发现META-INF/services下面有个文件“org.slf4j.spi.SLF4JServiceProvider”。这就是基于java的spi技术提供的服务实现。
这里不做spi技术的具体介绍。

多个日志实现服务

我们在上面的测试中已经添加了一种实现:slf4j-simple,我们继续添加logback实现看看会咋样:
添加maven依赖:

 <dependency>
	<groupId>ch.qos.logback</groupId>
	<artifactId>logback-classic</artifactId>
	<version>1.3.0-alpha5</version>
</dependency>

发现控制台输出:

SLF4J: Class path contains multiple SLF4J providers.
SLF4J: Found provider [org.slf4j.simple.SimpleServiceProvider@72ea2f77]
SLF4J: Found provider [ch.qos.logback.classic.spi.LogbackServiceProvider@33c7353a]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual provider is of type [org.slf4j.simple.SimpleServiceProvider@72ea2f77]
[main] INFO com.zlqian.slf4j.demo.Demo - 测试

这意思是什么呢?就是说classPath中发现多个日志实现服务(基于spi机制发现),取第一个日志实现服务。

logback

不进行配置

一般日志都是通过配置,输出到文件,如果我们不进行配置直接运行,我们看下输出:

10:37:27.100 [main] INFO com.zlqian.slf4j.demo.Demo - 测试

我们发现能够在控制台输出,这个是什么原因呢?logback有一个状态管理器StatusManager,我们通过它来查看当前的logback的状态。
编写代码:

logger.info("测试");
LoggerContext loggerContext = (LoggerContext)LoggerFactory.getILoggerFactory();
StatusPrinter.print(loggerContext);

查看控制台输出:

10:44:55.085 [main] INFO com.zlqian.slf4j.demo.Demo - 测试
10:44:55,047 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml]
10:44:55,047 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy]
10:44:55,047 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.xml]
10:44:55,049 |-INFO in ch.qos.logback.classic.BasicConfigurator@306a30c7 - Setting up default configuration.

看到这里我们知道原因了,由于没有配置,所以默认采用ConsoleAppender进行日志打印。

logback 架构

logback有三个核心模块logback-core logback-classic logback-access.
core是logbacck的基础,classic继承core实现了slf4j-api。access是用于http容器中的,这里暂时不讨论access。

核心类

logback中3个核心类,这3个类协作完成日志的格式化输出。

所属模块
Loggerclassic
Appendercore
Loyoutcore

Logger

获取Logger

通过LoggerFactory.getLogger(name)获取Logger,如果name一样获取到的是同一个引用;

Logger x = LoggerFactory.getLogger("wombat"); 
Logger y = LoggerFactory.getLogger("wombat");

x 和 y 2者是相同的Logger。

LoggerContext

用于生成Logger以及将它们按照树形结构组织。logger之间按照名称存在着父子关系。
例如名称为com.zlqian的Logger 是 com.zlqian.test的Logger的父关系。
这关系有啥用呢?
Logger是设置日志level,如果一个Logger没有设置level,就会依次向父Logger继承。
最上层的Logger名称:org.slf4j.Logger.ROOT_LOGGER_NAME。

Appender

logback将日志输出到多个源,每个输出源就是一个Appender。logback支持很多中Appender。
根据官网文档: console, files, remote socket servers, to MySQL, PostgreSQL, Oracle and other databases, JMS, and remote UNIX Syslog daemons.
如果将需要打印的信息交给Logger,那么该Logger中的Appender都将会输出,并且Logger的父Logger中的Appenders也都输出。
不过这点可以进行关闭,设置 additivity flag 为 false。

Layout

logback允许用户设置其日志输出格式,例如将日志格式设置为:"%-4relative [%thread] %-5level %logger{32} - %msg%n",那么其日志输出就如下:

176  [main] DEBUG manual.architecture.HelloWorld2 - Hello world.

流程

参考官网

过滤器

从流程图中我们可以看到在使用Logger打印的时候,首先会从LoggerContext中获取TurboFilter。
实际上logback中有2类过滤器: Filter和TurboFilter,后者就是上图中的过滤器。
它们的区别在于:

作用时机配置
TurboFilter在创建LoggingEvent前全局配置
Filter在创建LoggingEvent后在Appender中配置

由于以上区别,因此TurboFilter的性能更加高,而Filter配置更加灵活,不同的Appender可以配置不同的FIlter。

Layout

从流程图中,我们发现Appender会通过doLayout方法进行日志格式化。Layout负责将日志事件抓成string,如果想要自定义一个Layout,需要继承ch.qos.logback.core.LayoutBase,实现将ILoggingEvent转换成String。

MDC

目前server端多通过多线程来提高并发处理,logback为了提高多线程环境下,输出的日志更便于诊断,提供了Mapped Diagnostic Context技术,其核心原理就是通过ThreadLocal技术,请求过来时,通过在线程中设置请求的标识,在Appender输出时会根据MDC中的标识设置进行输出。

参考

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值