zoukankan      html  css  js  c++  java
  • Java入门14---logback

    一、logback简介

    官网:https://logback.qos.ch/
    Logback 继承自 log4j,springboot默认使用的日志框架是logback,它由三个模块组成:

    1. logback-core:是其它模块的基础设施,其它模块基于它构建;
    2. logback-classic:它的地位和作用等同于 Log4J,它也被认为是 Log4J 的一个改进版,并且它实现了简单日志门面 SLF4J
    3. logback-access:作为一个与 Servlet 容器交互的模块,比如说tomcat或者 jetty,提供一些与 HTTP 访问相关的功能。

    image

    logback加载

    我们简单分析一下logback加载过程,当我们使用logback-classic.jar时,应用启动,那么logback会按照如下顺序进行扫描:

    1. 在系统配置文件System Properties中寻找是否有logback.configurationFile对应的value
    2. 在classpath下寻找是否有logback.groovy(即logback支持groovy与xml两种配置方式)
    3. 在classpath下寻找是否有logback-test.xml
    4. 在classpath下寻找是否有logback.xml

    以上任何一项找到了,就不进行后续扫描,按照对应的配置进行logback的初始化,具体代码实现可见ch.qos.logback.classic.util.ContextInitializer类的findURLOfDefaultConfigurationFile方法。

    当所有以上四项都找不到的情况下,logback会调用ch.qos.logback.classic.BasicConfigurator的configure方法,构造一个ConsoleAppender用于向控制台输出日志,默认日志输出格式为"%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"。

    二、配置文件

    1.配置框架

    image

    代码 解释
    image image

    (1)configuration

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

    (2)property

    用来定义变量值的标签,property标签有两个属性,name和value;其中name的值是变量的名称,value的值时变量定义的值。通过property定义的值会被插入到logger上下文中。定义变量后,可以使“${name}”来使用变量。如上面的xml所示。

    (3)contextName

    每个logger都关联到logger上下文,默认上下文名称为“default”。但可以使用contextName标签设置成其他名字,用于区分不同应用程序的记录

    (4)appender

    负责写日志的组件【appender让我们的应用知道怎么打、打印到哪里、打印成什么样】

    (5)logger

    用来设置某一个包或者具体的某一个类的日志打印级别以及指定appender。appender是一个日志打印的组件,这里组件里面定义了打印过滤的条件、打印输出方式、滚动策略、编码方式、打印格式等等。但是它仅仅是一个打印组件,如果我们不使用一个logger或者root的appender-ref指定某个具体的appender时,它就没有什么意义。【logger则是告诉应用哪些可以这么打。例如某个类下的日志可以使用这个appender打印或者某个包下的日志可以这么打印。】

    (6)root

    根logger,也是一种logger,且只有一个level属性;root中不能有name和additivity属性,只有一个level。

    (7)filter

    filter其实是appender里面的子元素。它作为过滤器存在,执行一个过滤器会有返回DENY,NEUTRAL,ACCEPT三个枚举值中的一个。

    DENY:日志将立即被抛弃不再经过其他过滤器
    NEUTRAL:有序列表里的下个过滤器过接着处理日志
    ACCEPT:日志会被立即处理,不再经过剩余过滤器

    2.appender 配置

    2.1 属性

    有两个属性 name和class:

    name指定appender名称;
    class指定appender的全限定名。

    上面声明的是名为GLMAPPER-LOGGERONE,class为ch.qos.logback.core.rolling.RollingFileAppender的一个appender。

    2.2 种类

    ConsoleAppender:把日志添加到控制台
    FileAppender:把日志添加到文件
    RollingFileAppender:滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件。它是FileAppender的子类

    2.3 子标签

    (1)append 子标签

    true
    如果是 true,日志被追加到文件结尾,如果是false,清空现存文件,默认是true。

    (2)filter 子标签

    在简介中提到了filter;作用就是上面说的。可以为appender 添加一个或多个过滤器,可以用任意条件对日志进行过滤。appender 有多个过滤器时,按照配置顺序执行。
    ThresholdFilter
    临界值过滤器,过滤掉低于指定临界值的日志。当日志级别等于或高于临界值时,过滤器返回NEUTRAL;当日志级别低于临界值时,日志会被拒绝。

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

    LevelFilter
    级别过滤器,根据日志级别进行过滤。如果日志级别等于配置级别,过滤器会根据onMath(用于配置符合过滤条件的操作) 和 onMismatch(用于配置不符合过滤条件的操作)接收或拒绝日志。

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

    执行一个过滤器会有返回DENY,NEUTRAL,ACCEPT三个枚举值中的一个。

    DENY:日志将立即被抛弃不再经过其他过滤器
    NEUTRAL:有序列表里的下个过滤器过接着处理日志
    ACCEPT:日志会被立即处理,不再经过剩余过滤器

    (3)file 子标签

    file 标签用于指定被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值。

    <file>
        ${logging.path}/glmapper-spring-boot/glmapper-loggerone.log
    </file>
    

    这个表示当前appender将会将日志写入到${logging.path}/glmapper-spring-boot/glmapper-loggerone.log这个目录下。

    (4)rollingPolicy 子标签

    这个子标签用来描述滚动策略的。这个只有appender的class是RollingFileAppender时才需要配置。这个也会涉及文件的移动和重命名(a.log->a.log.2018.07.22)。
    TimeBasedRollingPolicy
    最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责触发滚动。包括两个属性:

    1. FileNamePattern
    2. maxHistory

    下面这段配置表明每天生成一个日志文件,保存30天的日志文件

    <rollingPolicy 
        class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <!--日志文件输出的文件名:按天回滚 daily -->
        <FileNamePattern>
            ${logging.path}/glmapper-spring-boot/glmapper-loggerone.log.%d{yyyy-MM-dd}
        </FileNamePattern>
        <!--日志文件保留天数-->
        <MaxHistory>30</MaxHistory>
    </rollingPolicy>
    

    FixedWindowRollingPolicy
    根据固定窗口算法重命名文件的滚动策略。

    (5)encoder 子标签

    对记录事件进行格式化。它干了两件事:

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

    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}
        - %msg%n</pattern>
        <charset>UTF-8</charset>
    </encoder>
    

    目前encoder只有PatternLayoutEncoder一种类型。

    定义一个只打印error级别日志的appender

     <!-- 错误日志 appender : 按照每天生成日志文件 -->
    <appender name="ERROR-APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <append>true</append>
        <!-- 过滤器,只记录 error 级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>error</level>
        </filter>
        <!-- 日志名称 -->
        <file>${logging.path}/glmapper-spring-boot/glmapper-error.log</file>
        <!-- 每天生成一个日志文件,保存30天的日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名:按天回滚 daily -->
            <FileNamePattern>${logging.path}/glmapper-spring-boot/glmapper-error.log.%d{yyyy-MM-dd}</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <!-- 编码 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    

    3.logger 配置

    用来设置某一个包或者具体某一个类的日志打印级别、以及指定可以包含零个或者多个元素,标识这个appender将会添加到这个logger。仅有一个name属性、一个可选的level属性和一个可选的additivity属性:

    name:用来指定受此logger约束的某一个包或者具体的某一个类。
    level:用来设置打印级别(TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF),还有一个值INHERITED或者同义词NULL,代表强制执行上级的级别。如果没有设置此属性,那么当前logger将会继承上级的级别。
    addtivity:用来描述是否向上级logger传递打印信息。默认是true。

    <logger name="com.glmapper.spring.boot.controller"
            level="${logging.level}" additivity="false">
        <appender-ref ref="GLMAPPER-LOGGERONE" />
    </logger>
    

    com.glmapper.spring.boot.controller这个包下的${logging.level}级别的日志将会使用GLMAPPER-LOGGERONE来打印。

    三、举例

    1.通过控制台输出log

    <configuration>
        <!-- 默认的控制台日志输出,一般生产环境都是后台启动,这个没太大作用 -->
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <Pattern>%d{HH:mm:ss.SSS} %-5level %logger{80} - %msg%n</Pattern>
            </encoder>
        </appender>
    
        <root level="info">
            <appender-ref ref="STDOUT"/>
        </root>
    </configuration>
    
    

    2.控制台不打印,直接输出到日志文件

    <configuration>
        <!-- 属性文件:在properties文件中找到对应的配置项 -->
        <springProperty scope="context" name="logging.path"  source="logging.path"/>
        <springProperty scope="context" name="logging.level" source="logging.level.com.glmapper.spring.boot"/>
        <!-- 默认的控制台日志输出,一般生产环境都是后台启动,这个没太大作用 -->
        <appender name="STDOUT"
            class="ch.qos.logback.core.ConsoleAppender">
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <Pattern>%d{HH:mm:ss.SSS} %-5level %logger{80} - %msg%n</Pattern>
            </encoder>
        </appender>
    
        <appender name="GLMAPPER-LOGGERONE"
        class="ch.qos.logback.core.rolling.RollingFileAppender">
            <append>true</append>
            <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
                <level>${logging.level}</level>
            </filter>
            <file>
                ${logging.path}/glmapper-spring-boot/glmapper-loggerone.log
            </file>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <FileNamePattern>${logging.path}/glmapper-spring-boot/glmapper-loggerone.log.%d{yyyy-MM-dd}</FileNamePattern>
                <MaxHistory>30</MaxHistory>
            </rollingPolicy>
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
                <charset>UTF-8</charset>
            </encoder>
        </appender>
    
        <root level="info">
            <appender-ref ref="GLMAPPER-LOGGERONE"/>
        </root>
    </configuration>
    

    但是实际上我们不希望业务日志中会包括这些启动信息。所以这个时候我们就需要使用logger标签,将上面的配置文件进行简单修改:

    <logger name="com.glmapper.spring.boot.controller" level="${logging.level}"
            additivity="false">
        <appender-ref ref="GLMAPPER-LOGGERONE" />
    </logger>
    
    <root level="${logging.level}">
        <appender-ref ref="STDOUT"/>
    </root>
    

    让root指向控制台输出;logger负责打印包com.glmapper.spring.boot.controller下的日志。

    3.根据包进行日志文件隔离

    将com.glmapper.spring.boot.controller中的日志输出到glmapper-controller.log;将com.glmapper.spring.boot.service中的日志输出到glmapper-service.log。

    <!--打印日志到glmapper-service.log的appender-->
    <appender name="GLMAPPER-SERVICE"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <append>true</append>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>${logging.level}</level>
        </filter>
        <file>
            ${logging.path}/glmapper-spring-boot/glmapper-service.log
        </file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${logging.path}/glmapper-spring-boot/glmapper-service.log.%d{yyyy-MM-dd}</FileNamePattern>
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    
    <!--打印日志到glmapper-controller.log的appender-->
    <appender name="GLMAPPER-CONTROLLER"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <append>true</append>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>${logging.level}</level>
        </filter>
        <file>
            ${logging.path}/glmapper-spring-boot/glmapper-controller.log
        </file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${logging.path}/glmapper-spring-boot/glmapper-controller.log.%d{yyyy-MM-dd}</FileNamePattern>
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    
    <!--此logger约束将.controller包下的日志输出到GLMAPPER-CONTROLLER,错误日志输出到GERROR-APPENDE;GERROR-APPENDE见上面-->
    <logger name="com.glmapper.spring.boot.controller" level="${logging.level}" additivity="false">
        <appender-ref ref="GLMAPPER-CONTROLLER" />
        <appender-ref ref="ERROR-APPENDER" />
    </logger>
    
    <!--此logger约束将.service包下的日志输出到GLMAPPER-SERVICE,错误日志输出到ERROR-APPENDE;ERROR-APPENDE见上面-->
    <logger name="com.glmapper.spring.boot.service" level="${logging.level}" additivity="false">
        <appender-ref ref="GLMAPPER-SERVICE" />
        <appender-ref ref="ERROR-APPENDER" />
    </logger>
    

    假如我们不想在info里面出现error怎么办呢?很简单,我们以APPENDER-SERVICE为例,将filter过滤器进行修改:
    将下面的:

    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        <level>${logging.level}</level>
    </filter>
    

    修改为:

    <filter class="ch.qos.logback.classic.filter.LevelFilter">
        <level>ERROR</level>
        <!-- 如果命中就禁止这条日志 -->
        <onMatch>DENY</onMatch>  
        <!-- 如果没有命中就使用这条规则 -->
        <onMismatch>ACCEPT</onMismatch>  
    </filter>
    

    4.根据类进行日志文件隔离

    一般情况下比如说我们有个定时任务类需要单独来记录其日志信息,这样我们就可以考虑使用基于类维度来约束打印。

    <!--特殊功能单独appender 例如调度类的日志-->
    <appender name="SCHEDULERTASKLOCK-APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <append>true</append>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>${logging.level}</level>
        </filter>
        <file>${logging.path}/glmapper-spring-boot/scheduler-task-lock.log</file>
        <!-- 每天生成一个日志文件,保存30天的日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名:按天回滚 daily -->
            <FileNamePattern>${logging.path}/glmapper-spring-boot/scheduler-task-lock.log.%d{yyyy-MM-dd}</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <!-- 编码 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    
    <!--这里指定到了具体的某一个类-->
    <logger name="com.glmapper.spring.boot.task.TestLogTask" level="${logging.level}" additivity="true">
            <appender-ref ref="SCHEDULERTASKLOCK-APPENDER" />
            <appender-ref ref="ERROR-APPENDER" />
        </logger>
    
    

    5.调用LOG,但不打印任何信息

    <logger name="xxx" additivity="false" />
    

    6.异步写日志

    日志通常来说都以文件形式记录到磁盘,例如使用,这样的话一次写日志就会发生一次磁盘IO,这对于性能是一种损耗,因此更多的,对于每次请求必打的日志(例如请求日志,记录请求API、参数、请求时间),我们会采取异步写日志的方式而不让此次写日志发生磁盘IO,阻塞线程从而造成不必要的性能损耗。

    参考链接:
    【1】配置 logback
    【2】Java日志框架:logback详解 - 五月的仓颉 - 博客园
    【3】logback 中文手册

  • 相关阅读:
    为什么叫 React Hooks
    谈谈 Promise 以及实现 Fetch 的思路
    Mac使用tree查看目录结构
    Mac下Nginx安装教程
    Mac包管理工具brew的安装、使用及换源
    Mac安装cnpm
    10分钟快速搭建可用的springboot-web项目
    【转载】ibit-mybatis介绍
    【转载】sql-builder介绍
    Java软件工程师技能图谱
  • 原文地址:https://www.cnblogs.com/nxf-rabbit75/p/14855318.html
Copyright © 2011-2022 走看看