LogBack学习记录(二)体系架构

来源:互联网 发布:python 编写图形界面 编辑:程序博客网 时间:2024/05/20 23:58

logback由三个jar包组成:

 logback-core, logback-classic and logback-access。

logback-core是其他两个部分的基础,logback-classic 继续了core,并且实现了SLF4J 的接口,在一般应用中使用这两个就足够了。 logback-access提供远程日志的功能,一般用不到。


logback 的实现逻辑由三个部分组成:

Logger ,Appender ,Layout 。logger来源于 logback-classic包,而Appender 和Layout 则来自于core包。


Logger 

可以将整个系统的日志管理输出看成一个树,如果对这颗树不做任何控制,那么将输出系统中的所有日志。而每个logger就相当于这个树的每个分支,如上一张的例子中

Logger logger = LoggerFactory.getLogger(HelloWorld.class);

这里的logger是HelloWorld.class 的这个分支。并且这种树状结构构成了子父级的关系。如以“com.foo”命名的logger就是‘com.foo.bar’的父亲。真个logger的根级节点可以通过 如下代码获取:

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

在这种继承树的结构下,如果一个logger没有被赋予级别,那么他就会继承其父类的级别。

Example 1Logger nameAssigned levelEffective levelrootDEBUGDEBUGXnoneDEBUGX.YnoneDEBUGX.Y.ZnoneDEBUG如果被赋予级别了,那么将采用赋予的级别

Example 2Logger nameAssigned levelEffective levelrootERRORERRORXINFOINFOX.YDEBUGDEBUGX.Y.ZWARNWARN如果没有赋予级别,将采用其最近的父级别:

Example 4Logger nameAssigned levelEffective levelrootDEBUGDEBUGXINFOINFOX.YnoneINFOX.Y.ZnoneINFO

一条logger一般通过logger.info("msg"),logger.error("msg")等方式在代码中进行输出,info表示这条日志的级别就是info级别的,以此类推。需要注意的是,这条日志输出语句最终能否得到执行输出取决于两个方面:

一,logger 的输出时设置的级别(通过,logger.info("msg"),logger.error("msg")等方法得出

二,logback对于该logger的输出控制级别。

只有当控制级别高于设置级别时,该条日志输出语句才能运行。logback的日志级别的关系关系如下:

 TRACE < DEBUG < INFO <  WARN < ERROR.

通过一个例子说明,相关源码位于chapt2中(LogLeverTest)。

Logger logger = (Logger) LoggerFactory.getLogger("com.foo");
//将日志级别设置为info级别的
logger.setLevel(Level. INFO);
Logger barlogger = (Logger)  LoggerFactory.getLogger("com.foo.Bar");
//WARN >= INFO 可以输出
logger.warn("Low fuel level.");
//  DEBUG < INFO. 无法输出
logger.debug("Starting search for nearest gas station.");
//barlogger 继承 com.foo的级别,采用info级别
// INFO >= INFO 可以输出 
barlogger.info("Located nearest gas station.");
//  DEBUG < INFO.无法输出 
barlogger.debug("Exiting gas station search");


需要注意的是,通过相同名字获取的logger是同一个对象,这对于提高系统的效率很有好处。一般情况下,我们需要对特定的类进行日志输出,为了避免重复问题,建议当采用名称的方式创建时,采用类的完整路径的方式进行命名。

Logger x = LoggerFactory.getLogger("wombat"); Logger y = LoggerFactory.getLogger("wombat");
这里的x,y指向同一个对象。
还有,虽然logger存在这种类似树的结构,但是并不要求必须先创建父类logger然后采用创建子类logger,完全可以按照任意顺序尽心创建。

此外在LogLeverTest的例子中,采用logger.setLevel(Level. INFO);的方式进行了logger的级别设置,在实际的使用中一般将通过配置文件的方式进行设置。

Appenders and Layouts

除了可以通过logger来控制日志是否进行输出外,可以通过appender来确定日志输出的目标。日志输出目标可以是控制台,文件,远程服务器,mysql等等,并且一个logger可以绑定多个appender目标。
logger通过addAppender方法来添加appender。logger将会向每一个被添加的appender输出日志。需要注意的是,appender也存在树继承问题,如:如果console被配置到了root logger 中,那么系统中的任意的一级logger都将在console中输出。如果一个logger,命名为filelog添加了一个输出到某个文档的appender,那么filelog的子类将不但输出到console还要输出到该文档中。当然也可以通过将additivity 设置为false来关闭这中日志输出方式。当关闭后,将只输出到指定的appender中。

可以通过layout 来对输出的样式进行控制。通过将layout与appender进行关联,而appender则与logger进行关联,从而控制了logger的输出目标和样式。PatternLayout 是一种标准的logback样式,可以通过对其一些参数设置(类似于c语言的printf 方法)来实现个性化的日志输出。

For example, the PatternLayout with the conversion pattern "%-4relative [%thread] %-5level %logger{32} - %msg%n" will output something akin to:

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

The first field is the number of milliseconds elapsed since the start of the program. The second field is the thread making the log request. The third field is the level of the log request. The fourth field is the name of the logger associated with the log request. The text after the '-' is the message of the request.


提高日志效率及参数化的输出支持

很多情况下,我们会采用如下方式进行日志的输出

logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));

但是当日志级别升级为info或者更高级别时,这条语句是得不到运行的。但是String.valueof却需要每次都运行,这样会浪费系统资源,因此建议采用如下方式进行日志的输出编写方式。

if(logger.isDebugEnabled()) {   logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));}

logback支持参数式的输出样式,通过例子即可明白:
logger.debug("The new entry is {}.", entry);
当然采用这种参数的方式也可以降低系统的消耗,如果这条语句不执行,那么entty的tostring方法将不会执行。
多参数的方式
logger.debug("The new entry is {}. It replaces {}.", entry, oldEntry);

Object[] paramArray = {newVal, below, above};logger.debug("Value {} was inserted between {} and {}.", paramArray);





原创粉丝点击