一文理解logback

Logback是由log4j创始人设计的又一个开源日志组件,可以认为是log4j的改进版本。非常简单灵活,是目前主流的日志记录工具。推荐你也开始使用logback。

很多人都会使用log4j或logback。但我也相信,大多数人其实并不是很好的理解了它们,大部分场景下都是复制个配置文件改下就应付了。其实稍微花点时间研究下,就能更加合理的配置和使用logback。

开始使用

maven或gradel引入logback的两个jar包即可开始使用了。

gradle:

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.11'
    compile group: 'ch.qos.logback', name: 'logback-core', version: '1.1.8'
    compile group: 'ch.qos.logback', name: 'logback-classic', version: '1.1.8'

}

新建个类即可开始使用

package bumishi.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by @bumishi(http://bumishi.cn) on 2017/1/19.
 */
public class LogbackStudy {

    public static void main(String[] arg){
        //创建一个名字为test的logger
        Logger logger= LoggerFactory.getLogger("test");
        logger.debug("debug");
        logger.info("info");
        logger.warn("warn");
        logger.error("error");

    }
}

logback需要一个配置文件来描述以怎样的格式输出日志,以及日志要输出到哪里去,以及日志的级别等。

加载配置文件

程序启动时,logback先从classpath中查找一个名为logback.groovy的配置文件

如果没有找到,再查找名为logback-test.xml的文件

如果没有找到,再查找名为logback.xml的文件

如果没有找到,会尝试从classpath的 META-INF\services\ch.qos.logback.classic.spi.Configurator文件中解析一个实现了 com.qos.logback.classic.spi.Configurator接口的完整类作为一个配置对象来配置

如果还是没有找到可以配置的方式,那么logback默认地会调用BasicConfigurator,创建一个最小化配置。最小化配置由一个关联到根logger的ConsoleAppender 组成。输出用模式为

%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n

的PatternLayoutEncoder 进行格式化。根logger 默认级别是 DEBUG。

此外,我们也可以在启动程序时通过命令行参数指定。
通过指定一个名为 "logback.configurationFile"的Java system属性,这个属性的值可以是一个url,一个classpath中的文件,或者一个外部的文件。

java -Dlogback.configurationFile=/path/to/config.xml chapters.configuration.MyApp1

需要注意的是,这个文件的扩展名必须是.xml或.groovy,其它扩展名将会被忽略。

通常,我们在测试环境下使用logback-test.xml,生产环境使用logback.xml

这里,我们创建一个logback-test.xml


    
        
            %d{MM/dd/yyyy HH:mm:ss} %-5level [%thread%X{sourceThread}]%logger{24} - %msg%n
        
    

    
        /var/log/admin-manage/log.log
        
            /var/log/admin-manage/log.%d{yyyy-MM-dd}.log.gz
            7
        
        
            %d{MM/dd/yyyy HH:mm:ss} %-5level ${version} [%thread]%logger{16} - %msg%n
            
        
    

       
        
    


我们来逐一解释配置中的项目。

configuration是根节点。appender是用来表示日志要输出到哪里的组件。encoder用来将日志信息解析成具有一定格式的信息。

我们创建了一个名为STDOUT,类型为ch.qos.logback.core.ConsoleAppender的appender,这个appender用于把日志信息输出到控制台,就像System.out.println()一样。其中的pattern表示一个格式,%d表示日期,%d{MM/dd/yyyy HH:mm:ss} 表示以MM/dd/yyyy HH:mm:ss 这个格式显示当前时间,%thread表示线程名,%-5:级别从左显示5个字符宽度,level是日志级别,%msg:日志消息,%n是换行符。我们根据输出来的日志信息就能明白其中的含义。

我们同时创建了一个名为FILE,类型为ch.qos.logback.core.rolling.RollingFileAppender的appender,这是一个可以将日志输出到一个文件的appender,并且可以按照日期自动滚动,不至于让所有日志都写在一个文件上。rollingPolicy是一种文件滚动策略,可以让日志文件按日或按月归档。
上面的配置表示按照每天生成日志文件,最多保留7天,日志文件存放在/var/log/admin-manage/log.log。每过一天,日志名就变成类似log.2017-01-19.log.gz的形式。

只配置appender并不能直接输出日志,logback中,appender是要给logger用的,我们需要配置logger。

每个logger都是ch.qos.logback.classic.Logger的一个实例,每个logger有一个名称,有一个级别,以及0个或多个appender,这意味着同一条日志信息可以同时输出到多个地方去。

整个logback中,最为重要的部分就是理解logger的继承层次了,绝大多数人并不理解。理解了这个后你就能随心所欲的使用logback来按你你想要的方式来输出日志了。

logback及log4j中logger的继承层次都类似。

logger是一个具备父子关系的树结构。最顶端的logger是一个固定名称为ROOT的logger,所有的logger都是它的孩子,就像Java的Object一样。然而logger的继承层次却是完全根据logger的name来决定的。logback根据logger的name按照"."来进行分割,就像Java的包名一样。名为com.bumishi的logger是名为com的logger的子logger,名为com的logger是ROOT的子logger,任何一个logger如果向上找不到父logger那它的父logger就是ROOT。

在logback的配置文件中,ROOT logger用表示,其它logger用表示。每个logger都有几个属性:

name:名称,根据此名称建立继承层次结构

level:级别,如debug,info,warn,error等,级别依次越来越高,给logger指定高级别时,低于这个级别的日志信息将不会被发送到appender。

additivity:表示此logger输出的日志是否要向上传递到父logger的appender,默认是true。传递到父logger的意思是,日志信息除了在当前logger的appender中输出,还会在父logger中的appender输出。

appender列表
一个logger可以有0个或多个appdner,通过appender-ref节点引用前面定义的appender。

上面的配置中,我们只配置了一个根logger——root,指定了它的级别为debug,指定了appender输出到控制台。

由于配置的是root,所有这个配置会对所有的logger有效,我们在应用中任何名称的logger输出的所有级别大于或等于debug的信息都将输出到控制台中。

我们运行上述程序即可看到效果:

01/19/2017 21:58:12 DEBUG [main]test - debug
01/19/2017 21:58:12 INFO  [main]test - info
01/19/2017 21:58:12 WARN  [main]test - warn
01/19/2017 21:58:12 ERROR [main]test - error

我们尝试定义多个不同的logger


    
        
            %d{MM/dd/yyyy HH:mm:ss} %-5level [%thread%X{sourceThread}]%logger{24} - %msg%n
        
    

    
        /var/log/admin-manage/log.log
        
            /var/log/admin-manage/log.%d{yyyy-MM-dd}.log.gz
            7
        
        
            %d{MM/dd/yyyy HH:mm:ss} %-5level ${version} [%thread]%logger{16} - %msg%n
            
        
    

    
    
    
        
    
    
        
    

    
        
    


在Java中分别运行下不同logger的输出结果

package bumishi.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by @bumishi(http://bumishi.cn) on 2017/1/19.
 */
public class LogbackStudy {

    public static void main(String[] arg) {
        print("test1");
        print("test2");
        print("test3");
        print("test4");
    }

    public static void print(String name) {
        Logger logger = LoggerFactory.getLogger(name);
        logger.debug("debug");
        logger.info("info");
        logger.warn("warn");
        logger.error("error");
    }
}

结果:

1/19/2017 22:58:24 INFO  [main]test1 - info
01/19/2017 22:58:24 WARN  [main]test1 - warn
01/19/2017 22:58:24 ERROR [main]test1 - error
01/19/2017 22:58:24 WARN  [main]test3 - warn
01/19/2017 22:58:24 ERROR [main]test3 - error
01/19/2017 22:58:24 WARN  [main]test4 - warn
01/19/2017 22:58:24 WARN  [main]test4 - warn
01/19/2017 22:58:24 ERROR [main]test4 - error
01/19/2017 22:58:24 ERROR [main]test4 - error

你是否能理解这个结果呢?

我一个一个解释下:

一文理解logback_第1张图片

如果我们在加两个这样的logger

 
        
    
    
        
    

用com.test4打印,那么就会出现3次了。

 print("com.test4");
01/19/2017 23:10:36 WARN  [main]com.test4 - warn
01/19/2017 23:10:36 WARN  [main]com.test4 - warn
01/19/2017 23:10:36 WARN  [main]com.test4 - warn
01/19/2017 23:10:36 ERROR [main]com.test4 - error
01/19/2017 23:10:36 ERROR [main]com.test4 - error
01/19/2017 23:10:36 ERROR [main]com.test4 - error

专注技术研究

你可能感兴趣的:(一文理解logback)