一、什么是Logback?
Logback是Log4j项目的继承者,由Log4j创始人Ceki Gülcü基于过去十年企业级日志系统设计经验打造。Logback比目前所有已存的日志系统要快,它提供了其它日志系统缺失的独特和有用的特性。
二、Logback架构
Logback分为3个模块:logback-core、logback-classic和logback-access。core模块为其它两个模块奠定了基础,classic模块拓展了core模块,classic模块意义上来说相当于Log4j的进阶版本。Logback-classic模块实现了SLF4J API(simple logging facade for java,日志规范,logback为其中一种实现),因此能轻易在Logback和其它日志系统(如:log4j、java.util.logging)切换。
1、Logger(日志记录器)
Loggers命名为实体,他们的名字大小写敏感并且遵循层级命名规则(如果一个logger名字加点是另一个logger名字的前缀,则这个logger是另一个logger的祖先logger)。例如,名为"com.foo"的logger是名为"com.foo.Bar"的父logger。
Root logger在logger层级中处于最上级,可以通过名字进行检索。
Logger rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
其它的日志记录器能通过LoggerFactory的静态方法getLogger检索,方法参数的名字为日志记录器的名字,下面是Logger接口的基本方法。
package org.slf4j; public interface Logger { // Printing methods: public void trace(String message); public void debug(String message); public void info(String message); public void warn(String message); public void error(String message); }
2、Effective Level & Level Inheritence(有效等级和等级继承)
日志记录器可以指定级别,如:TRACE、DEBUG、INFO、WARN、ERROR。如果给定的日志记录器没有指定级别,那么它会继承最近祖先的级别,root日志记录器默认被分配的级别为DEBUG,下面是一些例子:
日志记录器名字 | 分配的级别 | 有效级别 |
ROOT | DEBUG | DEBUG |
X | NONE | DEBUG |
X.Y | NONE | DEBUG |
X.Y.Z | NONE | DEBUG |
日志记录器名字 | 分配的级别 | 有效级别 |
ROOT | EROOR | EROOR |
X | INFO | INFO |
X.Y | DEBUG | DEBUG |
X.Y.Z | WARN | WARN |
日志记录器名字 | 分配的级别 | 有效级别 |
ROOT | DEBUG | DEBUG |
X | INFO | INFO |
X.Y | NONE | INFO |
X.Y.Z | EROOR | EROOR |
日志记录器名字 | 分配的级别 | 有效级别 |
ROOT | DEBUG | DEBUG |
X | INFO | INFO |
X.Y | NONE | INFO |
X.Y.Z | NONE | INFO |
3、 打印方法基本选择规则
如果打印方法级别高于日志记录器的有效级别,那么日志请求是有效的,例如:日志请求的级别是p,日志记录器的有效级别为q,如果日志请求可用,则p>=q。级别排序:TRACE<=DEBUG<=INFO<=WARN<=ERROR<=OFF。
下面图表描述了选择规则如何运作。
日志请求 | 日志记录器有效级别 | |||||
TRACE | DEBUG | INFO | WARN | ERROR | OFF | |
TRACE | YES | NO | NO | NO | NO | NO |
DEBUG | YES | YES | NO | NO | NO | NO |
INFO | YES | YES | YES | NO | NO | NO |
WARN | YES | YES | YES | YES | NO | NO |
ERROR | YES | YES | YES | YES | YES | NO |
4、检索日志记录器
调用LoggerFactory.getLogger方法并指定相同的名字会返回相同的logger对象。例如x和y引用相同的logger对象:
Logger x = LoggerFactory.getLogger("wombat"); Logger y = LoggerFactory.getLogger("wombat");
5、Appenders & Layouts(输出源和布局)
日志输出的目的地叫做appender,目前存在的输出源有控制台、文件、远程套接字服务器、数据库和JMS等。
到指定日志记录器的日志请求会被转发到日志记录器的所有输出源以及高层级的输出源,什么叫高层级输出源,其实就是祖先日志记录器里配置的输出源。换句话说,输出源是叠加性地继承。下面图标清楚地展示了输出源的叠加性。
6、参数化日志打印
logback-classic中的日志记录器实现了SLF4J中的Logger接口,里面的日志打印方法在最小化对代码可读性造成影响的同时主要用来改善性能。
logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
上面这种日志打印方法会增加构造消息参数的性能,不管消息是否可以被打印,都会把整型变量i和entry[i]转换成字符串,然后再进行字符串拼接。
一种避免参数构造的可选方法为加上判断,如下:
if(logger.isDebugEnabled()) { logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i])); }
上面这种方式如果debugging不可用不会增加参数构造的性能,但如果debugging可用,那么会有两处地方会耗性能,一处在判断debug是否可用,一处在参数构造。
更好的方式:
Object entry = new SomeObject(); logger.debug("The entry is {}.", entry);
通过上面这种方式,只有确定打印日志时,日志记录器实现才会格式化消息并且替代占位符。换句话说,这种形式在日志打印不可用的时候不会造成参数构造时的性能消耗。
logger.debug("The new entry is "+entry+"."); logger.debug("The new entry is {}.", entry);
上面两条语句会产生相同的输出,但当日志打印不可用时,第二种方式会胜过第一种方式。
logger.debug("The new entry is {}. It replaces {}.", entry, oldEntry);
两个参数可以采用如上方式。
Object[] paramArray = {newVal, below, above}; logger.debug("Value {} was inserted between {} and {}.", paramArray);
三个或以上参数可以采用如上方式。