一、logback介绍

Logback是流行的log4j项目的继承者,Logback的体系结构足够通用,可以应用于不同的环境。目前,logback分为三个模块,即logback-core、logback-classic和logback-access。

logback-core模块为其他两个模块奠定了基础。

logback-classic模块可以被同化为log4j的显著改进版本。此外,logback-classic本机实现了SLF4J API,这样您就可以随时在logback和其他日志框架(如log4j或java.util)之间来回切换。

logback-access模块与Servlet容器(如Tomcat和Jetty)集成,以提供HTTP-access日志功能。请注意,您可以轻松地在logback-core之上构建自己的模块。

二、logback较log4j的优势

  1. 内核重写、测试充分、初始化内存加载更小,这使得logback性能相比log4j的性能得到了较大的提升。
  2. logback继承了log4j,并且实现了SLF4JAPI,这使得logback能够和其他日志框架相互替换。
  3. logback官方文档比较丰富。
  4. logback支持自动扫描重新加载配置文件,扫描过程比较快,并且安全,它并不需要额外的创建扫描线程。
  5. 自动移除旧的日志文件,比如那些日志文件超过很长时间的都会都当成移除的对象,可以控制已经产生日志文件的最大数量。
  6. 自动压缩已经打印出来的日志信息,压缩的这个过程是一个异步过程,在压缩过中并不受影响。

 三、logback加载

简单的分析一下logback加载的过程,当我们使用logback-classic.jar包时,应用启动后,将会按照如下的顺序进行扫描一些配置文件。

  • 在系统配置文件System Properties中寻找是否有logback.configurationFile对应的value.
  • 如果没有配置以上的属性值,将会在classpath中查找logback.groovy文件。
  • 如果找不到文件,就继续在classpath中查找logback-test.xml文件。
  • 如果找不到文件,就继续在classpath中继续查找logback.xml文件。
  • 如果找不到文件,将自动调用ch.qos.logback.classic.BasicConfigurator在控制台输出日志。

 加载不顺序如下图所示:

java backlog java backlog是什么意思_配置文件

以上任何一项找到后,就不会再继续向下查找配置文件,如果都没有找到这些文件,就会调用ch.qos.logback.classic.BasicConfigurator的configure方法,构造出一个ConsoleAppender用于向控制台输出默认配置的日志信息,输出的日志信息为"%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"。

四、logback配置文件的一些标签及其属性介绍

java backlog java backlog是什么意思_logback_02

configuration为logback.xml配置文件的根标签,主要含有一下几个属性:

  • scan:当scan被设置为true时,当配置文件发生改变,将会被重新加载,默认值为true。
  • scanPeriod:检测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认为毫秒,只有当scan为true时,这个值才默认生效,默认时间间隔为1分钟。
  • debug:当这个值被设置为true时,将会打印出logback内部日志信息,实时查看logback内部运行的状况,默认为false。

    

接下来看看<logger>与<root>,他们都是同一种元素,都为<logger>元素,但是<root>这个标签只有一个level属性,因为它的name属性就是ROOT。<logger>主要有以下几个属性:

  • name:必选属性,用来指定此<logger>约束于哪个包或者哪个特定的类。
  • level:可选属性,用来指定打印级别,五个常用的打印级别从低到高分别为TRACE、DEBUG、INFO、WARN、ERROR,如果没有设置次级别,那么当前logger会继承上级的级别。
  • additivity:可选属性,用来指定是否向上级传递打印信息,默认为true。

接下来通过代码来测试几种情况:

logback.xml的配置为:

<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="60 seconds" dubug="false">
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="DEBUG">
        <appender-ref ref="STDOUT"/>
    </root>


</configuration>

测试代码为:

public class Main {

    public static void main(String[] args) {

        Logger logger = LoggerFactory.getLogger(Object.class);
        logger.trace("-------trace---------");
        logger.debug("-------debug---------");
        logger.info("-------info---------");
        logger.warn("-------warn---------");
        logger.error("-------error---------");

    }
}

打印结果如下:

java backlog java backlog是什么意思_配置文件_03

从logback.xml中,分析出,当main方法运行时,root节点将日志级别大于等于debug的日志信息交给已经配置好的STDOUT的appender进行处理,“STDOUT”将信息打印到控制台上。
再对logback.xml进行修改,增加一个<logger>:

<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="60 seconds" dubug="false">
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
        </encoder>
    </appender>

    <logger name="java">
    </logger>
    <root level="DEBUG">
        <appender-ref ref="STDOUT"/>
    </root>


</configuration>

运行日志信息的情况如下:

java backlog java backlog是什么意思_配置文件_04

当运行的时候,会根据logger的name的属性值找到指定包下或者特定的类。

  1. 此时的logger没有指定打印级别,将继承root的打印级别,即level=DEBUG.
  2. 没有配置additivity的信息,默认为true,表示将日志信息向父<root>传递。
  3. 没有配置<appender-ref>,表示此logger不会打印任何信息。

再来一个例子:

<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="1 seconds" dubug="false">
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
        </encoder>
    </appender>

    <logger name="java" level="INFO" />
    <logger name="java.lang" level="WARN">
        <appender-ref ref="STDOUT"/>
    </logger>
    <root level="DEBUG">
        <appender-ref ref="STDOUT"/>
    </root>


</configuration>

java backlog java backlog是什么意思_java_05

 

 如果上面的例子懂了,那么再来理解一下这个例子:

  • LoggerFactory.getLogger(Object.class)首先会找到name="java.lang"包下的类,并且将日志级别等于或者大于WARN的日志信息用STDOUT的这个appender打印出来。
  • 因为name=java.lang的这个logger没有配置additity,那么additivity=true,默认是将打印信息传递给父级,即name="java"这个logger,但是由于name="java"的这个<logger>同样没有设置additivity,默认为true,这个name="java"的<logger>将打印信息继续上传,传递到<root>,将由STDOUT的appender将日志信息打印输出。

接下来了解<appender>,<appender>作为<configuration>的子节点,有两个必要的属性:

  • name:用来指定<appender>的名称,<logger>与<root>标签可以通过<appender-ref ref="名称">来用appender打印日志信息。
  • class:用来指定类的权限定名。

对于<appender>有多种,上面演示的ConsoleAppender类用来向控制台打印日志信息的。

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
        </encoder>
    </appender>

另一种是将日志信息输出到文件中的FileAppender,其内部的节点主要有以下几个:

  • <file>表示写入的文件名,可以使用相对目录也可以是绝对目录,如果上级目录不存在,则可以自动创建
  • <append>:表示文件的追加方式,如果为true,则表示直接在文件末尾进行文件的追加,如果是false,表示覆盖的追加方式。
  • <encoder>:表示日志输出的格式。
  • <prudent>:默认值为false,如果设置成true,表示日志安全的写入文件,效率较低。

以下是FileAppender类型的配置文件的情况:

<appender name="STDOUT1" class="ch.qos.logback.core.FileAppender">
        <file>
            E:/logback.log
        </file>
        <append>true</append>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
        </encoder>
        <prudent>true</prudent> <!--默认为false,如果为true,表示日志安全的写入文件-->
    </appender>

还有一种RollingFileAppender,RollingFileAppender的作用是可以滚动记录日志文件,先将指定的日志文件提交到指定文件,当符合某个条件时再将日志记录到其他文件,当符合某个条件时再将日志记录到其他文件,RollingFileAppender配置更加灵活,因此用得更多。

  • <rollingPolicy>:指定了滚动策略,定义RollingFileAppender的行为,有以下两个主要节点
  • <fileNamePattern>:必要节点,包含文件名及"%d"转换符,%d可以是时间格式,用来设置日志文件名称
     
  • <maxHistory>:可选节点,控制保留的归档文件的最大数量,如果超出数量就删除旧文件,如果设置每个月滚动且<maxHistory>是6,则只保存最近6个月的文件
<appender name="STBOUT2" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>rolling-file-%d{yyyy-MM-dd}.log</fileNamePattern><!--文件名称-->
            <maxHistory>6</maxHistory><!--控制文件的最大数量,如果超出数量就删除旧文件,改配置就表示保持最近6个月的文件-->
        </rollingPolicy>
        <encoder>
            <pattern>
                %-4relative [%thread] %-5level %logger{35} - %msg%n
            </pattern>
        </encoder>


    </appender>

<encoder> 节点主要的作用有:

  • 把日志信息转换为字节数组
  • 把字节数组写到输出流

其内部有一个<pattern>节点,用来定义输出日志的格式,使用方式"%+转换符"的方式,如果要输出%,要用\%对%进行转义。

<filter>节点

<filter>节点是<appender>的一个子节点,表示在当前日志给出的日志级别再进行一次过滤,基本用到Filter有ch.qos.logback.classic.filter.LevelFiler和ch.qos.logback.filter.ThreshouldFilter。

针对LevelFilter这个类,它指的是将指定级别日志信息打印输出。来看一下下面的这个例子

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
        </encoder>

        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

<logger name="java" level="INFO" additivity="false"/>
    <logger name="java.lang" level="WARN">
        <appender-ref ref="STDOUT"/>
    </logger>
    <root level="DEBUG">
        <appender-ref ref="STDOUT"/>
    </root>

运行结果:

java backlog java backlog是什么意思_java_06

 

这和前面讲过的例子一样,无非是加了一个<filter>过滤了日志的输出,没有加<filter>之前,该日志信息输出为WARN和ERROR级别的日志信息,因为加了<filter>,并且在标签中明确规定,只有level=ERROR级别的日志才能输出,因此最后只输出了Error级别的日志信息。

 

最后再测试一下ThreshouldFilter,配置文件如下:

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
        </encoder>

        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
    </appender>

 <logger name="java" level="INFO" additivity="false"/>
    <logger name="java.lang" level="DEBUG">
        <appender-ref ref="STDOUT"/>
    </logger>
    <root level="DEBUG">
        <appender-ref ref="STDOUT"/>
    </root>

运行结果:

java backlog java backlog是什么意思_logback_07

<logger>的name=java.lang的日志级别为DEBUG,additivity默认为true,可以将日志信息传递到父级别name=java的<logger>,但是次<logger>中没有<appender-ref >标签,所以该<logger>不打印日志信息,并且此<logger>的父级别<root>也不打印,只有name=java.lang的<logger>打印,但是增加了<filter>的ThresholdFilter就会再次进行过滤,将指定大于特定级别的日志才能打印。

以上仅仅是自己做的一点小小的总结,有不足的地方还请大家指点。