• 【运维篇】三、SLF4J与Logback


    请添加图片描述

    0、Java的门面设计模式

    因为SLF4J就是门面设计模式的应用,因此先整理下这种设计模式。参考原文:https://blog.csdn.net/jason0539/article/details/22775311

    部分截图:

    在这里插入图片描述
    在这里插入图片描述

    核心就是外部(客户端)与一个子系统通信时,通过一个统一的外观对象进行,从而隐藏子系统的具体逻辑,使得子系统更易于使用。客户端不再需要了解子系统内部的实现,也不需要跟众多子系统内部的模块进行交互,只需要跟门面类交互就可以了。

    在这里插入图片描述
    门面对象有以下几个特点:

    • 知道所有子角色的功能和责任
    • 将客户端发来的请求委派到子系统中,没有实际业务逻辑
    • 不参与子系统内业务逻辑的实现

    1、SLF4J

    SLF4J,Simple Logging Facade For Java,即简单日志门面,是一套存取日志的标准接口

    注意是接口,不是具体实现,就像JDBC一样只是统一的接口,想要使用就需要搭配其他具体的日志实现方案,如logback、log4j

    在这里插入图片描述

    slf4j-simple、logback都是slf4j的具体实现,log4j并不直接实现slf4j,但是有专门的一层桥接slf4j-log4j12来实现slf4j。关于这些具体实现框架的信息,贴个图:

    在这里插入图片描述

    2、作用

    关于SLF4J的使用目的,看这个场景:

    - 自己开发的系统中,日志框架使用logback实现
    - 这个系统中使用了A.jar,A.jar中使用了log4j框架
    - 这个系统也使用了B.jar,B.jar中使用了slf4j-simple
    
    • 1
    • 2
    • 3

    此时,我们就得维护多套日志框架,使用不便。就像这样:

    // 使用log4j,需要log4j.jar
    import org.apache.log4j.Logger;
    Logger logger_log4j = Logger.getLogger(Test.class);
    logger_log4j.info("Hello World!");
    
    // 使用log4j2,需要log4j-api.jar、log4j-core.jar
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    Logger logger_log4j2 = LogManager.getLogger(Test.class);
    logger_log4j2.info("Hello World!");
    
    // logback,需要logback-classic.jar、logback-core.jar
    import ch.qos.logback.classic.Logger;
    import ch.qos.logback.classic.LoggerContext;
    Logger logger_logback = new LoggerContext().getLogger(Test.class);
    logger_logback.info("Hello World!");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    使用不同的日志框架,就要引入不同的jar包,使用不同的代码获取Logger。如果项目升级需要更换不同的框架,那么就需要修改所有的地方来获取新的Logger,这将会产生巨大的工作量。 因此,加入门面的设计模式,让调用端只关心如何调用,而不关心怎么实现打印日志,这个抽象层就是slf4j。slf4j只是一个日志标准,并不是日志系统的具体实现,它只负责:

    • 提供日志接口
    • 提供获取具体日志对象的方法

    3、调试

    先看下只有slf4j依赖的情况,创建个小模块,仅引入单元测试与slf4j的依赖,不引入任何日志的具体实现的依赖。

    在这里插入图片描述

    pom.xml内容:

    在这里插入图片描述

    在单元测试中打印行日志看下效果:

    @Test
    public void testSlf4j(){
    	
    	Logger logger = LoggerFactory.getLogger(Object.class);
    	logger.info("log...");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    运行单元测试:

    在这里插入图片描述

    在没有给slf4j提供具体的实现时,打印日志失败,大致意思是找不到绑定器和实现。接下来随便再引入一个日志实现框架的依赖:

    <dependency>
    	<groupId>ch.qos.logbackgroupId>
    	<artifactId>logback-classic<artifactId>
    	<version>1.2.3<version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    再运行单元测试,日志打印成功:

    在这里插入图片描述
    再引入一个其他的日志实现:

    <dependency>
    	<groupId>org.slf4jgroupId>
    	<artifactId>slf4j-simple<artifactId>
    	<version>1.7.25<version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    再运行上面的UT,发现控制台显示有多个SLF4J绑定器,最终生效的是logback下的:

    在这里插入图片描述

    4、SpringBoot采用SLF4J+Logback

    默认情况下,SpringBoot使用了 SLF4J+logback 的日志框架组合。查看SpringBoot起步依赖:

    在这里插入图片描述

    往下跟logging-starter:

    <dependencies>
    	
      
      <dependency>
        <groupId>ch.qos.logbackgroupId>
        <artifactId>logback-classicartifactId>
        <version>1.2.3version>
        <scope>compile
      dependency>
      
      
      <dependency>
        <groupId>org.apache.logging.log4jgroupId>
        <artifactId>log4j-to-slf4jartifactId>
        <version>2.11.1version>
        <scope>compilescope>
      dependency>
      
      
      <dependency>
        <groupId>org.slf4jgroupId>
        <artifactId>jul-to-slf4jartifactId>
        <version>1.7.25version>
        <scope>compilescope>
      dependency>
      
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    Maven依赖图:

    在这里插入图片描述

    5、切换SpringBoot的日志框架

    切换日志框架,即切换实现,就是排除默认的依赖,引入自己需要的框架的依赖。

    logback切换为log4j2:

    <dependencies>
    	  <dependency>
    		  <!‐‐starter‐web里面自动添加starter‐logging ,向下就是logback的依赖‐‐>
    		  <groupId>org.springframework.bootgroupId>
    		  <artifactId>spring‐boot‐starter‐webartifactId>
    		  <exclusions>
    			  <!‐‐排除starter‐logging 也就是logback的依赖‐‐>
    			  <exclusion>
    				  <artifactId>spring‐boot‐starter‐loggingartifactId>
    				  <groupId>org.springframework.bootgroupId>
    			  exclusion>
    		  exclusions>
    	  dependency>
    
    	 <!‐‐Log4j2的场景启动器‐‐>
    	  <dependency>
    		  <groupId>org.springframework.bootgroupId>
    		  <artifactId>spring‐boot‐starter‐log4j2artifactId>
    	  dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    再添加log4j2的配置文件log4j2-spring.xml即可。

    logback切换为log4j:

    要将logback的桥接器排除,添加log4j的桥接器:

    <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
                <exclusions>
                    <exclusion>
                        <artifactId>logback-classicartifactId>
                        <groupId>ch.qos.logbackgroupId>
                    exclusion>
                exclusions>
            dependency>
            <dependency>
                <groupId>org.slf4jgroupId>
                <artifactId>slf4j-log4j12artifactId>
            dependency>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    再添加log4j的配置文件。

    关于桥接:
    
    • 1

    在这里插入图片描述

    6、logback的配置加载

    logback是log4j的作者写的另一日志框架,对之前的框架进行了完善和优化。关于logback的加载,当我们使用logback-classic.jar时,应用启动,那么logback会按照如下顺序进行扫描:

    • 在系统配置文件System Properties中寻找是否有logback.configurationFile对应的value
    • 在classpath下寻找是否有logback.groovy(即logback支持groovy与xml两种配置方式)
    • 在classpath下寻找是否有logback-test.xml
    • 在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

    在这里插入图片描述

    7、logback的配置组成

    整个配置拆为三大块:Appender、Logger、Pattern。先看下一个logback的 的三个属性。

    的三个属性:

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

    8、logback之logger

    用来设置某一个包或者具体某一个类的日志打印级别(分组的那个味儿)、以及指定所用的

    包含一个元素和三个属性:

    • 元素:0个或多个,用来说明这个logger分组下的日志往哪儿输出、怎么输出
    • name属性:name必填,name不是随便起的,它表示的是LoggerFactory.getLogger(XXX.class),XXX类的包路径,包路径越少越是父级,传入的xxx.class用哪个logger,就是看这个类属于哪个name包下
    • level:用来设置打印级别,可选,未设置时继承上级logger的级别,也是元素,但是它是根logger,只有一个level属性,因为它的name就是ROOT
    • additivity:是否向上级logger传递打印信息,默认为true

    写个UT来测试下效果:

    public class Slf4jTest {
    
        @Test
        public void testSlf4j() {
            Logger logger = LoggerFactory.getLogger(Object.class);
            logger.trace("=====trace=====");
            logger.debug("=====debug=====");
            logger.info("=====info=====");
            logger.warn("=====warn=====");
            logger.error("=====error=====");
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    类路径下写logback.xml:

    
    <configuration scan="false" scanPeriod="60000" debug="false">
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <layout class="ch.qos.logback.classic.PatternLayout">
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%npattern>
            layout>
        appender>
    
        <root level="info">
            <appender-ref ref="STDOUT" />
        root>
    
    configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    以上这个配置,即root这个logger把日志级别大于info的信息交给STDOUT这个appender处理(STDOUT将信息打印到控制台),此时运行上面的UT:

    在这里插入图片描述

    再调整下上面的logback.xml,新加一个logger:

    <logger name="java" additivity="false" />
    
    • 1

    此时运行UT,无输出结果:

    在这里插入图片描述
    结果分析:

    • 首先logger的name是java,我UT传入的class为java.lang.Object,属于这个logger
    • 其次,level没写,继承父级logger的level,即info
    • additivity=false,即不向父级logger传递
    • 而它自己却又没有配置任何的appender-ref,所以无输出
    • additivity改为true,则传递到root这个根logger,用它的appender-ref,就能输出info及以上信息

    再调整下上面的logback.xml,再新加一个logger:

    <logger name="java" additivity="false" />
    
    <logger name="java.lang" level="warn">
    	<appender-ref ref="STDOUT" />
    logger>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    运行UT:

    在这里插入图片描述
    结果分析:

    • 传入的Object.class属于java.lang这个logger
    • java.lang的logger配有appender,成功打印warn及以上
    • 没写additivity,默认为true,传递到父级name=java的logger
    • java这个logger无appender,也不向上传递,那不打印任何信息

    最后,注意这种导致重复打印的不合理写法:

    在这里插入图片描述

    9、logback之appender

    是负责写日志的组件。有两个必要属性name和class:

    • name指定的名称
    • class指定的全限定名

    常用的appender有:

    • ConsoleAppender
    • FileAppender
    • RollingFileAppender
    • AsyncAppender

    ConsoleAppender用来将日志输出到控制台:

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

    FileAppender用于将日志写到文件中:

    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>D:/server.logfile>
        <append>trueappend>
        <encoder>
            <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%npattern>
        encoder>
    appender>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    其中:

    • file元素指定文件名,可以用相对路径,也可绝对路径
    • appender元素为true,及追加,不是清空文件(Linux的>和>>)

    RollingFileAppender的作用是滚动记录文件,先将日志记录到指定文件,当符合某个条件(如达到每个文件的大小)时再将日志记录到其他文件:

    <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>${log.path}/data-svc-error.logfile>
            
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                
                <fileNamePattern>${log.path}/data-svc-error.%d{yyyy-MM-dd}.logfileNamePattern>
                
                <maxHistory>7maxHistory>
            rollingPolicy>
            <encoder>
                <pattern>${log.pattern}pattern>
            encoder>
        appender>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    其中:

    • fileNamePattern指定日志文件格式
    • maxHistory设置滚动历史时长,保留近maxHistory天的日志文件,当然也有按文件大小切割的配置

    AsyncAppender采用异步写日志的方式,减少性能损耗: 之前的appender,如RollingFileAppender,每写一次日志就发生一次磁盘IO

      
    <appender name ="ASYNC" class= "ch.qos.logback.classic.AsyncAppender">  
          
        <discardingThreshold>0discardingThreshold>  
          
        <queueSize>256queueSize>  
          
        <appender-ref ref ="myRollingFileAppender"/>  
    appender>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    异步写入实现原理:

    • 当我们配置了AsyncAppender,系统启动时会初始化一条名为"AsyncAppender-Worker-ASYNC"的线程

    • 当Logging Event进入AsyncAppender后,AsyncAppender会调用appender方法,appender方法中再将event填入Buffer(使用的Buffer为BlockingQueue,具体实现为ArrayBlockingQueye)

    • 不过填入之前,会先判断当前Buffer的容量以及丢弃日志特性是否开启,当消费能力不如生产能力时,AsyncAppender会将超出Buffer容量的Logging Event的级别进行丢弃,作为消费速度一旦跟不上生产速度导致Buffer溢出处理的一种方式。

    • 上面的线程的作用,就是从Buffer中取出Event,交给对应的appender进行后面的日志推送

    • 从上面的描述可以看出,AsyncAppender并不处理日志,只是将日志缓冲到一个BlockingQueue里面去,并在内部创建一个工作线程从队列头部获取日志,之后将获取的日志循环记录到附加的其他appender上去,从而达到不阻塞主线程的效果。

    • 因此AsyncAppender仅仅充当的是事件转发器,必须引用另外一个appender来做事。(如上面引用了定义的RollingAppender类型的appender)

    基于这个原理,看这个appender的参数:

    • discardingThreshold:假如等于20则表示,表示当还剩20%容量时,将丢弃TRACE、DEBUG、INFO级别的Event,只保留WARN与ERROR级别的Event,为了保留所有的events,可以将这个值设置为0,默认值为queueSize/5
    • queueSize:即BlockingQueue的最大容量,默认为256
    • includeCallerData:表示是否提取调用者数据,这个值被设置为true的代价是相当昂贵的,为了提升性能,默认当event被加入BlockingQueue时,event关联的调用者数据不会被提取,只有线程名这些比较简单的数据
    • appender-ref:表示AsyncAppender使用哪个具体的进行日志输出

    10、logback之pattern

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <layout class="ch.qos.logback.classic.PatternLayout">
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%npattern>
            layout>
    appender>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%npattern>
            encoder>
    appender>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    encoder表示对参数进行格式化,上面第一种使用了定义,第二种使用了定义,区别是:

    • 是0.9.19版本之后引进的,以前的版本使用,logback极力推荐的是使用而不是
    • 最常用的FileAppender和它的子类的期望是使用而不再使用

    11、appender的Filter

    的一个子节点,表示在当前给到的日志级别下再进行一次过滤,最基本的Filter有:

    • ch.qos.logback.classic.filter.LevelFilter
    • ch.qos.logback.classic.filter.ThresholdFilter

    LevelFilter这种过滤器:

    <configuration scan="false" scanPeriod="60000" debug="false">
    
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%npattern>
            encoder>
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>WARNlevel>
                <onMatch>ACCEPTonMatch>
                <onMismatch>DENYonMismatch>
            filter>
        appender>
    
        <logger name="java" additivity="false" />
        <logger name="java.lang" level="DEBUG">
            <appender-ref ref="STDOUT" />
        logger>
    
        <root level="INFO">
            <appender-ref ref="STDOUT" />
        root>
    
    configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    以上即,过滤WARN级别的日志,匹配时接收这个记录,不匹配时拒绝这个记录,因此最后的输出只有WARN日志:

    在这里插入图片描述
    注意,有了过滤器之后,这里最终输出的信息,是logger和Filter交集的关系,不是logger配info就输出info及以上了。再看ThresholdFilter过滤器,Threshold即门槛:

    
    <configuration scan="false" scanPeriod="60000" debug="false">
    
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%npattern>
            encoder>
            <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
                <level>INFOlevel>
            filter>
        appender>
    
        <logger name="java" additivity="false" />
        <logger name="java.lang" level="DEBUG">
            <appender-ref ref="STDOUT" />
        logger>
    
        <root level="INFO">
            <appender-ref ref="STDOUT" />
        root>
    
    configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    此时,门槛设置为INFO,则小于INFO级别的被过滤掉了,尽管logger中设置了DEBUG,最终输出的结果也没有DEBUG:

    在这里插入图片描述

    12、logback.xml全解释

    logback.xml文件各项配置的含义备份:

    
    
    <configuration scan="false" scanPeriod="60 seconds" debug="false">
        
        <property name="LOG_HOME" value="app/log"/>
        
        <property name="appName" value="logbackBootText"/>
    
        
        <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
            
            <layout class="ch.qos.logback.classic.PatternLayout">
                
                
                <springProfile name="dev">
                    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ----> [%thread] ---> %-5level %logger{50} - %msg%npattern>
                springProfile>
                <springProfile name="!dev">
                    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ==== [%thread] ==== %-5level %logger{50} - %msg%npattern>
                springProfile>
            layout>
        appender>
    
        
        <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
            
            
            
            
            
    
    
            
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                
                <fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.logfileNamePattern>
    
                
                <MaxHistory>365MaxHistory>
                
                <totalSizeCap>20GBtotalSizeCap>
    
                
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>100MBmaxFileSize>
                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>
    
        
        <appender name="appLogAppenderBoot" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    
                <fileNamePattern>${LOG_HOME}/boot-${appName}-%d{yyyy-MM-dd}-%i.logfileNamePattern>
    
                <MaxHistory>365MaxHistory>
    
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>100MBmaxFileSize>
                timeBasedFileNamingAndTriggeringPolicy>
            rollingPolicy>
            <layout class="ch.qos.logback.classic.PatternLayout">
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] -> [ %-5level ] [ %logger{50} : %line ] -> %msg%npattern>
            layout>
        appender>
    
        
        <root level="DEBUG">
            
            <appender-ref ref="stdout"/>
            <appender-ref ref="appLogAppender"/>
            <appender-ref ref="appLogAppenderBoot"/>
        root>
    
        
        
        
        
        
        
        <logger name="org.springframework.boot" level="debug" additivity="false">
            <appender-ref ref="appLogAppenderBoot"/>
        logger>
    
        
        
        
        
        <logger name="com.tuniu" level="debug" additivity="false">
            
            <appender-ref ref="appLogAppender"/>
            <appender-ref ref="stdout"/>
        logger>
    
    
        
        
        
        
    
        
        
    
    
    configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133

    13、logback常用配置备份

    贴个精简版的,目前工作中服务正在用的:

    
    <configuration scan="true" scanPeriod="60 seconds" debug="false">
        
        <property name="log.path" value="/logs"/>
        
        <property name="log.pattern"
                  value="%d{HH:mm:ss.SSS} [%thread] %-5level [%X{X-B3-TraceId:-},%X{X-B3-SpanId:-}] %logger{20} - [%method,%line] - %msg%n"/>
    
        
        <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>${log.pattern}pattern>
            encoder>
        appender>
    
        
        <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>${log.path}/data-service-ent-svc-info.logfile>
            
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                
                <fileNamePattern>${log.path}/data-service-xxx-svc-info.%d{yyyy-MM-dd}.logfileNamePattern>
                
                <maxHistory>7maxHistory>
            rollingPolicy>
            <encoder>
                <pattern>${log.pattern}pattern>
            encoder>
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                
                <level>INFOlevel>
                
                <onMatch>ACCEPTonMatch>
                
                <onMismatch>DENYonMismatch>
            filter>
        appender>
    
        <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>${log.path}/data-service-xxx-svc-error.logfile>
            
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                
                <fileNamePattern>${log.path}/data-service-ent-svc-error.%d{yyyy-MM-dd}.logfileNamePattern>
                
                <maxHistory>7maxHistory>
            rollingPolicy>
            <encoder>
                <pattern>${log.pattern}pattern>
            encoder>
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                
                <level>ERRORlevel>
                
                <onMatch>ACCEPTonMatch>
                
                <onMismatch>DENYonMismatch>
            filter>
        appender>
    
        
        <logger name="com.plat" level="info"/>
        
        <logger name="org.springframework" level="warn"/>
    
        <root level="info">
            <appender-ref ref="console"/>
        root>
    
        
        <root level="info">
            <appender-ref ref="file_info"/>
            <appender-ref ref="file_error"/>
        root>
    configuration>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    上面日志存放路径是/logs,而deploy部署文件则是将这个路径持久化到hostpath中,以便后续排查问题:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: xxx-svc-deployment
      namespace: mynamespace
    spec:
      selector:
        matchLabels:
          app: xxx-svc-deployment
      template:
        metadata:
          labels:
            app: xxx-svc-deployment
        spec:
          dnsPolicy: ClusterFirst
          containers:
            - name: xxx-svc-deployment
              image: repoistory.xxx-svc-deployment:release-2.0
              ports:
                - containerPort: 9527
              volumeMounts:
                - mountPath: /logs
                  name: go-logs     # 持久化到宿主机的hostpath
          volumes:
            - name: go-logs
              hostPath:
                path: /data/logs
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28


    参考文章:

    • https://www.cnblogs.com/xrq730/p/8619156.html
    • https://www.cnblogs.com/xrq730/p/8628945.html
  • 相关阅读:
    git的基本使用2
    Oracle触发器设置
    实验十 符号计算基础与符号微积分(matlab)
    Python可变长关键字参数,传入时使用变量值而不是变量名作为键
    Django 安装
    APT攻击的特点及含义
    如何逐步安装 AlmaLinux 9操作系统
    vue脚手架vue-cli的卸载与安装方式
    【力扣刷题】数组实现栈、后缀表达式(逆波兰表达式)求值、中缀表达式转换为后缀表达式(无括号&&有括号)
    Vue的computed和watch的区别是什么?
  • 原文地址:https://blog.csdn.net/llg___/article/details/133036585