作者: Ceki Gülcü,和log4j作者是同一个人,logback的性能和使用都提升了很多,如果没有特殊要求,项目中直接使用logback吧。
上一篇《项目中日志框架的正确使用方式slf4j+logback》介绍了起源和大概的原理,至少应该了解以下内容:
- logback无缝衔接SLF4J(也是Ceki Gülcü的作品,日志门面)
- 项目中需要包含对
slf4j-api-*.jar
的依赖 - 项目中需要包含对
logback-core.jar
和logback-classic.jar
的依赖
使用方法还是千篇一律的写法:
package chapters.introduction;
// 这里并没有引入logback相关文件,在记录日志时也是只使用SLF4j提供的接口
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld1 {
public static void main(String[] args) {
// 这句话会根据classpath下的引用查找SLF4j的具体实现类,可参照上一篇
Logger logger = LoggerFactory.getLogger("chapters.introduction.HelloWorld1");
logger.debug("Hello world.");
}
}
由三大组件构成
- logback-core:核心组件,为其他两个提供支撑
- logback-classic:扩展Logback-core,而且是日志功能的真实实现,可理解为log4j的进阶版本
- logback-access:可结合logback-core用于http容器的日志功能,如tomcat,不常用
由三大主类构成
- Logger:在
logback-classic
中实现,日志记录器 - Appender :在
logback-core
中实现,打印到什么地方 - Layout.:在
logback-core
中实现,设置打印格式
Logger介绍
获取Logger
通过
LoggerFactory.getLogger(A)
获取Logger
,如果A相同,Logger
始终是同一个对象
Logger aLogger = LoggerFactory.getLogger("com.foo");
Logger bLogger = LoggerFactory.getLogger("com.foo");
那么:aLogger和bLogger引用完全相同的Logger对象。
日志记录等级及关系:TRACE
< DEBUG
<INFO
< WARN
<ERROR
日志记录等级有2个用处:
- 在代码逻辑中输出日志时,需要明确等级,如
logger.info("打印普通日志")
,明确了等级=info
- 日志全局配置中需要指定真实打印日志的等级,如
logging.level=warn
,只有大于>warn
的日志等级才会真实被打印,上面的info
不会被打印
Logger的继承关系
为什么会存在继承关系?
比如在使用logger
的时候并没有配置level
,怎么办?
这时候就是根据继承关系向上查找,直到找到后生效。
如果都没有设置怎么办?
不会发生这种情况,因为根记录器提供一个默认的level
,并设为debug
,也就是保底的配置。
如何继承?看一个示例:
//ROOT_LOGGER_NAME固定为ROOT,是所有日志记录器的根(Root)
Logger rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
Logger faLogger = LoggerFactory.getLogger("com.foo");
Logger chLogger = LoggerFactory.getLogger("com.foo.bar");
只要缺省了某一个配置,就会沿着继承关系逐级向上查找,直到找到为止!
- Level的继承关系:如果自身设置了level,则使用自身的生效;否则向上查找;
- Appender的继承关系:默认是累加的,即自身和父级的都会生效(这种累加会一直向上查找,直到遇到附加
flag=false
的为止),当然可以设置flag=false
禁用累加方式,Appender比较复杂,见下表:
Logger | 设置Appender | 附加Flag | 最终输出目标 | 备注 |
---|---|---|---|---|
root | A1 | 不适用 | A1 | 根日志记录器不需要设置Flag |
x | A-x1, A-x2 | true | A1, A-x1, A-x2 | 其中A1是继承了root |
x.y | none | true | A1, A-x1, A-x2 | 继承了root和x |
x.y.z | A-xyz1 | true | A1, A-x1, A-x2, A-xyz1 | 继承了root、x和x.y |
security | A-sec | false | A-sec | 不继承父级 |
security.access | none | true | A-sec | 只继承security,因为security设置了false,所以不再继续继承祖先 |
Appender
一个Logger
可以被打印到多个Appender
指定的位置,如同时打印到文件或console。
Layout
用来控制打印到Appender
的输出格式,比如%-4relative [%thread] %-5level %logger{32} - %msg%n
输出以下格式:
176 [main] DEBUG manual.architecture.HelloWorld2 - Hello world.
日志参数的推荐写法
通常,记录日志的写法如下:
logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
无论该日志是否打印,日志内容中的+
都会执行解析,增加了开销
,所以更推荐以下写法:
Object entry = new SomeObject();
//只有需要打印`debug`级别的日志时,才会解析日志内容,平时无开销
logger.debug("The entry is {}.", entry);