SLF4J和Logback
SLF4J概念
简单日志门面,对应的英文为Simple Logging Facade,是存取日志的标准接口。
也就是说它仅仅是一个日志输出的
接口
,并不是一种具体的实现方案,就像JDBC
一样只是统一的接口。想要使用必须搭配其他的日志实现方案,如:
log4j
,logback
,JDK logging
等等。
可以看到 Logback
直接继承自 SLF4J
,它比其它所有的日志系统更快并且更小,包含了许多独特并且有用的特性。
Logback概述
Logback
分成三个不同的模块,logback-core
,logback-classic
,logback-access
。
快速使用
添加依赖:
logback-classic
模块需要在 classpath 添加 slf4j-api.jar、logback-core.jar 以及 logback-classic.jar。
maven项目中,使用坐标:
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
该依赖会包含其他几个坐标,可以手动添加相同版本的依赖,也可以只添加这一个。
如果你安装了 Maven
,你可以在 logback 的解压文件夹中运行 mvn install
来构建 logback 以及它所包含的模块。Maven 会自动下载 logback 需要的其它类库。
测试例子:
public class Test {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger("Test");
logger.debug("hello world,this is a debug message...");
// 打印内部的状态
LoggerContext loggerContext = (LoggerContext)LoggerFactory.getILoggerFactory();
StatusPrinter.print(loggerContext);
}
}
控制台打印结果:
12:08:39.804 [main] DEBUG com.codesy.test.Test1 - hello world,this is a debug message…
12:08:39,639 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml]
12:08:39,640 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy]
12:08:39,640 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.xml]
12:08:39,656 |-INFO in ch.qos.logback.classic.BasicConfigurator@1af6ecc - Setting up default configuration.
Logger
和 LoggerFactory
时 SLF4J包中的类 , LoggerContext
获得内部状态信息。
得到 Logger 实例,通过它调用不同的方法 trace()
,debug()
,info()
,warn()
,error()
来向指定的位置输出日志信息。
控制台显示的信息位没有找到配置文件 [logback-test.xml]
[logback.groovy]
[logback.xml]
从而 Setting up default configuration(设置默认配置)
我们可以自己创建对应的配置文件,让日志信息采取我们想要的方式打印存储。也可以使用默认简单的配置,即不手写配置文件,使用默认配置类 ch.qos.logback.classic.BasicConfigurator,该类只有一个方法,里面设置了默认的配置方案。
基本的Logback组件
Logback 的构建重点是三个主要的类上:Logger
,Appender
和 Layouts
。
组件Logger
每一个 Logger
实例都会依附在 LoggerContext
上,它管理所有 Logger实例,并且通过一个树状的层级结构来管理。
如果一个
Logger
实例的名字A
加上一个.
和另一个 Logger 实例名字B
,那么 A 就是B的祖先
,如果它们之间再无其他 Logger,A就是B的父级
。例如 一个Logger实例名为 com.codesy 如果 另一个实例名为 com.codesy.test ,那么前者就是后者的父级。名称是
大小写敏感
的。
示例:获取一个 名为 com.codesy.test 的Logger实例,查看它所依附的 LoggerContext
的所有 Logger实例
public class Test {
public static void main(String[] args) {
//获取 com.codesy.test 实例
Logger logger= LoggerFactory.getLogger("com.codesy.test");
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
//getLoggerList()方法返回所有Logger实例
List<ch.qos.logback.classic.Logger> loggerList = context.getLoggerList();
for (ch.qos.logback.classic.Logger logger1 : loggerList) {
System.out.println(logger1.getName());
}
}
}
输出结果:
ROOT
com
com.codesy
com.codesy.test
可以看到LoggerContext 中一共存在4个Logger实例,以 .
进行分割。获得 com.codesy.test 实例,其实同时得到了com
,com.codesy
实例,它们都是com.codesy.test的前缀,通过 . 相连。
还注意到一个最顶级的Logger实例 ROOT
,它是这棵树的最高层。
Logger的等级
Logger
实例被分成不同的 等级
,不同的等级定义在 ch.qos.logback.classic.Level
类中。
等级分类有 (TRACE < DEBUG < INFO < WARN < ERROR)
每一个获取到的 Logger实例如果没有指定等级,那么它会继承离它最近的一个祖先的等级。
ROOT
实例默认等级为 DEBUG
,倘若其他Logger实例都没有指定等级,那么继承ROOT的DEBUG等级。
如果实例本身指定了等级,那么就直接用自身的等级,不用继承。
示例:
Logger的规则
每一个 Logger
实例都会有日志输出方法,例如:
trace(),debug(),info(),warn(),error() 等等。
每一条打印语句都表示这条日志的打印等级:debug("...")
表示这个日志等级为 DEBUG
。
Logger
实例有等级,通过调用的打印方法
也有等级,那么它们之间有什么关系呢?
如果一条的日志的打印等级大于等于 Logger实例 的等级,该条日志才可以被打印出来。
各等级的排序为:TRACE < DEBUG < INFO < WARN < ERROR。
示例:
public class Test {
public static void main(String[] args) {
Logger logger= LoggerFactory.getLogger("com.codesy.test");
logger.debug("这是一条DEBUG等级的日志消息");
logger.trace("这是一条TRACE等级的日志消息");
}
}
控制台打印:
16:37:41.598 [main] DEBUG com.codesy.test - 这是一条DEBUG等级的日志消息
可以看到 logger.trace(“这是一条TRACE等级的日志消息”); 这条语句没有被输出到控制台,因为 logger 没有指定等级默认继承 ROOT
的等级 DEBUG
。这条日志消息的等级为 TRACE
比 DEBUG
小,无法打印。
注意:
对于我们上述的 Logger 实例它是 org.slf4j.Logger
包下的,我们也可以获取 ch.qos.logback.classic.Logger
包下的 Logger实例。
public final class Logger implements org.slf4j.Logger //实现了org.slf4j.Logger包下的Logger
该 Logger实例包含特有的方法,如设置Logger实例等级等
logger.setLevel(TRACE); //这样该Logger实例等级为 TRACE
另一点:
获取 Logger实例 通过 :
Logger logger = LoggerFactory.getLogger("com.codesy.test");
还有一种通过类的Class对象获得Logger实例,推荐使用 "com.codesy.test"
这种形式,这个命名策略能够看出日志的来源是哪里。
组件Appender与Layout
上述的Logger等级规则可以使得低等级的日志不被打印出来,那么
Appender
就是日志输出的位置,包console、file、remote socket server、MySQL、PostgreSQL、Oracle 或者其它的数据库、JMS、remote UNIX Syslog daemons 等位置。
一个Logger实例可以有多个 appender (多个输出位置)。
子级Logger实例会继承
来自父级的 appender
,例如 com.codesy
这个实例添加了 一个 console appender,那么 com.codesy.test
除了它本身的appender外 ,也会拥有console appender。当然前提是 additivity = true
这个属性设置为 true
表示可以继承父级的appender,为 false
则不能,默认为 true
。
Layout
它使用户可以自定义日志的输出格式。
参数化日志
在以前的log4j时候,没有实现slf4j日志接口,打印语句是这样的
int num = 1;
logger.debug("The num is " + num + ".");
这样会带来效率成本,它会拼接字符串,并且需要把num转成String类型,消耗性能。
而在实现slf4j日志接口的logback里,这样打印会节省性能
int num = 1;
logger.debug("num is {}.",num);
将 ‘{}’ 替换成 num的字符串形式,{}是占位符。
它也支持对象数组形式的参数,如
Object[] array = {1,"Hello",true};
logger.debug("Integer is {}, String is {}, Boolean is {}.",array);
在代码中使用日志语句是十分麻烦的,因为一个中型项目也会有成千上万条日志语句。所以需要用配置文件来管理日志,日后再说。