zoukankan      html  css  js  c++  java
  • Java日志框架(二)

    最流行的日志框架解决方案

    按笔者理解,现在最流的日志框架解决方案莫过于SLF4J + LogBack。其有以下几个优点:

    • LogBack 自身实现了 SLF4J 的日志接口,不需要 SLF4J 去做进一步的适配。
    • LogBack 自身是在 Log4J 的基础上优化而成的,其运行速度和效率都比 LOG4J 高。
    • SLF4J + LogBack 支持占位符,方便日志代码的阅读,而 LOG4J 则不支持。

    从上面几点来看,SLF4J + LogBack是一个较好的选择。

    LogBack 被分为3个组件:logback-core、logback-classic 和 logback-access。

    • logback-core 提供了 LogBack 的核心功能,是另外两个组件的基础。
    • logback-classic 则实现了 SLF4J 的API,所以当想配合 SLF4J 使用时,需要将 logback-classic 引入依赖中。
    • logback-access 是为了集成Servlet环境而准备的,可提供HTTP-access的日志接口。

    了解 LogBack 日志的日志流向,对于我们后面学习日志框架的配置很有帮助。从下图可以看出 LogBack 的日志记录数据流是从 Class 或 Package 流到 Logger,再从Logger到Appender,最后从Appender到具体的输出终端。

    LogBack日志流向描述图

    LogBack配置文件可以分为几个节点,其中 Configuration 是根节点,Appender、Logger、Root是Configuration的子节点。

    appender节点

    <appender>是<configuration>的子节点,是负责写日志的组件。appender有两个必要属性name、class 。name指定appender的名称,class指定appender的全限定名
    class,主要包括:

    • ch.qos.logback.core.ConsoleAppender 控制台输出
    • ch.qos.logback.core.FileAppender 文件输出
    • ch.qos.logback.core.RollingFileAppender 文件滚动输出
    <?xml version="1.0" encoding="utf-8"?> 
    <configuration debug="true" scan="true" scanPeriod="2">
        <!-- conf consoel out -->
        <appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
        </appender>
    
        <!-- conf file out -->
        <appender name="file_out" class="ch.qos.logback.core.FileAppender">
        </appender>
    
        <!-- conf file out -->
        <appender name="file_out" class="ch.qos.logback.core.RollingFileAppender">
        </appender>
    
        <root></root>
        <logger></logger>
    </configuration>

    ConsoleAppender

    把日志添加到控制台,有如下节点:

    • <encoder> : 对日志进行格式化。
    • <target> : 字符串System.out 或者 System.err, 默认 System.out;
    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        <!-- conf consoel out -->
      <appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>%date [%thread] %-5level %logger - %message%newline</pattern>
            </encoder>
      </appender>
    
      <root level="INFO">             
        <appender-ref ref="console_out" />   
      </root>     
    </configuration>

    FileAppender

    把日志添加到文件,有如下节点:

    • <file>:被写入的文件名,可以是相对目录 , 也可以是绝对目录 , 如果目录不存在则会自动创建。
    • <append>:如果是true , 日志被追加到文件结尾 , 如果是false,清空现存文件 , 默认是true。
    • <encoder>:对日志进行格式化 [具体的转换符说明请参见官网.]
    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        <appender name="file_out" class="ch.qos.logback.core.FileAppender">
            <file>logs/debug.log</file>
            <encoder>
                <pattern>%date [%thread] %-5level %logger - %message%newline</pattern>
            </encoder>
        </appender>
    </configuration>

    rollingFileAppender

    滚动纪录文件,先将日志记录到指定文件,当符合某种条件时,将日志记录到其他文件,有如下节点:

    • <file>:被写入的文件名,可以是相对目录,也可以解决目录,如果目录不存在则自动创建。
    • <append>:如果是true,日志被追加到文件结尾,如果是false,清空现存文件,默认是true。
    • <encoder>:对日志进行格式化。
    • <rollingPolicy>:当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名。

    rollingPolicy

    • TimeBaseRollingPolicy :最常用的滚动策略,根据时间来制定滚动策略,即负责滚动也负责触发滚动。有如下节点;

      • <fileNamePattern>:必要节点,包含文件及“%d” 转换符,“%d”可以包含一个java.text.SimpleDateFormat 制定的时间格式,如:%d{yyyy-MM},如果直接使用%d ,默认格式是 yyyy-MM-dd。
      • <maxHistory>:可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件,假设设置每个月滚动,且<maxHistory> 是 6,则只保存最近6个月的文件,删除之前的旧文件,注意:删除旧文件是哪些为了归档而创建的目录也会被删除。
      • <filenamePattern>:必须包含“%i” 例如:设置最小值,和最大值分别为1和2,命名模式为 log%i.log,会产生归档文件log1.log和log2.log,还可以指定文件压缩选项,例如:log%i.log.gz 或者 log%i.log.zip
    • triggeringPolicy:告知RollingFileAppender,激活RollingFileAppender滚动。
    <!-- 03:conf errorAppender out -->
    <appender name="errorAppender" class="ch.qos.logback.core.RollingFileAppender">
        <file>logs/error.log</file>
        <!-- 设置滚动策略 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <!--设置日志命名模式--> 
            <fileNamePattern>errorFile.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!--最多保留30天log-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <!-- 超过150MB时,触发滚动策略 -->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <maxFileSize>150</maxFileSize>
        </triggeringPolicy>
        <encoder>
            <pattern>%d [%p] %-5level %logger - %msg%newline</pattern>
        </encoder>
    </appender>

    logger节点

    logger是<configuration>的子节点,来设置某一个包或者具体的某一个类的日志打印级别,以及指定<appender>。logger仅有一个name属性,两个可选属性 level/addtivity。

    • name:用来指定受此loger约束的某一个包或者具体的某一个类。
    • level:用来设置打印级别,大小写无关。可选值有TRACE、DEBUG、INFO、WARN、ERROR、ALL和OFF。还有一个特俗值INHERITED 或者 同义词NULL,代表强制执行上级的级别。如果未设置此属性,那么当前logger将会继承上级的级别。
    • addtivity:是否向上级logger传递打印信息,默认为true;

    <logger>可以包含零个或多个<appender-ref>元素,表示这个appender将会添加到logger。

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        <!-- conf consoel out -->
        <appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <!-- 过滤掉非INFO级别 -->
                <level>INFO</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
        </appender>
    
        <!--  conf infoAppender out -->
        <appender name="infoAppender" class="ch.qos.logback.core.RollingFileAppender">
            <file>logs/info.log</file>
            <!-- 设置滚动策略 -->
            <rollingPoliy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
                <!--设置日志命名模式--> 
                <fileNamePattern>infoFile.%d{yyyy-MM-dd}.log</fileNamePattern>
                <!--最多保留30天log-->
                <maxHistory>30</maxHistory>
            </rollingPoliy>
            <!-- 超过150MB时,触发滚动策略 -->
            <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
                <maxFileSize>150</maxFileSize>
            </triggeringPolicy>
            <encoder>
                <pattern>%d [%p] %-5level %logger - %msg%newline</pattern>
            </encoder>
        </appender>
    
        <!-- 添加两个appender节点 -->
        <logger name="logback.olf.log" level="info">
            <appender-ref ref = "console_out"/>
            <appender-ref ref = "infoAppender"/>
        </logger>
    </configuration>

    root节点

    元素配置根logger。该元素有一个level属性,没有name属性,因为已经被命名 为root。Level属性的值大小写无关,其值为下面其中一个字符串:TRACE、DEBUG、INFO、 WARN、ERROR、ALL 和 OFF。如果 root 元素没 有引用任何 appender,就会失去所有 appender。

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        <!-- conf consoel out -->
        <appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <!-- 过滤掉非INFO级别 -->
                <level>INFO</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
        </appender>
    
        <!-- 01:conf infoAppender out -->
        <appender name="infoAppender" class="ch.qos.logback.core.RollingFileAppender">
    
            <file>logs/info.log</file>
            <!-- 设置滚动策略 -->
            <rollingPoliy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
                <!--设置日志命名模式--> 
                <fileNamePattern>infoFile.%d{yyyy-MM-dd}.log</fileNamePattern>
                <!--最多保留30天log-->
                <maxHistory>30</maxHistory>
            </rollingPoliy>
            <!-- 超过150MB时,触发滚动策略 -->
            <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
                <maxFileSize>150</maxFileSize>
            </triggeringPolicy>
            <encoder>
                <pattern>%d [%p] %-5level %logger - %msg%newline</pattern>
            </encoder>
        </appender>
    
        <!-- 02:conf debugAppender out -->
        <appender name="debugAppender" class="ch.qos.logback.core.RollingFileAppender">
            <file>logs/debug.log</file>
            <!-- 设置滚动策略 -->
            <rollingPoliy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
                <!--设置日志命名模式--> 
                <fileNamePattern>debugFile.%d{yyyy-MM-dd}.log</fileNamePattern>
                <!--最多保留30天log-->
                <maxHistory>30</maxHistory>
            </rollingPoliy>
            <!-- 超过150MB时,触发滚动策略 -->
            <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
                <maxFileSize>150</maxFileSize>
            </triggeringPolicy>
            <encoder>
                <pattern>%d [%p] %-5level %logger - %msg%newline</pattern>
            </encoder>
        </appender>
    
        <!-- 03:conf errorAppender out -->
        <appender name="errorAppender" class="ch.qos.logback.core.RollingFileAppender">
            <file>logs/error.log</file>
            <!-- 设置滚动策略 -->
            <rollingPoliy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
                <!--设置日志命名模式--> 
                <fileNamePattern>errorFile.%d{yyyy-MM-dd}.log</fileNamePattern>
                <!--最多保留30天log-->
                <maxHistory>30</maxHistory>
            </rollingPoliy>
            <!-- 超过150MB时,触发滚动策略 -->
            <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
                <maxFileSize>150</maxFileSize>
            </triggeringPolicy>
            <encoder>
                <pattern>%d [%p] %-5level %logger - %msg%newline</pattern>
            </encoder>
        </appender>
    
        <root level="ALL">
            <appender-ref ref="infoAppender"/>
            <appender-ref ref="debugAppender"/>
            <appender-ref ref="errorAppender"/>
        </root>
    </configuration>

    filter过滤节点

    级别过滤器(LevelFilter)

    LevelFilter 根据记录级别对记录事件进行过滤。如果事件的级别等于配置的级别,过滤 器会根据 onMatch 和 onMismatch 属性接受或拒绝事件。下面是个配置文件例子:

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        <!-- conf consoel out -->
        <appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <!-- 过滤掉非INFO级别 -->
                <level>INFO</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
    
            <encoder>
                <pattern>%-4relative [%thread] %-5level %logger{30} - %msg%n</pattern>
            </encoder>
        </appender>
        <root level="DEBUG">
            <appender-ref ref="console_out" />
        </root>
    </configuration>

    临界值过滤器(ThresholdFilter)

    ThresholdFilter过滤掉低于指定临界值的事件。

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        <!-- conf consoel out -->
        <appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
            <filter class="ch.qos.logback.classic.filter.ThresholdFilter">  
            <!-- 过滤掉TRACE和DEBUG级别的日志 -->
                <level>INFO</level> 
            </filter>
    
            <encoder>
                <pattern>%-4relative [%thread] %-5level %logger{30} - %msg%n</pattern>
            </encoder>
        </appender>
        <root level="DEBUG">
            <appender-ref ref="console_out" />
        </root>
    </configuration>

    求值过滤器(EvaluatorFilter)

    评估是否符合指定的条件

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        <!-- conf consoel out -->
        <appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
            <filter class="ch.qos.logback.classic.filter.EvaluatorFilter">  
                 <evaluator>
                 <!--过滤掉所有日志中不包含hello字符的日志-->
                    <expression>
                        message.contains("hello")
                    </expression>
                    <onMatch>NEUTRAL</onMatch>
                    <onMismatch>DENY</onMismatch>
                 </evaluator>
            </filter>
    
            <encoder>
                <pattern>%-4relative [%thread] %-5level %logger{30} - %msg%n</pattern>
            </encoder>
        </appender>
        <root level="DEBUG">
            <appender-ref ref="console_out" />
        </root>
    </configuration>

    匹配器(Matchers)

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        <!-- conf consoel out -->
        <appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
            <filter class="ch.qos.logback.classic.filter.EvaluatorFilter">  
                 <evaluator> 
                    <matcher>
                        <Name>odd</Name>
                        <!-- 过滤掉序号为奇数的语句-->
                        <regex>statement [13579]</regex>
                    </matcher>
                    <expression>odd.matches(formattedMessage)</expression>
                    <onMatch>NEUTRAL</onMatch>
                    <onMismatch>DENY</onMismatch>
                 </evaluator>
            </filter>
    
            <encoder>
                <pattern>%-4relative [%thread] %-5level %logger{30} - %msg%n</pattern>
            </encoder>
        </appender>
        <root level="DEBUG">
            <appender-ref ref="console_out" />
        </root>
    </configuration>

    下面是一个我常用的logback.xml配置文件,供大家参考:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <configuration debug="true" scan="true" scanPeriod="30 seconds"> 
    
      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> 
        <!-- encoders are  by default assigned the type
             ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%level] - %m%n</pattern>
    
            <!-- 常用的Pattern变量,大家可打开该pattern进行输出观察 -->
            <!-- 
              <pattern>
                  %d{yyyy-MM-dd HH:mm:ss} [%level] - %msg%n
                  Logger: %logger
                  Class: %class
                  File: %file
                  Caller: %caller
                  Line: %line
                  Message: %m
                  Method: %M
                  Relative: %relative
                  Thread: %thread
                  Exception: %ex
                  xException: %xEx
                  nopException: %nopex
                  rException: %rEx
                  Marker: %marker
                  %n
    
              </pattern>
               -->
        </encoder>
      </appender>
    
      <!-- 按日期区分的滚动日志 -->
      <appender name="ERROR-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
          <file>logs/error.log</file>
    
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%class:%line] - %m%n</pattern>
        </encoder>
    
          <filter class="ch.qos.logback.classic.filter.LevelFilter">
          <level>ERROR</level>
          <onMatch>ACCEPT</onMatch>
          <onMismatch>DENY</onMismatch>
        </filter>
    
          <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
          <!-- daily rollover -->
          <fileNamePattern>error.%d{yyyy-MM-dd}.log.zip</fileNamePattern>
    
          <!-- keep 30 days' worth of history -->
          <maxHistory>30</maxHistory>
        </rollingPolicy>
      </appender>
    
      <!-- 按文件大小区分的滚动日志 -->
      <appender name="INFO-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
          <file>logs/info.log</file>
    
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%class:%line] - %m%n</pattern>
        </encoder>
    
          <filter class="ch.qos.logback.classic.filter.LevelFilter">
          <level>INFO</level>
          <onMatch>ACCEPT</onMatch>
          <onMismatch>DENY</onMismatch>
        </filter>
    
          <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
          <fileNamePattern>info.%i.log</fileNamePattern>
          <minIndex>1</minIndex>
          <maxIndex>3</maxIndex>
        </rollingPolicy>
    
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
          <maxFileSize>5MB</maxFileSize>
        </triggeringPolicy>
    
      </appender>
    
      <!-- 按日期和大小区分的滚动日志 -->
      <appender name="DEBUG-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
          <file>logs/debug.log</file>
    
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%class:%line] - %m%n</pattern>
        </encoder>
    
          <filter class="ch.qos.logback.classic.filter.LevelFilter">
          <level>DEBUG</level>
          <onMatch>ACCEPT</onMatch>
          <onMismatch>DENY</onMismatch>
        </filter>
    
          <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
          <!-- rollover daily -->
          <fileNamePattern>debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
    
          <timeBasedFileNamingAndTriggeringPolicy
                class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <!-- or whenever the file size reaches 100MB -->
            <maxFileSize>100MB</maxFileSize>
          </timeBasedFileNamingAndTriggeringPolicy>
    
        </rollingPolicy>
    
      </appender>
    
       <!-- 级别阀值过滤 -->
      <appender name="SUM-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
          <file>logs/sum.log</file>
    
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%class:%line] - %m%n</pattern>
        </encoder>
    
        <!-- deny all events with a level below INFO, that is TRACE and DEBUG -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
          <level>INFO</level>
        </filter>
    
          <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
          <!-- rollover daily -->
          <fileNamePattern>debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
    
          <timeBasedFileNamingAndTriggeringPolicy
                class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <!-- or whenever the file size reaches 100MB -->
            <maxFileSize>100MB</maxFileSize>
          </timeBasedFileNamingAndTriggeringPolicy>
    
        </rollingPolicy>
    
      </appender>
    
      <root level="debug">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="ERROR-OUT" />
        <appender-ref ref="INFO-OUT" />
        <appender-ref ref="DEBUG-OUT" />
        <appender-ref ref="SUM-OUT" />
      </root>
    </configuration>

    日志系统转换指南

    在实际的日志转换过程中,SLF4J其实是充当了一个中介的角色。例如当我们一个项目原来是使用LOG4J进行日志记录,但是我们要换成LogBack进行日志记录。此时我们需要先将LOG4J转换成SLF4J日志系统,再从SLF4J日志系统转成LogBack日志系统。

    从日志框架转向SLF4J

    • jul-to-slf4j:jdk-logging到slf4j的桥梁
    • log4j-over-slf4j:log4j1到slf4j的桥梁
    • jcl-over-slf4j:commons-logging到slf4j的桥梁

    从SLF4J转向具体的日志框架

    • slf4j-jdk14:slf4j到jdk-logging的桥梁
    • slf4j-log4j12:slf4j到log4j1的桥梁
    • log4j-slf4j-impl:slf4j到log4j2的桥梁
    • logback-classic:slf4j到logback的桥梁
    • slf4j-jcl:slf4j到commons-logging的桥梁

    日志技术框架一览

    • JUL:JDK中的日志记录工具,也常称为JDKLog、jdk-logging。
    • LOG4J1:一个具体的日志实现框架。
    • LOG4J2:一个具体的日志实现框架,是LOG4J1的下一个版本。
    • LOGBACK:一个具体的日志实现框架,但其性能更好。
    • JCL:一个日志门面,提供统一的日志记录接口,也常称为commons-logging。
    • SLF4J:一个日志门面,与JCL一样提供统一的日志记录接口,可以方便地切换看具体的实现框架。

    JUL、LOG4J1、LOG4J2、LOGBACK是日志实现框架,而JCL、SLF4J是日志实现门面。


    原文链接:https://www.imooc.com/article/21908

  • 相关阅读:
    java 自定义表单 动态表单 表单设计器 工作流引擎 flowable 设计方案
    设置Springboot返回jackson数据序列化
    SpringCloud Alibaba 报 AbstractMethodError 是版本兼容问题导致
    Springboot进阶JDBC、Druid、Mybatis、Swagger、SpringMVC、Mail
    java 自定义表单 动态表单 表单设计器 工作流引擎 flowable 项目源码
    springcloud Alibaba 微服务 flowable 工作流 自定义表单 vue.js前后分离
    ClassLoader读取文件,springboot打jar包后读取不到
    Nginx/Tomcat/Apache的优缺点和区别
    Swagger3 相比2配置变了
    webloginc配置项目根目录
  • 原文地址:https://www.cnblogs.com/ifindu-san/p/9716821.html
Copyright © 2011-2022 走看看