关于springBoot日志的学习

1.日志框架介绍

  • 当前市面上存在着多种日志框架,例如当下流行的下列几种框架

    日志门面(日志抽象层) 日志实现
    JCL(Jakarta Commons Logging)、 SLF4j(Simple Logging Facade for Java)、Jboss-logging Log4j、JUL(java.util.logging)、Log4j2 、Logback
    • 外观模式:隐藏了系统的复杂性,并向客户端提供了一个可以访问系统的接口。这种类型的设计模式属于结构性模式。为子系统中的一组接口提供了一个统一的访问接口,这个接口使得子系统更容易被访问或者使用。

      1016421-20160910215031051-160598096.png
      • 使用场景:
        1. 为复杂的模块或子系统提供外界访问的模块
        2. 子系统相互独立
        3. 在层析结构中,可以使用外观模式定义系统的每一层的入口。
    • 在当下的日志框架中,使用了外观模式的设计模式思想,主要分成两类

      1. 日志门面:日志门面主要是对日志模块定义了统一的接口,形成一个规范标准
      2. 日志实现:日志的实现主要是对日志门面进行具体的实现
  • SpringBoot:底层是Spring框架,Spring框架默认是用JCL,SpringBoot选用 SLF4j和logback

2. SLF4j使用

2.1 如何在系统中使用SLF4J

  • 在当下的日志系统的开发中,不应直接使用日志接口的实现,而是应该通过日志门面去间接的使用日志模块,以达到能够灵活切换的目的

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class HelloWorld {
      public static void main(String[] args) {
        //初始化日志对象
        Logger logger = LoggerFactory.getLogger(HelloWorld.class);
        //根据日志的等级进行日志的输出
        logger.info("Hello World");
      }
    }
    
  • 在图中,每个日志框架都实现了SLF4J,在引入日志jar包的时候,我们需要引入一个门面的jar包与实现该门面的jar进行日志模块的搭建

concrete-bindings.png

2.2 历史遗留的日志问题

  • 在当下主流架构中所使用的框架中,每种框架都是用了不同的日志模块。并且,在许多的框架所使用的日志模块所实现的日志门面有所不同,这样对我们在业务系统开发中造成了无法对日志进行统一管理的困难。例如:

    • Spring boot(slf4j+logback)
    • Spring(commons-logging)
    • Hibernate(jboss-logging)

    等等一系列不同的日志模块

  • 可以从SLF4J解决历史问题相关文档中看到

    1528472154419.png

SLF4J为了适配对于实现不同门面标准的日志,提供了一系列转换的包,为此,我们需要做到以下几步:

  1. 将系统中其他日志框架先排除出去
  2. 用中间包来替换原有的日志框架
  3. 我们导入slf4j其他的实现

3. SpringBoot日志

  • SpringBoot使用了slf4j+logback进行日志输出,我们需要再pom文件中添加spring boot的日志相关环境启动器xml相关的依赖配置信息

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-logging</artifactId>
    </dependency>
    
  • 通过idea为pom文件的关系图中我们可以看到spring boot已经自动的为我们引入了三种门面的相关转换器,通过转换器的转换实现对于slf4j接口的对接,并且通过logback-core进行日志的实现

1528473466889.png
  • ==SpringBoot能自动适配以上门面接口的日志,而且底层使用slf4j+logback的方式记录日志,引入其他框架的时候,只需要把框架依赖的日志框架排除掉即可==

  • 日志等级

    Level Color
    FATAL Red
    ERROR Red
    WARN Yellow
    INFO Green
    DEBUG Green
    TRACE Green
    • 以上表格排序为日志的输出等级,由高到低排列,输出等级越低,所输出的相关信息越多,低等级会将更高等级的日志一起输出,以此类推

    • 可以通过相关配置对输出日志的颜色进行替换

      %clr(%d {yyyy-MM-dd HH:mm:ss.SSS}){yellow}
      支持以下颜色和样式:
          blue
          cyan
          faint
          green
          magenta
          red
          yellow
      
  • 日志相关配置

    • 在默认的情况下,Spring boot的日志只会输出到控制台当中,不会写入日志文件,除了控制台输出之外,如果你想写日志文件,你需要设置一个 logging.file或者logging.path属性。
    #日志级别的设置可以指定包下的日志输出级别
    logging.level.root = WARN
    logging.level.org.springframework.web = DEBUG
    logging.level.org.hibernate = ERROR
    
    #可通过以下配置在指定的路径下生成日志信息,当日志文件大小超过10M,spring boot会自动的生成新的日志文件
    #在指定的路径文件下生成对应文件名的日志信息
    logging.file=d:\my.log 
    #在d:\log这个路径下生成spring.log的日志文件信息
    logging.path=d:\log
    #记录异常时使用的转换字
    logging.exception-conversion-word
    #日志控制台输出的格式
    logging.pattern.console=${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}
    #日志在文件中的输出格式
    logging.pattern.file=${FILE_LOG_PATTERN:-%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}
    
    • 默认是日志配置文件如下
    <?xml version="1.0" encoding="UTF-8"?>
    
    <!--
    Default logback configuration provided for import, equivalent to the programmatic
    initialization performed by Boot
    -->
    
    <included>
        <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
        <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
        <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
        <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
        <property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN:-%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
    
        <appender name="DEBUG_LEVEL_REMAPPER" class="org.springframework.boot.logging.logback.LevelRemappingAppender">
            <destinationLogger>org.springframework.boot</destinationLogger>
        </appender>
    
        <logger name="org.apache.catalina.startup.DigesterFactory" level="ERROR"/>
        <logger name="org.apache.catalina.util.LifecycleBase" level="ERROR"/>
        <logger name="org.apache.coyote.http11.Http11NioProtocol" level="WARN"/>
        <logger name="org.apache.sshd.common.util.SecurityUtils" level="WARN"/>
        <logger name="org.apache.tomcat.util.net.NioSelectorPool" level="WARN"/>
        <logger name="org.crsh.plugin" level="WARN"/>
        <logger name="org.crsh.ssh" level="WARN"/>
        <logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="ERROR"/>
        <logger name="org.hibernate.validator.internal.util.Version" level="WARN"/>
        <logger name="org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration" level="WARN"/>
        <logger name="org.springframework.boot.actuate.endpoint.jmx" additivity="false">
            <appender-ref ref="DEBUG_LEVEL_REMAPPER"/>
        </logger>
        <logger name="org.thymeleaf" additivity="false">
            <appender-ref ref="DEBUG_LEVEL_REMAPPER"/>
        </logger>
    </included>
    
    • 对于日志配置文件的高级使用,为了让spring boot能够管理日志文件的配置文件信息,建议使用文件名后面带-sring进行日志配置文件的命名

      日志模块类型 配置文件名称
      Logback logback-spring.xml, logback-spring.groovy, logback.xml or logback.groovy
      Log4j2 log4j2-spring.xml or log4j2.xml
      JDK (Java Util Logging) logging.properties

      可以根据profile来定义日志输出的相配置信息的格式以及相关的内容

      <springProfile name="staging">
          <!-- configuration to be enabled when the "staging" profile is active -->
      </springProfile>
      
      <springProfile name="dev, staging">
          <!-- configuration to be enabled when the "dev" or "staging" profiles are active -->
      </springProfile>
      
      <springProfile name="!production">
          <!-- configuration to be enabled when the "production" profile is not active -->
      </springProfile>
      
    • logbakc日志配置文件

      <?xml version="1.0" encoding="UTF-8"?>
      <!--
      scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
      scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒当scan为true时,此属性生效。默认的时间间隔为1分钟。
      debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
      -->
      <configuration scan="false" scanPeriod="60 seconds" debug="false">
          <!-- 定义日志的根目录 -->
          <property name="LOG_HOME" value="/app/log" />
          <!-- 定义日志文件名称 -->
          <property name="appName" value="atguigu-springboot"></property>
          <!-- ch.qos.logback.core.ConsoleAppender 表示控制台输出 -->
          <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
              <!--
              日志输出格式:
                  %d表示日期时间,
                  %thread表示线程名,
                  %-5level:级别从左显示5个字符宽度
                  %logger{50} 表示logger名字最长50个字符,否则按照句点分割。 
                  %msg:日志消息,
                  %n是换行符
              -->
              <layout class="ch.qos.logback.classic.PatternLayout">
                  <springProfile name="dev">
                      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ----> [%thread] ---> %-5level %logger{50} - %msg%n</pattern>
                  </springProfile>
                  <springProfile name="!dev">
                      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ==== [%thread] ==== %-5level %logger{50} - %msg%n</pattern>
                  </springProfile>
              </layout>
          </appender>
      
          <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->  
          <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
              <!-- 指定日志文件的名称 -->
              <file>${LOG_HOME}/${appName}.log</file>
              <!--
              当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名
              TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。
              -->
              <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                  <!--
                  滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动 
                  %i:当文件大小超过maxFileSize时,按照i进行文件滚动
                  -->
                  <fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
                  <!-- 
                  可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每天滚动,
                  且maxHistory是365,则只保存最近365天的文件,删除之前的旧文件。注意,删除旧文件是,
                  那些为了归档而创建的目录也会被删除。
                  -->
                  <MaxHistory>365</MaxHistory>
                  <!-- 
                  当日志文件超过maxFileSize指定的大小是,根据上面提到的%i进行日志文件滚动 注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy
                  -->
                  <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                      <maxFileSize>100MB</maxFileSize>
                  </timeBasedFileNamingAndTriggeringPolicy>
              </rollingPolicy>
              <!-- 日志输出格式: -->     
              <layout class="ch.qos.logback.classic.PatternLayout">
                  <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern>
              </layout>
          </appender>
      
          <!-- 
              logger主要用于存放日志对象,也可以定义日志类型、级别
              name:表示匹配的logger类型前缀,也就是包的前半部分
              level:要记录的日志级别,包括 TRACE < DEBUG < INFO < WARN < ERROR
              additivity:作用在于children-logger是否使用 rootLogger配置的appender进行输出,
              false:表示只用当前logger的appender-ref,true:
              表示当前logger的appender-ref和rootLogger的appender-ref都有效
          -->
          <!-- hibernate logger -->
          <logger name="com.atguigu" level="debug" />
          <!-- Spring framework logger -->
          <logger name="org.springframework" level="debug" additivity="false"></logger>
      
      
      
          <!-- 
          root与logger是父子关系,没有特别定义则默认为root,任何一个类只会和一个logger对应,
          要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个logger的appender和level。 
          -->
          <root level="info">
              <appender-ref ref="stdout" />
              <appender-ref ref="appLogAppender" />
          </root>
      </configuration> 
      
  • 替换日志组件方式

    • 在springBoot的日志输出中,如果需要对当前系统的日志模块进行替换,可以通过pom文件视图首先去除logbakc相关的配置信息,同事加入相应的日志模块的环境启动器

      • 替换log4j作为日志模块
      1.  首先先将`logback-classic`依赖文件移除
      
      2.  将日志转换类移除`log4j-over-slf4j`
      
      3.  引入日志依赖包
      
      4.  最终结果
      
          ```xml
          <!--springBoot项目web的环境启动器-->
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-web</artifactId>
              <exclusions>
                  <exclusion>
                      <artifactId>logback-classic</artifactId>
                      <groupId>ch.qos.logback</groupId>
                  </exclusion>
                  <exclusion>
                      <artifactId>log4j-over-slf4j</artifactId>
                      <groupId>org.slf4j</groupId>
                  </exclusion>
              </exclusions>
          </dependency>
          <dependency>
              <groupId>org.slf4j</groupId>
              <artifactId>slf4j-log4j12</artifactId>
          </dependency>
          ```
      
      • 替换log4j2作为日志模块

        1. 直接移除spring-boot-starter-logging依赖

        2. 添加log4j2的环境启动器

        3. 配置文件信息

           <dependency>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-web</artifactId>
               <exclusions>
                   <exclusion>
                       <artifactId>spring-boot-starter-logging</artifactId>
                       <groupId>org.springframework.boot</groupId>
                   </exclusion>
               </exclusions>
          </dependency>
          <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
          </dependency>
          
      • log4j配置文件

        ### set log levels ###
        log4j.rootLogger = debug ,  stdout ,  D ,  E
        
        ### 输出到控制台 ###
        log4j.appender.stdout = org.apache.log4j.ConsoleAppender
        log4j.appender.stdout.Target = System.out
        log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
        log4j.appender.stdout.layout.ConversionPattern =  %d{ABSOLUTE} ===== %5p %c{ 1 }:%L - %m%n
        
        #### 输出到日志文件 ###
        #log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
        #log4j.appender.D.File = logs/log.log
        #log4j.appender.D.Append = true
        #log4j.appender.D.Threshold = DEBUG ## 输出DEBUG级别以上的日志
        #log4j.appender.D.layout = org.apache.log4j.PatternLayout
        #log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
        #
        #### 保存异常信息到单独文件 ###
        #log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
        #log4j.appender.D.File = logs/error.log ## 异常日志文件名
        #log4j.appender.D.Append = true
        #log4j.appender.D.Threshold = ERROR ## 只输出ERROR级别以上的日志!!!
        #log4j.appender.D.layout = org.apache.log4j.PatternLayout
        #log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
        
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容