Java日志框架 Round One- SLF4J(1.7.25) + Logback(1.2.3)

maven依赖

<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

1 logback介绍

Logback 同第一个广泛应用的java日志框架log4j 都来自于Ceki Gülcü大神的手笔,logback继承于log4j,基于SLF4J提供的外观接口, 是两大java日志外观框架阵营 slf4j(也是来自Ceki Gülcü大神) 和common logging之中slf4j的官方实现。刚面世的时候由于性能上较log4j 和 jul的巨大提升受到java工程师的热捧,现在被log4j2爆了。
下面这段内容 摘自 http://www.logback.cn/
Logback 的架构非常的通用,适用不同的使用场景。Logback 被分成三个不同的模块:logback-core,logback-classic,logback-access。
logback-core 是其它两个模块的基础。logback-classic 模块可以看作是 log4j 的一个优化版本,它天然的支持 SLF4J,所以你可以随意的从其它日志框架(例如:log4j 或者 java.util.logging)切回到 logack。
logback-access 可以与 Servlet 容器进行整合,例如:Tomcat、Jetty。它提供了 http 访问日志的功能。

2 logback架构介绍

logback的架构主要基于三个对象进行配置

Bean描述
Logger日志
Appender日志输出者
Encoder编码者

2.1 Logger 日志

logger对象是日志框架的核心对象,主要属性是name,用于产生日志事件,并绑定了一个或多个appender用于输出到指定的目的地。

如何获取一个logger实例?
example

Logger logger1 = LoggerFactory.getLogger(Dog.class);
Logger logger2 = LoggerFactory.getLogger("demo");

其中logger2 得到的实例及xml配置文件中声明的logger实例。

<configuration>
	<logger name="demo" />
</configuration>

2.1.1 LoggerContext 上下文

Logback通过LoggerContext来管理所有的logger,每个logger都继承于ROOT根日志,这个我们可以从代码中看到,在初始化LoggerContext实例的时候会初始化一个名为ROOT的logger。

	public LoggerContext() {
        this.root.setLevel(Level.DEBUG);
        this.loggerCache.put("ROOT", this.root);
        this.initEvaluatorMap();
        this.size = 1;
        this.frameworkPackages = new ArrayList();
    }

每一个 logger 都依附在 LoggerContext 上,它负责产生 logger,并且通过一个树状的层级结构来进行管理。

2.1.2 Level 有效层级

Logger 能够被分成不同的等级。不同的等级(TRACE, DEBUG, INFO, WARN, ERROR)定义在 ch.qos.logback.classic.Level 类中。

对于一个给定的名为 L 的 logger,它的有效层级为从自身一直回溯到 root logger,直到找到第一个不为空的层级作为自己的层级。
为了确保所有的 logger 都有一个层级,root logger 会有一个默认层级 — DEBUG

//只展示了部分接口
package org.slf4j;
public interface Logger {
    void trace(String var1);
    void trace(Marker var1, String var2);
    void debug(String var1);
    void debug(Marker var1, String var2);
    void info(String var1);
    void info(Marker var1, String var2);
    void warn(String var1);
    void warn(Marker var1, String var2);
    void error(String var1);
    void error(Marker var1, String var2);
}

层级有效力比较:TRACE < DEBUG < INFO < WARN < ERROR。

如果一条的日志的打印级别大于 logger 的有效级别,该条日志才可以被打印出来。

public final class Level implements Serializable {
    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;
}

有效力的大小设置,logback是通过给定一个int整数来比较的。

此外logback还支持使用marker标志来设定自定义的级别

		Logger logger = LoggerFactory.getLogger(Dog.class);
        Marker marker = MarkerFactory.getMarker("HAPPY");
        logger.info(marker,"The litte dog felt very happy");

带有marker的输出语句的有效力等同于调用的输出方法的有效力,上例中marker的有效力即INFO的有效力。如果使用TRACE控制台就看不到这个日志消息了。

2.1.3 层级结构与配置传递

官方是这样解释的,如果一个 logger 的名字加上一个 . 作为另一个 logger 名字的前缀,那么该 logger 就是另一个 logger 的父级。
按照我们通常的做法,会使用类的完全限定名作为logger的名称,这样就可以避免名称的重复而获取到其他类中的重名的logger。

private static Logger logger = LoggerFactory.getLogger(Dog.class);

假设我们现在有一个类,creature.animal.Dog, 我们在代码中初始化一个logger实例,结果就会得到包含ROOT的四个logger实例对象,logback将根据完全限定名以 点 ( . )分割并依次初始化,以此来构建上下级的树形结构。

/**
 * @author Kern
 * @date 2020/3/26 17:04
 * @description TODO
 */
public class Dog {
    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(Dog.class);
        ((LoggerContext)LoggerFactory.getILoggerFactory()).getLoggerList().forEach(e -> {
            System.out.println(e.getName());
        });
    }
}

在这里插入图片描述
那么这个结构的意义在哪里? 配置的传递!
以level的配置为例,我们都明白初始化一个日志的时候我们是不需要设定Level的

一般情况下都是在初始化前进行配置。如果不配置level的话,本文第一段代码中也可以看到,ROOT的默认的level是DEBUG。

当子类的level配置为null时,logback将向上查找,直到找到一个level层级不为null的父类,并沿用他的level配置。如果子类的level配置不为null,则直接使用子类的level。 不仅如此,包括appender置也沿用这一规则。这样的设计帮助实现了一次配置,多处使用的功能,同时也是非常灵活的。

其次可以通过设定additivity的属性为false来阻断配置的传递(Why would you do that?)。

//java
((ch.qos.logback.classic.Logger)logger).setAdditive(false);
<!-- xml -->
<configuration>
	<logger name="creature.animal.Dog" additivity="false"/>
</configuration>

由于上下文初始化时的默认行为,一个什么也不配置的logback 默认的Level为DEBUG,同时持有一个ConsoleAppender,也就是说默认情况下,将至少具备在控制台打印日志有效层级为DEBUG的消息。

public class LoggerContext extends ContextBase implements ILoggerFactory, LifeCycle {

	final Logger root = new Logger("ROOT", (Logger)null, this);
	public LoggerContext() {
		//默认加载ROOT
        this.root.setLevel(Level.DEBUG);
        this.loggerCache.put("ROOT", this.root);
        this.initEvaluatorMap();
        this.size = 1;
        this.frameworkPackages = new ArrayList();
    }
}
-------------------------------分割线----------------------------

//在读取不到配置文件时,默认的配置类。
public class BasicConfigurator extends ContextAwareBase implements Configurator {
    public BasicConfigurator() {
    }

    public void configure(LoggerContext lc) {
        this.addInfo("Setting up default configuration.");
        //控制台appender
        ConsoleAppender<ILoggingEvent> ca = new ConsoleAppender();
        ca.setContext(lc);
        ca.setName("console");
        LayoutWrappingEncoder<ILoggingEvent> encoder = new LayoutWrappingEncoder();
        encoder.setContext(lc);
        TTLLLayout layout = new TTLLLayout();
        layout.setContext(lc);
        layout.start();
        encoder.setLayout(layout);
        ca.setEncoder(encoder);
        ca.start();
        //下面两句加载到ROOT中
        Logger rootLogger = lc.getLogger("ROOT");
        rootLogger.addAppender(ca);
    }
}

2.2 Appender 日志输出者

appender的任务是写入日志事件到目的地(文件/控制台/远程服务器)

一个 logger 可以有多个 appender。也就是说一个日志实例可以将其产生的日志事件写入到多个目的地。

站在 logback 的角度来说,输出目的地叫做 appender。appender 包括console、file、remote socket server、MySQL、PostgreSQL、Oracle 或者其它的数据库、JMS、remote UNIX Syslog daemons 中。

2.2.1 Appender接口结构

在这里插入图片描述
我们项目中常用的ConsoleAppender / FileAppender / RollingFileAppender 如上图,继承于 UnsynchronizedAppenderBase,其中的doAppend 方法与 AppenderBase 的 doAppend方法的主要差异在于方法上的同步锁,这也是类命名的由来。

AppenderBase 的 doAppend() 的实现是 synchronized 的。 不同的线程通过同一个 appender 打印日志是线程安全的。当一个线程 T 正在执行 doAppend() 方法,接下来其它的线程调用将会被阻塞直到线程 T 离开 doAppend() 方法,这样可以确保 T 对 appender 的访问具有独占性。

因为这种同步并不总是适合的,所以 logback 提供了 ch.qos.logback.core.UnsynchronizedAppenderBase 类,跟 AppenderBase 类十分的相似。

public abstract class UnsynchronizedAppenderBase<E> extends ContextAwareBase implements Appender<E> {
	public void doAppend(E eventObject) {
        //省略。。。
    }
}
-------------------分割线-------------------------------
public abstract class AppenderBase<E> extends ContextAwareBase implements Appender<E> {
	public synchronized void doAppend(E eventObject) {
        //省略。。。
    }
}

2.2.2 常用的appender简单介绍

具体的配置就不多赘述了。简单介绍一下功能及关键的属性

2.2.2.1 ConsoleAppender 输出到控制台
属性描述默认值
encoder通过pattern配置输出格式
targetSystem.out/System.err控制台输出调用System.out

配置示例

	<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<!--    <encoder 元素强制一个 class 属性去指定一个类的全限定名,用于实例化。
        如果 encoder 的 class 是 PatternLayoutEncoder,那么基于默认类映射,class 属性可以被隐藏。-->
        <encoder>
            <pattern>[%t] %level %d{yyyy-MM-dd'T'HH:mm:ss} %class.%method[%line] %msg%n</pattern>
        </encoder>
<!--        默认为System.out   System.out  / System.err-->
        <target>System.out</target>
    </appender>
2.2.2.2 FileAppender 输出到文件
属性描述默认值
appendboolean是否在文件中追加内容,false的话就覆盖log文件true
encoder通过pattern配置输出格式
fileString文件名
prudentboolean严谨模式,文件加排他锁,影响性能false

配置示例

	<appender name="localFile" class="ch.qos.logback.core.FileAppender">
<!--        文件名-->
        <file>本地路径/log.log</file>
        <!--            只输出INFO以上的日志-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
<!--        是否追加,false覆盖,默认true-->
        <append>true</append>
<!--        将 immediateFlush 设置为 false 可以获得更高的日志吞吐量,默认方法更加的安全。 -->
        <immediateFlush>true</immediateFlush>

        <!--        encoder即该appender的输出格式配置-->
        <encoder>
            <pattern>%level %d{yyyy-MM-dd'T'HH:mm:ss} %class.%method[%line] %msg%n</pattern>
        </encoder>
    </appender>
2.2.2.3 RollingFileAppender 滚动文件输出

这部分内容文首中内容介绍的十分详细,就不复制黏贴了。还是需要仔细看看。为了文章的完整性,还是简单贴一些关键概念。

RollingFileAppender 继承自FileAppender,具有滚动输出日志文件的功能。

例如,RollingFileAppender 将日志输出到 log.txt 文件,在满足了特定的条件之后,将日志输出到另外一个文件。

属性描述默认值
rollingPolicyRollingPolicy负责日志轮转的功能。what to do?
triggeringPolicyTriggeringPolicy它负责日志轮转的时机,通知 RollingFileAppender 何时轮转。。 when to do?

示例配置

 <appender name="warnRolling" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--        滚动规则-->
<!--        只输出WARN以上的日志-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>WARN</level>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        	<!--这里为了实验,时间格式配置到了分秒,实际生产中是不可能这么小的时间粒度的 -->
            <fileNamePattern>本地路径/%d{yyyy-MM-dd'T'HHmm}/rollingLog.%d{yyyy-MM-dd'T'HHmmss,aux}.log</fileNamePattern>
            <maxHistory>5</maxHistory>
            <totalSizeCap>1MB</totalSizeCap>
        </rollingPolicy>
<!--        encoder即该appender的输出格式配置-->
        <encoder>
            <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
        </encoder>
    </appender>

2.2.3 Encoder

从上面的例子中可以看到,每个appender中都包含了一个encoder元素,我们从常用的三个Appender的父类OutputStreamAppender也可以看到Encoder属性

public class OutputStreamAppender<E> extends UnsynchronizedAppenderBase<E> {
    protected Encoder<E> encoder;
}

如果把appender解释为日志的输出者,那么encoder就是日志消息的解释器,encoder接口负责把日志消息转换为字节数组,其实现之一PatternLayoutEncoder是我们在xml配置文件中常用到的格式化的定制日志消息的解释器。

2.2.3.1 LayoutWrappingEncoder

直到 logback 的 0.9.19 版本,许多 appender 依赖 layout 实例去控制日志的格式化输出。因为基于 layout 接口存在了大量的代码,所以我们需要一种方式容 encoder 与 layout 进行交互。LayoutWrappingEncoder 就是 encoder 与 layout 之间的桥梁。它实现了 encoder 接口并且包裹了一个 layout,通过委托该 layout 将日志事件转换为字符串。

2.2.3.2 PatternLayoutEncoder

由于 PatternLayout 是最常用的 layout,logback 使用 PatternLayoutEncoder 来满足这种用法。它扩展了 LayoutWrappingEncoder,被限制用来包裹 PatternLayout 实例。
在 logback 0.9.19 版本,无论 FileAppender 还是其子类通过 PatternLayout 来进行配置,都必须使用 PatternLayoutEncoder 来代替。
outputPatternAsHeader
为了帮助解析日志文件,logback 可以将格式化字符串插入到日志文件的顶部。这个功能默认是关闭的。可以为相关的 PatternLayoutEncoder 设置 outputPatternAsHeader 属性的值为 true 来开启这个功能。

2.2.3.3 Layout

layout 是 logback 的组件,负责将日志事件转换为字符串。Layout 接口中的 format() 方法接受一个表示日志事件的对象 (任何类型) 并返回一个字符串。

常用的 PatternLayout 格式字符串解析

编码释义
%c{length} / %lo{length} / %logger{length}日志的名称
%C{length} / %class{length}输出发出日志请求的全限定名称
%contextName / %cnlogger上下文名称
%d{pattern} / %date{pattern} / %d{pattern, timezone} / %date{pattern,timezone}时间{格式,时区}
%L / %line所在行号,生成行号不是特别快,因此不建议使用。
%m / %msg / %message输出日志消息
%M / %method输出发出日志请求的方法名
%n换行
%p / %le / %level输出日志时间的级别
%r / %relative输出应用程序启动到创建日志事件所花费的毫秒数
%t / %thread输出生成日志事件的线程名

3 完整配置及DEMO测试

logback 环境的配置会在应用初始化的时候完成。最优的方式是通过读取配置文件。当然也可以利用ServiceLoader机制加载继承了BasicConfigurator的配置类来完成。这里采用常用的xml配置。

3.1 配置文件查找规则

这里简单介绍一个logback加载配置文件的规则:

  • 1.logback 会在类路径下寻找名为 logback-test.xml 的文件。
  • 2.如果没有找到,logback 会继续寻找名为 logback.groovy 的文件。
  • 3.如果没有找到,logback 会继续寻找名为 logback.xml 的文件。
  • 4.如果没有找到,将会通过 JDK 提供的 ServiceLoader 工具在类路径下寻找文件 META-INFO/services/ch.qos.logback.classic.spi.Configurator,该文件的内容为实现了 Configurator 接口的实现类的全限定类名。
  • 5.如果以上都没有成功,logback 会通过 BasicConfigurator 为自己进行配置,并且日志将会全部在控制台打印出来。

3.2 配置文件内容简要

每一个xml配置文件用 configuration 标签包围,不需要xml文件头。
其中包括 :

  • appender
  • logger
  • root
<configuration>
<!--    0-N个-->
    <appender name="" class="">
        <!--    1个-->
        <encoder>
            <!--    1个-->
            <pattern></pattern>
        </encoder>
    </appender>
    
<!--    0-N个-->
    <logger name="">
        
    </logger>

<!--    1个-->
    <root level="">
        <!--    0-N个-->
        <appender-ref ref="" />
    </root>

</configuration>

3.3 测试Demo

新建springboot项目
在这里插入图片描述
pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>cn.kerninventory</groupId>
    <artifactId>demo-slf4j-logback</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>demo-slf4j-logback</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

<!--        移除spingboot中旧版本的logback-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-api</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>ch.qos.logback</groupId>
                    <artifactId>logback-classic</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
        <!--logback中有slf4j的依赖,不用重复引,不然还可能不兼容 -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

package cn.kerninventory.demoslf4jlogback;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class DemoSlf4jLogbackApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoSlf4jLogbackApplication.class, args);
    }

}

新建logback-test.xml 文件

<!--配置文件,只要符合logback的解析规则就可以-->
<!--在 logback 版本 0.9.17 之后,显示规定的标签名不区分大小写。-->

<!--appender 输出目的地-->
<!--layout   输出的格式-->
<!--root     根日志-->

<!--scan=true, 配置文件修改时自动扫描,默认一分钟扫描一次, 该文件中设置30S扫描一次-->
<!--当设置了 scan="true",会新建一个 ReconfigureOnChangeTask 任务用于监视配置文件是否变化。ReconfigureOnChangeTask 也会自动监视外部文件的变化。-->
<!--如果更改后的配置文件有语法错误,则会回退到之前的配置文件。-->
<!-- packagingData="true"启用展示包数据,开销比较大-->
<configuration
        scan="true" scanPeriod="30 seconds"
        packagingData="true"
>
<!--    设置日志上下文的名称-->
    <contextName>LOGBACK</contextName>
<!--    设置属性-->
    <property name="basicDir" value="/logs" />
<!--    设置属性,引入其他配置文件, 
这个配置文件配置了一个dir.logs的路径属性,
下文中看到的话,可以替换为自己需要的路径
-->
    <property resource="filedir.properties" />

<!--    配置该属性则将打印配置文件的状态, 这将与设置root.level=debug 取得一样的效果-->
    <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />

<!--    appender 通过 <appender> 元素进行配置,
    需要两个强制的属性 name 与 class。
    name 属性用来指定 appender 的名字,
    class 属性需要指定类的全限定名用于实例化。

    <appender> 元素可以包含
    0 或一个 <layout> 元素,
    0 或多个 <encoder> 元素,
    0 或多个 <filter> 元素。
    除了这些公共的元素之外,<appender> 元素可以包含任意与 appender 类的 JavaBean 属性相一致的元素。-->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<!--    <encoder 元素强制一个 class 属性去指定一个类的全限定名,用于实例化。
        如果 encoder 的 class 是 PatternLayoutEncoder,那么基于默认类映射,class 属性可以被隐藏。-->
        <encoder>
            <pattern>[%t] %level %d{yyyy-MM-dd'T'HH:mm:ss} %class.%method[%line] %msg%n</pattern>
        </encoder>
<!--        默认为System.out   System.out  / System.err-->
        <target>System.out</target>
    </appender>

<!--     通过 "bySecond" 将时间格式化成 "yyyyMMdd'T'HHmmss" 的形式插入到 logger 的上下文中,这个值对后续的配置也适用-->
    <property name="filename" value="${dir.logs}/demolog.log"/>

    <appender name="localFile" class="ch.qos.logback.core.FileAppender">
<!--        文件名-->
        <file>${filename}</file>
        <!--            只输出INFO以上的日志-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
<!--        是否追加,false覆盖,默认true-->
        <append>true</append>
<!--        将 immediateFlush 设置为 false 可以获得更高的日志吞吐量,默认方法更加的安全。 -->
        <immediateFlush>true</immediateFlush>

        <!--        encoder即该appender的输出格式配置-->
        <encoder>
            <pattern>%level %d{yyyy-MM-dd'T'HH:mm:ss} %class.%method[%line] %msg%n</pattern>
        </encoder>
    </appender>

    <appender name="warnRolling" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--        滚动规则-->
<!--        只输出WARN以上的日志-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>WARN</level>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${dir.logs}/%d{yyyy-MM-dd'T'HHmm}/rollingLog.%d{yyyy-MM-dd'T'HHmmss,aux}.log</fileNamePattern>
            <maxHistory>5</maxHistory>
            <totalSizeCap>1MB</totalSizeCap>
        </rollingPolicy>
<!--        encoder即该appender的输出格式配置-->
        <encoder>
            <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
        </encoder>
    </appender>

<!--    手动添加的logger 除name之外其余都是可选的 -->
    <logger name="default" level="debug" additivity="true">
        <appender-ref ref="console" />
        <appender-ref ref="localFile" />
    </logger>

<!--    最多只能有一个root元素存在-->
<!--    root的level和appender-ref是唯二可以配置的属性-->
    <root level="DEBUG">
<!--        root 与 输出目的地的映射-->
        <appender-ref ref="console" />
        <appender-ref ref="localFile" />
        <appender-ref ref="warnRolling"/>
    </root>

</configuration>

测试接口

package cn.kerninventory.demoslf4jlogback.web;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author Kern
 * @date 2020/3/26 15:36
 * @description TODO
 */
@RestController
@RequestMapping("/demo")
public class DemoController {

    private static Logger logger = LoggerFactory.getLogger(DemoController.class);

    @GetMapping("")
    public String toLogging() throws InterruptedException {
        logger.info("logging start!");

        for (int i = 0 ; i < 500; i++) {
            logger.info("PC {}", i);
            if ((i & 3) == 0) {
                logger.warn("i={},i & 3 == 0", i);
            }
            if ((i & 5) == 0) {
                logger.error("i={},i & 5 == 0", i);
            }
            Thread.currentThread().sleep(300);
        }
        logger.info("logging end!");

        return "Hello logback!";
    }
}

运行结果
可以看到rollingLog根据时间区间生成了多个文件夹和多个文件。然后这里的文件生成不完全根据你定义的时间,我定义的每一秒都不一样的文件,但是结果是没有的。其中应该有算法根据文件数量和时间区间进行控制,在这里插入图片描述
控制台,配置了DEBUG,所以几种级别的日志都有。
在这里插入图片描述

demolog.log, 用Filter过滤了INFO以下的日志消息。
在这里插入图片描述
rollingLog,用Filter过滤了WARN以下的日志消息。
在这里插入图片描述
本文就到这里了。算是比较系统的过了一遍logback,应对日常的开发足够了。有兴趣的小伙伴可以再深入研究一下。

参考资源: http://www.logback.cn/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值