Logback使用总结

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 整理了下logback的常用点功能,并记录了一些在使用过程中的疑问,和问题的排错过程,防止自己再犯类似错误,也希望对路过的你有所帮助。

前言



整理了下logback的常用点功能,并记录了一些在使用过程中的疑问,和问题的排错过程,防止自己再犯类似错误,也希望对路过的你有所帮助。


一、logback如何使用



任何框架的使用都是三步走:


1.导入jar包

2.配置文件

3.开始使用


对于logback自然也是不例外的,这里简单说下,不做过多的赘述。springboot默认集成了logback,所以若是建立springboot项目千万别在导入logback的jar包了,不然就会有问题。


对于配置文件的管理,会在第二部分详细介绍这块。

使用的话就比较简单了,直接增加注解@Slf4j,然后使用log.info就可以正常使用了。


二、知识点



1.logback简单模板


以下是logback的简单模板(其实生产系统也是这一套),涵盖了logback的常用配置,日常使用这些配置也就够了,基于这个配置来总结下logback的使用:


<?xml version="1.0" encoding="UTF-8"  ?>
<configuration debug="false"><!--debug=false表示不打印logback的debug信息-->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%date{yyyy-MM-dd HH:mm:ss.sss}  %-5level  %class{30}  行:%line   %msg%n</pattern>
        </encoder>
    </appender>
    <appender name="RollingFileInfo" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>./logs/info.log</file>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>info</level>
        </filter>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>error</level>
            <onMatch>DENY</onMatch>
            <onMismatch>ACCEPT</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>./logs/%d{yyyy-MM, aux}/info.%d{yyyy-MM-dd}.log.gz</fileNamePattern>
            <maxHistory>30</maxHistory>
            <totalSizeCap>5GB</totalSizeCap>
        </rollingPolicy>
        <encoder>
            <pattern>%date{yyyy-MM-dd HH:mm:ss.sss}  %-5level  %-60class{60}  行:%-5line  %msg%n</pattern>
        </encoder>
    </appender>
    <appender name="RollingFileError" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>./logs/error.log</file>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>./logs/%d{yyyy-MM,aux}/error.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
            <maxFileSize>50MB</maxFileSize>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%date{yyyy-MM-dd HH:mm:ss.sss}  %-5level  %-60class{60}  行:%-5line  %msg%n</pattern>
        </encoder>
    </appender>
    <root level="info">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="RollingFileInfo"/>
        <appender-ref ref="RollingFileError"/>
    </root>
</configuration>


2.解析主要标签


1.configuration标签

它是根标签,包含下面三个属性

scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。

debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。

scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。

使用解读:一般这三个属性都是使用默认配置,无需更改。


2.root标签


该标签只能有一个,用来声明根记录器root的一些属性它有一个属性level用来声明日志等级:trace< debug< info< warn< error,此外所有的appender都需要告诉root根记录器,常用配置如下:

  <root level="info"> <!-- 声明日志级别,这里声明将作用于所有记录器-->
      <appender-ref ref="STDOUT" /> <!-- 声明附加器引用-->
      <appender-ref ref="RollingFileInfo"/>
      <appender-ref ref="RollingFileError"/>
  </root>


3.appender标签


该标签用来定义附加器,所谓附加器就是日志附着的方式,该标签与root标签同级,它包含2个属性


name:该属性指定附加器的名称与root标签中保持一致。


class:指定日志的附加方式,常用的附加器有:

        控制台附加器:ch.qos.logback.core.ConsoleAppender
    文件附加器:ch.qos.logback.core.FileAppender
    滚动文件附加器:ch.qos.logback.core.rolling.RollingFileAppender


三种附加器的区别,显而易见。 控制台附加器将日志输出到控制台,文件附加器将日志输出到文件,滚动文件附加器将日志输出到文件,滚动文件附加器支持文件的分割而文件附加器不支持。所以基本都是用:控制台附加器、滚动文件附加器。


4.encoder标签

编码器,用来声明日志的格式,常用方式如下

  <encoder>
      <pattern>%date{yyyy-MM-dd HH:mm:ss.sss}  %-5level  %-60class{60}  行:%-5line  %msg%n</pattern>
  </encoder>


常用的信息获取方式如下:

1)%date 获取当前日期,也可以指定更具体的格式比如:%date{yyyy-MM–dd HH:mm:ss.sss}

2)%level 获取当前日志等级

3)%msg 获取打印的日志信息,也就是通过代码中通过记录器打印的日志

4)%n 换行,日志在pattern都是要加的,这样日志在输出时才会正确换行

5)%logger 获取当前的记录器,还可以指定记录器的最长显示长度,比如:%logger{50},注意这个长度只是限制打印出的记录器的名字的长度

6)%class 获取当前类名,与logger类似,class也可以指明长度,比如:%class{40}

7)%line 获取打印日志的语句所处代码的行数。

8)%thread 获取当前线程名称

9)%10class 不足10位前面补空格

10%-10class 不足10位后面补空格


5.file标签

该标签比较简单用来声明日志文件,比较简单。


6.filter标签

改标签为过滤器,常用的过滤器有两种都是基于日志级别的过滤:

级别过滤器:ch.qos.logback.classic.filter.LevelFilter


当输出日志匹配到level时,就会返回onMatch中的信息,不匹配时返回onMismatch中的信息。

若是返回DENY则是拒绝输出,返回ACCEPT则是输出,此外还可以返回NEUTRAL保持中立,下面过滤器的作用是:若是日志是error则不输出日志,否则输出日志。


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


阈值过滤器:ch.qos.logback.classic.filter.ThresholdFilter

若是输出的日志级别高于level中声明的级别则会输出,否则不会输出。高于info的也就是warn和error了。

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


7.rollingPolicy标签

这个标签内容会多一些,这里主要是定义日志的分割行为的。用官方话说就是定义日志的滚动策略。常用的滚动策略有两种:


基于时间的滚动策略:ch.qos.logback.core.rolling.TimeBasedRollingPolicy

他的常用配置如下main所示了,fileNamePattern用来声明日志分割的具体策略,%d{yyyy-MM, aux}这里需要特别注意,fileNamePattern中只允许一个日期不声明aux,其他都必须声明为aux,这样logback才知道是以哪个时间为基准来分割日志。maxHistory标识日志存放的时间,这个时间的单位就是fileNamePattern中日志分割的时间单位。totalSizeCap标识所有日志文件的最大大小,超过这个值,logback会清理掉最初的日志,以满足这个限制。


  <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>./logs/%d{yyyy-MM, aux}/info.%d{yyyy-MM-dd}.log.gz</fileNamePattern>
      <maxHistory>30</maxHistory>
      <totalSizeCap>5GB</totalSizeCap>
  </rollingPolicy>


基于大小和时间的滚动策略:ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy

这个比上面的多了个maxFileSize,这个是限制文件大小的。当日志达到这个限制就会被分割。此外需要特别注意的是,若是指定的大小未达到,即使指定的时间达到了日志也不会分割,必须是日志大小达到了日志才会分割。这种分割场景比较适合日志量特别大的系统,因为此时一天只能日志可能需要多次分割,若是日志量不大的系统日志一天一分割即可,此时使用上面的基于时间分割的策略为最优。这里还两点需要注意%i,这个是分割日志时标注日志需要所用,必须要有。后面跟的点gz,是用来压缩文件的。fileNamePattern语句最后跟gz或者zip时,logback都会自动识别将文件进行压缩。


<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
    <fileNamePattern>./logs/%d{yyyy-MM,aux}/error.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
    <maxFileSize>50MB</maxFileSize>
    <maxHistory>30</maxHistory>
</rollingPolicy>


8.property标签

用来定义变量值,它有两个属性name和value,通过property定义的值会在配置文件中都可以正常获取,可以使“${}”来使用变量。

  <configuration scan="true" scanPeriod="60 seconds" debug="false"> 
     <property name="APP_Name" value="myAppName" /> 
     <contextName>${APP_Name}</contextName> 
  </configuration>


三、问题和排错



这里记录下使用时碰到的一些问题,有些问题很白痴,但是还是记录下防止自己再犯好了。


1.描述:只引入logback的依赖,启动工程时报错:Failed to load class “org.slf4j.impl.StaticLoggerBinder”.

解决:增加一个依赖,该依赖应该是上方类的实现了,如下:

 <dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-simple</artifactId>
  <version>1.6.6</version>
</dependency>


增加该依赖后使用代码可以正常获取记录器,但是配置文件还是不行,其实报上面这个错最根本的原因还是springboot默认已经集成了logback,无需在引入了,取消引入就ok了。


2.描述:logback配置文件不生效,直接在classpath下增加了logback.xml或者logback-spring.xml都是不生效的。


解决:测试了很多方法,更换jar包,文件位置不对的都不行,现在测试以下降低springboot的版本,当前使用是springboot2.6.3降到2.5.9最后发现也不是springboot版本的问题,而是因为springboot默认集成了logback,无需再手动引入该依赖,引入了就是多余操作,jar包多余了,删除掉引用发现正常。


3.描述:使用springboot默认的logback,发现增加配置文件后日志在控制台全部不打印了


解决:这里是因为使用了配置文件,默认都从配置文件读取配置,但是又没有指定这块配置就导致了这样的结果。


这里需要指定日志输出到控制台,并且为其指定一个appender,这样就ok了,详细配置如下:

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


4.问题:附加器和各个记录器之间的关系?

解答:可以在记录器中声明附加器,记录器中声明的附加器会被记录器的子记录器通过继承来获得吗,我感觉可能是可以的,如果可以那我的日志为什么不生效呢,理论上根记录器有了附加器那其他的子记录器也应该有了附加器,都应该可以正常输出的啊,奇怪。

再测试下,之前的encoder中的pattern是否有日志输出

结论:父记录器的附加器确实可以被子记录器来获取,因此我们在声明附着器时是可以只在根记录器声明可以了。另外刚刚碰到的问题自己加的pattern日志没有出现,原来是因为日志忘了加%n进行换行,所有日志都输出到了一行。


5.问题:滚动文件附加器在使用基于时间的滚动分割时,文件不会自动分割。

解答:两个原因:

1).需要指定日志输出文件,并且分割文件的位置也要指定(不然会在项目的根目录里)

2).必须要有日志正在打印才会分割,若是日志文件是空的,即使满足基于时间的分割要求,日志也是不会发生分割的。


6.问题:在滚动文件附加器中使用基于大小和时间的滚动策略,若是项目重启,对待之前存在的日志文件maxHistory还能生效吗?

经验证还是生效的,所以重启并不会影响到文件备份的整体性。


7.问题:日志的分割是以fileNamePattern中的哪个值来分割的

解答:经测试,是以指定文件名的最后的%d{}来进行分割,不过其他的%d都需要使用aux来声明,如%d{yyyy-MM,aux}


8.问题;配置了logback是否还需要使用nohup命令来指定日志的输出文件?

解答:猜测是不需要的,测试下。经验证是不需要,启动命令中将控制台日志输出到黑洞即可,>/dev/null &。


9.问题:lombok中如何使用logback

解答:直接使用注解 @Slf4j即可,不过需要idea中预先装好lombok。


10.问题:文件的路径到底使用斜杠还是反斜杠

解答:好像是绝对路径使用反斜杠,相对路径使用斜杠。

经测试,无论是相对路径还是绝对路径斜杠和反斜杠在windows中都可以使用,且无区别。

但是在linux服务器上测试时,发现相对路径用反斜杠不好使,还得用斜杠。


11.问题:logback能不能直接将日志进行压缩打包,这样可以节省很多空间

解答:网上说直接在分割文件末尾加.gz即可。项目上好像也是这么用的,测试一下。

验证后确实可以,其实在末尾加.zip也是可以的,logback支持这两种声明方式进行压缩。


12.问题:加上.gz以后,日志没有正常按时间进行切分

猜测:因为加了大小1mb限制,时间是以分钟来切割。那么会不会必须先达到1mb大小才会按照时间来切割。如果这样的话就是说必须以最大的限制条件来进行切割的,若是以分钟切割,一分钟内不达到最大的文件大小是不会切割的,达不到就会达到设定的最大值才来切割,若是达到了则会 按大小来切割。那么是不是可以说,其实基于时间和大小的滚动策略,其实基础是以大小来切割的,时间只是辅助。

验证下:验证确实如此。和加.gz没有任何关系。


13.问题:若是使用logback记录日志的话,那么启动不能使用nohup来记录日志了,那启动命令该怎么写?


解答:java -server -jar -Xss1m -server -Xms512m -Xmx2048m -Xmn128m -XX:MetaspaceSize=128M -XX:+UseConcMarkSweepGC mdm-project-server-biz.jar >/dev/null &


本地测试都正常使用该命令,在uat启动时发现日志并没有正常输出。

经历了一次深刻的教训,使用jenkinsn打包发布时,因为ssh到目标服务器以后,默认路径是你登录的用户工作路径。在这里执行上面的命令就会将脚本中创建的文件在这里创建,而不是以jar包所在的路径为相对路径进行创建这个问题前后解决了3小时,深痛教训,在jenkins中写脚本时,ssh以后一定要先cd再操作。


14.问题:以时间为基准的滚动策略对比以大小和时间为基准的滚动策略

解答:时间为基准的滚动策略:指定滚动时间,就只会以时间为大小往下滚动,但是还可以为他加上这个限制:


 <timeBasedFileNamingAndTriggeringPolicy  class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
  <!-- maxFileSize:这是活动文件的大小,默认值是10MB,测试时可改成1KB看效果 -->
   <maxFileSize>3kb</maxFileSize>
 </timeBasedFileNamingAndTriggeringPolicy>


这样的话,滚动效果就是和基于大小合和时间的滚动策略一模一样了。他们都是先看大小是否达到,大小达到了就会以时间进行分割日志文件,如果大小未达到是不会分割文件的。经验值加上他的效果和以大小时间为基础的滚动策略基本一致。


15.问题:fileNamePattern日志输出路径(绝对路径)增加了%{yyyy-MM}后,日志不能正常分割


解答:经验证,加了该路径后再windows系统中不能正常生产当前日期的文件夹。

下面测试下相对路径增加这个路径是否可行:不可行,在windows系统中无论是绝对路径还是相对路径增加这个文件夹都失败了。

可是记得之前是可以的,很奇怪。

再验证下linux系统中的情况:好像突然也不行了。


是不是和这个有关:%d{yyyy-MM-dd, aux}:经检查这个配置是告诉logback不是以这个时间进行分割的,一个fileNamePattern中除了指定的分割的日期,其他的日期都是需要加上这个aux的。

验证后发现确实和这个配置有关,问题解决。


16.问题:springboot中logback的配置文件名称如何命名?

解答:springboot中支持这几种命名:logback-test.xml、logback.xml、logback-spring.xml。使用这些名称都可以自动识别logback的配置文件,但是若是想要自己制定配置文件名称比如:logback-myself.xml,则需要在application.yml中增加这个配置:logging.config=classpath:logback-myself.xml


17.问题:使用以时间为基准的滚动策略,日志不按时间滚动分割

解答:这是因为没有日志产生的缘故,若是以时间分割日志,但是在分割单位时间内么有日志产生,那么日志也是不会分割的,只有打印新日志,日志才会依照时间进行分割。


总结



这是自己学习logback的总结,同时纪录了自己解决学习过程中问题的思路,logback东西不多这些基本就够用了,至于控制台的彩色日志,没啥用也就没研究。在这里记录下希望可以帮到想要学习的人。


相关文章
|
12月前
|
Java
解决logback不能打印日志的问题
解决logback不能打印日志的问题
599 0
|
11月前
|
XML 监控 Java
JAVA日志技术 & Logback
为什么需要记录日志?我们不可能实时的24小时对系统进行人工监控,那么如果程序出现异常错误时要如何排查呢?并且系统在运行时做了哪些事情我们又从何得知呢?这个时候日志这个概念就出现了,日志的出现对系统监控和异常分析起着至关重要的作用。......
65 0
|
缓存 Java API
logback配置
一、logback介绍 logback分成三个模块:logback-core,logback- classic,logback-access。 logback-core:提供了logBack的核心功能,是另外两个组件的基础; logback-classic:实现了SLF4J API; logback
707 0
|
9天前
|
Java
使用SLF4J和Logback23
使用SLF4J和Logback23
15 3
|
Java API 网络性能优化
NoClassDefFoundError: ch/qos/logback/classic/spi/ThrowableProxy
报错日志: java.lang.NoClassDefFoundError: ch/qos/logback/classic/spi/ThrowableProxy at ch.
11190 0
|
5月前
|
监控 Java 测试技术
日志框架到底是Logback 还是 Log4j2
日志框架到底是Logback 还是 Log4j2
45 0
|
XML 安全 Oracle
logback的使用和logback.xml详解
logback的使用和logback.xml详解
|
算法 Java API
(三)Logback中的Appender
(三)Logback中的Appender
|
安全 Java API
(一)Logback介绍及架构
(一)Logback介绍及架构
|
监控 Java Shell
(二)Logback配置
Logback通过加载配置文件的方式来初始化配置,配置文件的加载顺序如下: 1)Logback首先会去类路径下找名为logback-test.xml的文件。 2)如果没有找到如上文件,会去类路径下找名为logback.groovy的文件。 3)如果没有找到如上文件,会去类路径下找名logback.xml的文件。
(二)Logback配置