Logback学习系列(二)- Logger详解


Logback学习系列


Logback项目(版本为1.2.3)分为三个模块,官方GitHub地址为:Logback官方源码地址

<module>logback-core</module>
<module>logback-classic</module>
<module>logback-access</module>

另外还有两个模块,logback-sitelogback-examples用于提供站点资源和模板案例,一般项目使用日志不会包含这两个模块。所以本系列在后续不再谈论这两个模块。logback-classic提供slf4j日志接口的基本实现,logback-access搭配Servlet容器提供了通过Http访问日志的功能。作为基础模块,二者均依赖于logback-core。logback的三大基础抽象是LoggerAppenderLayout。通过Logger的消息类型和打印级别决定是否需要打印日志。

<logger name="chapters.configuration.Foo" level="debug">
	<appender-ref ref="FILE" />
</logger>

在上面配置当中,定义了一个logger节点,它的名称为chapters.configuration.Foo,而级别为debug。

public class Foo {
    static final Logger logger = LoggerFactory.getLogger(Foo.class);

    public void doIt() {
        logger.debug("Did it again!");
    }
}

在上面这个doIt方法执行的时候,通过logger打印debug日志。首先在配置文件当中包含有对应的logger,其次级别也相同,所以会打印日志。而如果在xml中定义的level与java代码中的级别不同呢?这就要取决于二者级别的大小了。关于Logger有两点非常重要,第一个就是名称,第二个就是级别。

  • 名称

Logger是基于名称(name)的,通过相同的名称(大小写敏感)在同一个系统(Logger上下文)当中,获取是同一个对象,也就是说名称是唯一的。在一般的项目当中,都会采用类的名称作为Logger对象的名称,但是这会带来一个非常麻烦的问题,就是定义Logger的级别问题,如果每个Logger都需要在配置文件中定义level,那将是一种灾难,且不说配置文件会巨大,而且修改难度非常大,所以,必须有一种方式可以简化配置。这也是名称的第二个关键,数据结构,所有的Logger在一起构成一棵树,而树的根就是所谓的root节点,在配置文件中

<root level="debug">
	<appender-ref ref="STDOUT" />
</root>

在代码中可以通过以下方式获取到root节点Logger对象

Logger rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);

所有的Logger根据名称挂到这个root节点下面。根据包名决定是否为父子节点。假如当前上下文当中存在名称为名称为chapters.introduction的logger、名称为chapters.configuration.MyApp1的logger1, 名称为chapters.configuration.MyApp2的logger2, 则可以认为root节点作为树根,logger作为root的子节点,logger-logger1和logger2作为logger的根节点。如下图所示
在这里插入图片描述
之所以要将logger的节点都构造成一个树的结构,目的是为了方便进行日志级别的控制。比如以下配置logback.xml

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>

    <appender name="STDOUT"
              class="ch.qos.logback.core.ConsoleAppender">
        <!-- encoders are assigned by default the type
             ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
        <encoder>
            <pattern>
                %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
            </pattern>
        </encoder>
    </appender>
    
    <!-- Strictly speaking, the level attribute is not necessary since -->
    <!-- the level of the root level is set to DEBUG by default.       -->
    <root level="DEBUG">
        <appender-ref ref="STDOUT" />
    </root>

</configuration>

代码如下

package ch.qos.logback.test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class LoggerNameTest {

    private static final Logger rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);

    private static final Logger logger = LoggerFactory.getLogger("chapters.introduction");

    private static final Logger logger1 = LoggerFactory.getLogger("chapters.introduction.MyApp1");

    private static final Logger logger2 = LoggerFactory.getLogger("chapters.introduction.MyApp2");

    public static void main(String[] args) {
        logger.debug("------------chapters.introduction---------------");
        logger1.debug("------------chapters.introduction.MyApp1---------------");
        logger2.debug("------------chapters.introduction.MyApp2---------------");
    }

}

由于root的level为debug,所以这些子节点都集成了父节点的level,都为debug。最后输出如下
在这里插入图片描述
可见三个logger都打印了结果,也就是日志控制级别为debug级别
如果在配置文件中加入以下配置

<logger name="chapters.introduction" level="INFO" />

此时logger的级别变为了INFO级别(INFO>DEBUG),关于级别的问题后面详述,这里只需要知道如果logger控制输出级别为INFO,那么使用调用debug输出因为级别过小,所以不会输出结果。按照树形数据结构以及继承法则,logger1和logger2这里都继承logger的级别,以上的测试是没有输出结果。
在这里插入图片描述
从源码来分析一下
在这里插入图片描述
从上图也可以看出,其实我们上面介绍的树形结构严格来说是不对的,这里包含了一个名称为chapters的节点,chapters.introduction并不是直接作为root的节点。如果用户只在代码中定义了一个如下的logger

private static final Logger logger2 = LoggerFactory.getLogger("chapters.introduction.MyApp2");

那么logger组成的树形结构如下所示
在这里插入图片描述
名称作为logger的唯一标识,同时通过树形结构建立彼此之间的关联。对应Logger类的继承结构如下所示
在这里插入图片描述
注意到这里其实有两个Logger类,其实最下面的那个类是ch.qos.logback.classic.Logger,上面的接口是org.slf4j.Logger,前者是后者在logback-classic中的实现。Logger的name保存名称、而parent、childrenList则用于保证树形结构。

/**
 * The name of this logger
 */
private String name;
/**
 * The parent of this category. All categories have at least one ancestor
 * which is the root category.
 */
transient private Logger parent;

/**
 * The children of this logger. A logger may have zero or more children.
 */
transient private List<Logger> childrenList;

在parent属性注释当中,包含了几个重要的信息,首先这里出现了一个词category,也就是类别的意思,任何的类别都有只是一个祖先,因为根类别是必定存在,而所有类别都是挂载在根类别上的。所以所谓的类别,其实就是分类,也可以说是分层,同时还有祖先和后代的称呼,当然这些在数据结构中树固有的称谓了。这里也不继续深究了。

  • 级别

上面的Logger类除了name、parent、childrenList三个属性之外,还有另外两个属性

// The assigned levelInt of this logger. Can be null.
transient private Level level;

// The effective levelInt is the assigned levelInt and if null, a levelInt is
// inherited form a parent.
transient private int effectiveLevelInt;

这里所谓的level本身是logback-classic中的ch.qos.logback.classic.Level类,这个类中包含以下几个级别。 OFF, ERROR, WARN, INFO, DEBUG, TRACE and ALL,所谓的大小最后也是映射到数字。如下所示

public static final int OFF_INT = Integer.MAX_VALUE;
public static final int ERROR_INT = 40000;
public static final int WARN_INT = 30000;
public static final int INFO_INT = 20000;
public static final int DEBUG_INT = 10000;
public static final int TRACE_INT = 5000;
public static final int ALL_INT = Integer.MIN_VALUE;

public static final Integer OFF_INTEGER = OFF_INT;
public static final Integer ERROR_INTEGER = ERROR_INT;
public static final Integer WARN_INTEGER = WARN_INT;
public static final Integer INFO_INTEGER = INFO_INT;
public static final Integer DEBUG_INTEGER = DEBUG_INT;
public static final Integer TRACE_INTEGER = TRACE_INT;
public static final Integer ALL_INTEGER = ALL_INT;

比如DEBUG对应数字10000,而INFO对应数字20000,这也是为啥说DEBUG级别要小于INFO级别。最后所有级别的排序最后为OFF > ERROR > WARN > INFO > DEBUG > TRACE > ALL。另一个属性effectiveLevelInt,所谓的有效级别,就是如果当前logger定义了level属性,则为level属性的值,没有定义level,则继承自父亲,如果父亲没有,则延着树结构向上查找,直到root,而root在Logger上下文构造的时候创建的,它的级别默认为DEBUG。对应源码如下所示

public LoggerContext() {
    super();
    this.loggerCache = new ConcurrentHashMap<String, Logger>();

    this.loggerContextRemoteView = new LoggerContextVO(this);
    this.root = new Logger(Logger.ROOT_LOGGER_NAME, null, this);
    this.root.setLevel(Level.DEBUG);
    loggerCache.put(Logger.ROOT_LOGGER_NAME, root);
    initEvaluatorMap();
    size = 1;
    this.frameworkPackages = new ArrayList<String>();
}

以下为创建子logger的时候直接将父logger的有效级别设置给子logger.
在这里插入图片描述
之所以Logback这类的日志框架要优于System.out或是System.err,一个很重要的原因就是通过级别可以有效控制日志是否真实进行打印。要知道,当代码编写完成之后,使用System.out或是System.err就必定会打印,而使用logger调用对应的方法,比如info时,是否打印取决于当前logger对象的等级,所以,logger的等级系统是优于System.out的关键。比如通过调用debug方法来打印日志时
在这里插入图片描述
然后将当前logger的有效等级与方法的等级进行比较
在这里插入图片描述
在这里,INFO大于DEBUG,不需要进行打印,方法直接返回。
以上详细介绍了Logger的五个关键属性以及对应的作用,首先name保证了logger的唯一性,配合parent和childrenList将Logger上下文中的所有Logger实例组成了一棵树形结构,同时默认必定存在一个root logger,这样每个Logger都必定存在一个祖先。其次通过level和effectiveLevelInt,用户可以方便通过配置来控制是否需要真实打印日志。然后再结合树形结构的继承来实现level的继承,这样同样设置一个logger的等级就达到控制它的后代(未设置等级)的等级。这样就不需要一个logger一个logger设置等级了。可以说,这里的数据结构(树)是精髓所在

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: logback-spring.xml 是使用 Spring Boot 框架进行日志记录的配置文件之一。它使用 Logback 库,这是一个广泛使用的 Java 日志框架。 以下是一个 logback-spring.xml 配置文件的例子,以及其每个配置选项的说明: ```xml <?xml version="1.0" encoding="UTF-8"?> <configuration> <!-- 控制台输出 --> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <!-- 日志文件输出 --> <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>logs/mylog.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>logs/mylog.%d{yyyy-MM-dd}.log</fileNamePattern> <maxHistory>30</maxHistory> </rollingPolicy> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <!-- 日志级别设置 --> <root level="INFO"> <appender-ref ref="console" /> <appender-ref ref="file" /> </root> </configuration> ``` 配置文件的 `<configuration>` 标签是必需的,它包含了整个配置文件。下面是每个配置选项的详细说明: - `<appender>`:定义一个日志输出目标,可以是控制台或文件。`name` 属性是必需的,用于引用此 appender。`class` 属性指定 appender 的实现类。 - `<encoder>`:定义输出格式,将日志信息转换为文本。`pattern` 元素是必需的,用于指定输出格式。 - `<file>`:定义日志文件名,可以是相对路径或绝对路径。 - `<rollingPolicy>`:定义滚动策略,用于在日志文件达到一定大小或时间间隔时,将当前日志文件重命名并创建新的日志文件。`class` 属性指定滚动策略的实现类。`fileNamePattern` 元素指定日志文件名的格式。`maxHistory` 元素定义保留的历史日志文件数目。 - `<root>`:定义日志记录器的根节点,用于指定日志级别和输出目标。`level` 属性指定日志记录器的级别,包括 TRACE、DEBUG、INFO、WARN、ERROR 和 OFF。`appender-ref` 元素用于指定输出目标,可以是之前定义的 appender。 希望这个简单的logback-spring.xml配置例子能够对你有所帮助。 ### 回答2: logback-spring.xml是Logback日志框架在Spring Boot项目的配置文件,它的作用是为了更好的集成和使用Logback。下面我们来详细解析一下它的配置。 首先,logback-spring.xml需要放在classpath下,它会自动覆盖logback.xml,在Spring Boot应用启动时被加载。Logger和AppenderLogback日志框架比较重要的组件,所以我们需要着重来讲解。 1. Logger LoggerLogback日志框架的主要组件,它负责接收日志信息,并且把日志信息转发给相应的Appender进行输出。Logger的常见配置项如下: ① name:用来指定Logger的名字,通常是当前类的包名。 ② level:用来指定日志级别,常用的级别有TRACE、DEBUG、INFO、WARN、ERROR和FATAL。 ③ additivity:用来指定是否向父Logger传递日志信息,默认为true,意味着Logger会向上层的父Logger发送该日志信息。 Logger的配置例子: <logger name="com.example.demo" level="DEBUG" additivity="true"> <appender-ref ref="CONSOLE" /> <appender-ref ref="FILE" /> </logger> 上面的配置代码表示日志输出到控制台和文件,并采用DEBUG级别。 2. Appender AppenderLogback日志框架的输出目的地,用来定义将日志信息输出到哪里。Appender的常见配置项如下: ① name:用来给Appender一个名字,最好是全局唯一的。 ② class:用来指定Appender的具体实现类。 ③ encoder:用来指定日志输出格式,可以是SimpleEncoder或PatternLayout。 ④ file:输出日志的文件路径。 Appender的配置例子: <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%-4relative [%thread] %-5level %class{35} - %msg%n</pattern> </encoder> </appender> 上面的配置代码表示输出到控制台,使用ConsoleAppender类,并且指定输出格式。 除了Logger和Appender之外,Logback日志框架还提供了Layout、Filter等组件来帮助我们更好的为日志配置样式、添加日志过滤器等操作。 细节注意: 1.由于Logback日志框架采用类似责任链模式的方式处理日志,因此最好不要在logback-spring.xml定义多个Appender。 2.在使用Logback日志框架时,最好将logback.xml或logback-spring.xml文件的日志级别设置成INFO以上级别,这样可以确保在生产环境输出日志时不会太过频繁。 3.尽量不要在logback-spring.xml内动态修改日志级别,推荐使用Spring Boot Actuator的loggers接口动态修改日志级别。 ### 回答3: logback-spring.xml是在Spring框架使用的日志配置文件。该文件定义了Logback日志框架的配置参数,以满足不同的日志记录需求。在下面,我将详细介绍logback-spring.xml的各种配置参数: 1. <configuration>标签:logback-spring.xml的根标签,可以用于定义全局的配置属性。 2. <appender>标签:用于指定日志输出器的类型和相关参数。 3. <logger>标签:配置日志记录器,包括指定输出级别、输出格式、是否继承等属性。 4. <root>标签:指定根日志记录器,可以通过该标签指定所有日志输出器的默认输出级别。 5. <springProperty>标签:可以在配置文件定义一些Spring框架的属性值,供其他组件使用。 6. <conversionRule>标签:定义日志输出格式的转换规则,可以通过该标签自定义日志输出格式。 7. <encoder>标签:指定日志格式化器的类型和相关参数。 总之,logback-spring.xml文件是Logback日志框架在Spring框架的配置文件,通过其的配置参数,可以灵活地实现日志输出级别、格式、输出器等方面的定制化需求。为了更好地应对不同的日志需求,我们需要合理地利用各种配置标签和属性,为应用程序提供高质量的日志记录服务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lang20150928

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值