• logback中logger详解


    前言

    logback实践笔记

    ​ 上一篇主要对root进行了实践总结,现在基于上一篇中的springboot代码环境对logback.xml中的logger来进行实践和自己遇到的坑。

    logger简介

    ​ 日志属性,可以根据logger中的name属性指定某个文件或者文件夹输出的日志级别,并通过appender-ref指定日志的输出格式。还有一个additivity属性,如果设置为false的话就不会向上传递。

    上代码

    logback.xml:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration debug="true" scan="true" scanPeriod="60 seconds">
        <appender name="logger_stdout" class="ch.qos.logback.core.ConsoleAppender">
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <Pattern>%d{YYYY-MM-dd HH:mm:ss} | %-5level | %thread | %logger - %msg%n</Pattern>
            </encoder>
        </appender>
    	<!-- name=指定打印日志文件级别 level=日志级别 additivity=是否想向上传递 先不加上 additivity=false 属性 -->
        <logger name="com.example.logback.logger" level="info">
          	<!-- 指定输出的appender -->
            <appender-ref ref="logger_stdout"/>
        </logger>
    </configuration>
    

    测试代码:

    package com.example.logback.logger;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    /**
     * @ClassName LoggerTest
     * @Description TODO
     * @Author ouyangkang
     * @Date 2019-01-07 17:04
     **/
    @Component
    public class LoggerTest {
    
        private final Logger logger = LoggerFactory.getLogger("测试");
    
        public void loggerTest() {
            logger.info("info=====>");
            logger.error("error====》");
            logger.debug("debug=====》");
        }
    }
    
    

    单元测试代码:

    package com.example.logback;
    
    import com.example.logback.logger.LoggerTest;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import javax.annotation.Resource;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class LogbackApplicationTests {
    	@Resource
    	private LoggerTest loggerTest;
    	@Test
    	public void loggerTest(){
    		loggerTest.loggerTest();
    	}
    
    }
    

    输出结果如下,图一

    图一

    看到了没有,并没有任何的输出。

    分析

    ​ 自己看到上面输出的结果也是很懵逼的,仔细查看了logback.xml中的代码,logger中的name指定的是自己测试代码的包啊,日志级别是info。怎么就啥都没输出啊。appender中的配置也没错啊。当初自己是找了好久的错误都没有找出来。

    测试代码

    ​ 首先查看自己写的测试代码,自己对 private final Logger logger = LoggerFactory.getLogger("测试");这行代码产生了怀疑,这个logger形参指定的是哪一个日志框架中的对象。于是自己修改上面的测试代码如下

    public class LoggerTest {
        public void loggerTest() {
        	Logger logger = LoggerFactory.getLogger("测试");
            logger.info("info=====>");
            logger.error("error====》");
            logger.debug("debug=====》");
        }
    }
    

    对logger logger = LoggerFactory.getLogger("测试"); 这行代码进行debug。进入了,如图二

    图二

    ​ getLogger方法是slf4j中获取logger工厂,查看getILoggerFactory()方法,发现其实他就是获取一个具体的loggerFactory工厂,看过抽象工厂设计模式的应该就知道了。这里由于我们是新建了logback.xml,那么返回的工厂类其实就是logback-classic中的LoggerContext。然后调用getLogger方法创建一个Logger对象。发现返回的Logger对象如下 图三

    图三

    此时我们继续跟进logger.info。找到最关键的代码,如图四

    图四

    ​ 该关键代码在logback-classic中的Logger类中,根据这个callAppenders方法名可以知道这就是打印日志的关键方法,继续跟进,查看callAppenders方法。如图五

    图五

    这个划重点了,仔细看,这个for循环中,可以看出来257行就是打印这个日志的代码了。但是这个Logger l = this; 这个代码是关键。这个this就是对象就是我们根据LoggerFactory.getLogger("测试")获取到的。继续跟进appendLoopOnAppenders方法。如图六

    图六

    发现是aai来打印这行日志,那么aii是怎么打印这行日志的呢,这个就要回到一开始logback.xml配置的地方了,自己配置了测试代码下的日志输出格式,但是没有配置一个logger.name 叫做”测试“的包下面的日志输出格式啊。于是自己修改logback.xml中的代码如下

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration debug="true" scan="true" scanPeriod="60 seconds">
        <appender name="logger_stdout" class="ch.qos.logback.core.ConsoleAppender">
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <Pattern>%d{YYYY-MM-dd HH:mm:ss} | %-5level | %thread | %logger - %msg%n</Pattern>
            </encoder>
        </appender>
    	<!-- name=指定打印日志文件级别 level=日志级别 additivity=是否想向上传递 先不加上 additivity=false 属性 -->
        <logger name="测试" level="info">
          	<!-- 指定输出的appender -->
            <appender-ref ref="logger_stdout"/>
        </logger>
    </configuration>
    

    运行单元测试,得出结果如下图七

    图七

    有了日志输出。

    思考

    ​ 我看公司代码一般获取日志对象都是 private final Logger logger = LoggerFactory.getLogger(this.getClass()); 然后logback.xml中的logger属性中name都是指定某一包名。其实这里自己跟代码跟了挺久了其中在图五中那个for循环就是一直向上查找,logback.xml是否设置了有该包下的日志输出格式。如果查找到有该输出格式就输出,并查看logback.xml中logger中你是否设置了additivity。不是这就是默认true,继续向上查找是否还有不同的输出格式。如果设置为false,就结束。

    我举一个例子吧这样就很好理解了

    logback.xml代码如下

    <?xml version="1.0" encoding="utf-8" ?>
    <!-- debug=是否打印logback内部日志 scan=是否重新加载  scanPeriod=多久扫描一次 -->
    <configuration debug="true" scan="true" scanPeriod="60 seconds">
        <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <Pattern>%d{YYYY年MM月dd日 HH:mm:ss} | %-5level | %thread | %logger - %msg%n</Pattern>
            </encoder>
        </appender>
    
        <appender name="logger_stdout" class="ch.qos.logback.core.ConsoleAppender">
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <Pattern>%d{YYYY-MM-dd HH:mm:ss} | %-5level | %thread | %logger - %msg%n</Pattern>
            </encoder>
        </appender>
    
        <!-- 指定name 在该aa.bb.cc 下的日志输出格式 这个就是在aa.bb.cc.dd 上的日志输出格式-->
        <logger name="aa.bb.cc" level="info">
            <!-- 指定输出的appender -->
            <appender-ref ref="logger_stdout"/>
        </logger>
        <!-- 指定name 在该aa.bb.cc.dd 下的日志输出格式 additivity 默认为true 可以向上传递-->
        <logger name="aa.bb.cc.dd" level="info" >
            <appender-ref ref="stdout"/>
        </logger>
    </configuration>
    
    

    测试代码如下

    package com.example.logback.logger;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    /**
     * @ClassName LoggerTest
     * @Description TODO
     * @Author ouyangkang
     * @Date 2019-01-07 17:04
     **/
    @Component
    public class LoggerTest {
        private final Logger logger = LoggerFactory.getLogger("aa.bb.cc.dd.ee");
        public void loggerTest() {
            logger.info("info=====>");
            logger.error("error====》");
            logger.debug("debug=====》");
        }
    }
    
    

    单元测试代码如 上代码里面的单元测试代码一样。

    得到结果如下:

    图八

    总结

    ​ LoggerFactory.getLogger(name),其中name对应着logback.xml中logger属性中name=对应的子包,当然你也可以设置一样的。logger中的additivity设置为false是代表该logger日志打印不向上传递, appender-ref指定的日志输出格式。

    ​ 下一篇把logback.xml中的appender属性介绍一下并进行实践。

  • 相关阅读:
    BZOJ.4842.[NEERC2016]Delight for a Cat(费用流)
    LOJ.6060.[2017山东一轮集训Day1/SDWC2018Day1]Set(线性基)
    BZOJ.5319.[JSOI2018]军训列队(主席树)
    BZOJ.4212.神牛的养成计划(Trie 可持久化Trie)
    HDU.5385.The path(构造)
    HDU.4903.The only survival(组合 计数)
    Codeforces.1043F.Make It One(DP 容斥)
    BZOJ.5110.[CodePlus2017]Yazid 的新生舞会(线段树/树状数组/分治)
    洛谷.3676.小清新数据结构题(树链剖分 树状数组)
    BZOJ.4598.[SDOI2016]模式字符串(点分治 Hash)
  • 原文地址:https://www.cnblogs.com/Krloypower/p/10243023.html
Copyright © 2020-2023  润新知