logback简介

logback主要由三个模块构成:logback-core,logback-classic及logback-access。

logback

logback-core为基础核心,另外两个均依赖它。其中logback-classic实现了简单日志门面SLF4J;logback-access主要作为一个与Servlet容器交互的模块,提供与HTTP访问相关的一些功能。

通常使用时直接引入logback-classic的依赖,便可自动引入logback-core,当然为保险起见也可以显式的引入两者。

SpringBoot对logback的支持

上面已经提到SpringBoot默认集成了logback,因此无需专门引入便可进行直接使用。

在SpringBoot的web项目中logback的依赖关系如下:
logback

我们可以看到一旦引入spring-boot-starter-web依赖,对应的不仅引入了logback框架,还同时引入了slf4j相关框架。所以,项目中直接使用即可。

slf4j的优势
使用slf4j的而不是直接使用 log4j, commons logging, logback 或者 java.util.logging,因为这样可以让你的程序适具有更多的扩展性。

  1. 在你的开源或内部类库中使用slf4j会使得它独立于任何一个特定的日志实现,这意味着不需要管理多个日志配置或者多个日志类库,以后别人调用你的工具包时也可以不用关心日志组件问题。
  2. slf4j提供了基于占位符的日志方法,减少了在String拼接时的性能开销问题。并且,通过使用slf4j的日志方法,你可以延迟构建日志信息(srting)的开销,意味着程序可以有更高的吞吐性能。

SpringBoot中logback的集成
首先创建一个SpringBoot项目,核心依赖文件便是spring-boot-starter-web。

org.springframework.boot
spring-boot-starter-web

这样其实就算集成完成了,我们可以在其中进行一些简单的logback使用了。

@RestController
public class HelloWorldController {

private static final Logger log = LoggerFactory.getLogger(HelloWorldController.class);

@RequestMapping("/hello")
public void hello() {
	log.debug("Hello world 测试debug日志");
	log.info("Hello world 测试info日志");
	log.warn("Hello world 测试warn日志");
	log.error("Hello world 测试error日志");
}

}
上面代码中分别使用debug,info,warn,error方法输出日志。日志的所有配置,都是基于SpringBoot集成logback时的默认配置来的。

此时如果访问对应的url,便可打印出对应日志。
为什么只打印了三行?因为SpringBoot默认日志输出级别为info级别。在application.properties文件中添加如下配置便可打印出debug级别的日志。
logging.level.com.secbro2=debug
其中com.secbro2为项目的基础package路径

SpringBoot对logback的基础配置
SpringBoot对logback内置了一些默认配置,这与 SpringBoot集成其他架构异曲同工。默认情况下SpringBoot将日志输出到控制台,不会写到日志文件。如果需要输出到日志文件,需要我们在application.properties中设置logging.file或logging.path属性。

注:二者不能同时使用。否则只有logging.file生效
logging.file=文件名
logging.path=日志文件路径

logging.level.包名=指定包下的日志级别
logging.pattern.console=日志打印规则
logging.file设置日志文件,可以是绝对路径或者相对路径。
logging.path设置日志目录,会在指定目录下创建sping.log文件,并写入日志内容。
二者不能同时使用,否则只有logging.file生效。

在application.properties中支持的配置有些简单,如果需要配置复杂的日志内容,则需要基于xml配置文件来进行操作。

自定义logback配置
在application .properties中配置日志,通常在小型系统或对日志没有严格要求的系统中使用。如果运用在生产环境,通常建议通过基于xml文件来对logback进行自定义配置。
在SpringBoot中,默认支持四种命名的日志配置文件。
logback
也就是说如果在src/main/resources目录下放置其中任一类型的配置文件,SpringBoot便会自动进行使用。
而Spring Boot官方推荐优先使用带有-spring的文件名配置(如有logback-spring.xml,则不会使用logback.xml)。
若需要对配置文件名进行修改,或者希望把放到其它目录下,可以在application中通过logging.config属性来指定,如logging.config=classpath:config/my-log-config.xml。

logback-spring.xml详解

logback的xml配置文件,核心部分有三个元素:appender、logger、root。
下面是配置文件的主体模块:
logback

configuration元素
logback.xml配置文件的基本结构可以描述为configuration元素,包含零个或多个appender元素,后跟零个或多个logger元素,后跟最多一个root元素(也可以没有)。

根元素configuration有三个属性:

debug:默认为false,若设置为true,则打印出logback内部日志信息。
scan:默认值为true,若设置为true,配置文件如果发生改变,将会被重新加载。
scanPeriod:与scan配合使用,当scan为true时,此属性生效,默认的时间间隔为1分钟,设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。如可以设置为scanPeriod="30 seconds"每30秒检测一次。

定义上下文名称
contextName元素,每一个日志组件(logger)都会关联到日志上下文,默认上下文名称是‘default’,用于标识应用,假如多个应用输出到同一个地方,就有必要使用%contextName来区别。

上下文的配置直接在configuration下

HelloWorld-log 经过定义zhi'hou,在其他property或者appender中便可以通过%contextName来获取和使用该上下文了。

定义变量
通过property元素可以定义变量。它有name和value两个属性。变量可以使用${name}来使用。这个的作用类似于代码中的常量字符串,定义之后公共地方可以就可以统一使用。如日志文件前缀、日志路径、日志输出格式等。

如果是在spring或者springboot项目中,想让property的value值通过配置文件获取,可以使用springProperty来定义

appender组件
appender 组件用来定义日志的输出格式,日志如何过滤以及日志文件的处理。appender的结构如下:
logback

appender的属性有name和class。
name指定appender名称,后面使用该appender也是通过名称来指定。
class属性指定要实例化的appender类的完全限定名称。
appender类默认有一下几种:

ConsoleAppender:日志输出到控制台,类名ch.qos.logback.core.ConsoleAppender。FileAppender:日志输入到文件,类名ch.qos.logback.core.FileAppender。RollingFileAppender:滚动记录文件,FileAppender的子类,当符合条件(大小、时间),日志进行切分处理。类名:ch.qos.logback.core.rolling.RollingFileAppender。

appender元素可以包含一个或者多个layout元素,零个或者多个encoder元素以及多个filter元素。

ConsoleAppender
ConsoleAppender,就是在控制台上输出。示例:

%-4relative [%thread] %-5level %logger{35} - %msg %n

FileAppender
FileAppender,作用是将日志输出到文件。目标文件可以指定,如果该文件已经存在,它将根据附加属性的值被追加或截断。示例:

log-${bySecond}.txt %logger{35} - %msg%n

RollingFileAppender
RollingFileAppender是FileAppender的子类,扩展了FileAppender,具有翻转日志文件的功能。
例如,RollingFileAppender可以记录到名为log.txt文件的文件,并且一旦满足某个条件,就将其日志记录目标更改为另一个文件。
有两个与RollingFileAppender交互的重要子组件。 第一个RollingFileAppender子组件,即 RollingPolicy 负责执行翻转所需的操作。 RollingFileAppender的第二个子组件,即 TriggeringPolicy 将确定是否以及何时发生翻转。 因此,RollingPolicy 负责什么和TriggeringPolicy 负责什么时候。
作为任何用途,RollingFileAppender 必须同时设置 RollingPolicy 和 TriggeringPolicy。 但是,如果其 RollingPolicy 也实现了TriggeringPolicy 接口,则只需要显式指定前者。
RollingFileAppender通常包括File、filter,rollingPolicy,encoder和layout元素。
encoder用来指定日志的输出格式及编码等:

${FILE_LOG_PATTERN} UTF-8

RollingPolicy
rollingPolicy用于配置滚动策略,支持TimeBasedRollingPolicy、SizeAndTimeBasedRollingPolicy、FixedWindowRollingPolicy、SizeBasedTriggeringPolicy

TimeBasedRollingPolicy
时间基准滚动策略可能是最流行的滚动策略。它定义了一个基于时间的滚动策略,例如每日或每月。时间的滚动策略承担了翻转的责任,同时也承担了触发的滚动。TimeBasedTriggeringPolicy实现了RollingPolicy和TriggeringPolicy接口。
${log.path}/debug.%d{yyyy-MM-dd}.log 30
fileNamePattern指定日志的路径及名称,此处是按日期输出,即%d{yyyy-MM-dd}格式。maxHistory表示日志最多保留天数,存活超过30天的日志会被删除。

SizeAndTimeBasedRollingPolicy
有时候可能希望按日期对文件进行存档,但同时限制每人日志文件的大小,这时候可以使用SizeAndTimeBasedRollingPolicy达到目的。

mylog.txt mylog-%d{yyyy-MM-dd}.%i.txt 100MB 60 20GB %msg%n

encoder
编码器负责将事件转换成字节数组,并将字节数组写入OutputStream。

filter
有时候,我们需要在特定的appender中只输出特定级别的日志,此时就需要用到filter。过滤器有很多种,这里只介绍LevelFilter和ThresholdFilter

LevelFilter根据精确的级别匹配过滤事件。如果事件的级别等于配置的级别,则根据onMatch和on属性的配置,过滤器接受或拒绝事件。示例:

INFO ACCEPT DENY %-4relative [%thread] %-5level %logger{30} - %msg%n LevelFilter 通常使用LevelFilter来过滤日志级别 DEBUG DENY ACCEPT

其中level指定日志级别,onMath指定符合过滤条件的操作接收(ACCEPT),onMismatch指定不符合条件的拒绝(DENY)。

如果需要将不同级别的日志输出到不同的日志文件,那么就需要配置多个filter,每个filter像上面一样指定level级别:DEBUG,INFO,WARN和ERROR。

通常情况下,日志输出会配置三个,一个控制台输出用于开发阶段;一个INFO及以上级别的日志输出,可追踪相应的生产日志;一个单独ERROR级别的日志输出,方便快速检查出异常日志。

ThresholdFilter
阈值筛选器将事件过滤到指定的阈值之下。对于级别相等或超过阈值的事件,当调用其decide()方法时,阈值筛选器将保持中立。但是,低于阈值的事件将被拒绝。示例:

INFO %-4relative [%thread] %-5level %logger{30} - %msg%n

logger配置
logger用来设置某一个类或者某个包的日志输出级别、以及关联的Appender
logger包含三个属性:
name:要输出日志的包名或者类名,比如com.chai,必须选
level,设置日志级别,允许一个不区分大小写的字符串值TRACE,DEBUG,INFO,WARN,ERROR,ALL或OFF。如果未设置,则logger会向上继承最近一个非空级别。可选项。
additivity:是否将日志向上级传递,默认为true,可选项。

logger通过一个或多个子节点appender-ref来控制日志的输出。

上面的示例表示org.springframework包下的日志以warn级别输出,com包下的日志以debug级别输出。

上面的示例对指定appender进行日志控制,由于设置了info级别,additivity为true,而且关联CONSOLE的appender,因此info以上级别的日志会输出到控制台。
同时会把日志上传到父级,即root。若root也有配置CONSOLE的输出的话,会在控制台输出两次。additivity为false,则不会。

root
root元素配置根记录器。它是一个特殊的logger,是所有logger的根节点,只有一个属性level,默认为DEBUG 。

level属性的值可以是不区分大小写的字符串TRACE,DEBUG,INFO,WARN,ERROR,ALL或OFF之一。root元素可以包含零个或多个appender-ref元素;被引用的每个appender都被添加到根记录器中。

如果是基于SpringBoot项目,针对不同环境(profile)有不同的日志输出,比如开发(dev)环境只输出CONSOLE的,生产环境(prod)只输入info和error,那则可用到Spring支持的profile机制。对应的元素为springProfile。

profile的值与springboot中配置文件的spring.profiles.active值进行对照。

输出logback状态数据
某些时候为了了解logback配置文件加载情况,配置中对应的appender、logger的装载情况等,我们需要启用logback状态数据的输出。这也是logback官网强烈推荐的,可以帮助我们排除诊断一些问题。

启用状态数据输出有两种方式:
在根元素(configuration) 中设置属性debug=“true”。
添加元素(statusListener),class使用OnConsoleStatusListener。如下:

两种方式选其一即可。第一种方式的debug与配置文件中的日志级别没有关系,只用于表示输出状态数据。

异步输出日志
前面提到的appender,日志输出到文件是同步输出的,即每次输出都会直接写IO到磁盘文件。对于高并发的应用,会产生阻塞,造成不必要的性能损耗。

logback提供了日志异步输出的AsyncAppender。处理方式也很简单,添加一个基于异步写日志的appender,并指向原配置的appender即可:

0 1024 true// INFO结构同上

AsyncAppender的是通过阻塞队列来避免日志直接输出到文件,先把日志事件输出到阻塞队列中,然后启动一个新的worker线程,主线程不阻塞,worker线程从队列中获取需要写的日志,异步输出到对应的位置。

代码中的日志格式
在日常使用日志时,可以通过最开始的示例定义Logger对象,然后调用其对应级别的日志输出。当然,如果采用Lombok的情况下,可直接类上使用@Slf4j注解来自动注入log属性,不用再声明:

private static final Logger log = LoggerFactory.getLogger(HelloWorldController.class);
就可以替换为:
@Slf4j
@RestController
public class HelloWorldController {
}

而在日志输出格式也有多种,其中最不可取的形式是如下模式的日志输出:
Object entry = new SomeObject(); logger.debug("The entry is " + entry);

这种模式会导致即使采用info基本输出,debug中的对象toString和字符串拼装依旧会处理。建议采用如下模式输出:
Object entry = new SomeObject(); logger.debug(“The entry is {}.”, entry);
此时,如果日志输出级别为info,则不会处理对象的toString和字符串的拼接。
logback作者进行测试得出:第一种和第二种写法输出结果相同。但在禁用日志记录语句的情况下,第二种将比第一种写法优于至少30倍。

综合样例:

<?xml version="1.0" encoding="UTF-8"?> logback-spring
<!--0. 日志格式和颜色渲染 -->
<!-- 彩色日志依赖的渲染类 -->
<conversionRule conversionWord="clr"
                converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
<conversionRule conversionWord="wex"
                converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
<conversionRule conversionWord="wEx"
                converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
<!-- 彩色日志格式 -->
<property name="CONSOLE_LOG_PATTERN"
          value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>

<!--1. 输出到控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        <level>debug</level>
    </filter>

    <!--日志文档输出格式-->
    <encoder>
        <!--指定日志格式-->
        <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
        <!--设置字符集-->
        <charset>UTF-8</charset>
    </encoder>
</appender>

<!--输出到文档-->
<!-- 时间滚动输出 level为 DEBUG 日志 -->
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <!-- 正在记录的日志文件的路径及文件名~~~~~file设置打印的文件的路径及文件名,建议绝对路径-->
    <file>${logging.path}/web_debug.log</file>

    <!--日志文档输出格式-->
    <encoder>
        <!--指定日志格式-->
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        <!-- 设置字符集 -->
        <charset>UTF-8</charset>
    </encoder>

    <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
    <!--
        日志记录器的滚动策略
        SizeAndTimeBasedRollingPolicy 按日期,大小记录日志
        另外一种方式:
            rollingPolicy的class设置为ch.qos.logback.core.rolling.TimeBasedRollingPolicy

    -->
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <!-- 日志归档 -->
        <!--
            归档的日志文件的路径,例如今天是2018-08-23日志,当前写的日志文件路径为file节点指定,
            可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。
            而2018-08-23的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引
         -->
        <fileNamePattern>${logging.path}/web-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>

        <!--
           配置日志文件不能超过100M,若超过100M,日志文件会以索引0开始,命名日志文件
           例如error.20180823.0.txt
           -->
        <timeBasedFileNamingAndTriggeringPolicy
                class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>100MB</maxFileSize>
        </timeBasedFileNamingAndTriggeringPolicy>

        <!--日志文档保留天数-->
        <maxHistory>15</maxHistory>
    </rollingPolicy>

    <!-- 此日志文档只记录debug级别的 -->
    <!-- 过滤策略:
        LevelFilter : 只打印level标签设置的日志级别
        ThresholdFilter:打印大于等于level标签设置的级别,小的舍弃
     -->
    <!--<filter class="ch.qos.logback.classic.filter.ThresholdFilter">-->
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
        <!-- 过滤的日志级别 -->
        <level>debug</level>
        <!--匹配到就允许-->
        <onMatch>ACCEPT</onMatch>
        <!--没有匹配到就禁止-->
        <onMismatch>DENY</onMismatch>
    </filter>
</appender>


<!-- 2.2 level为 INFO 日志,时间滚动输出  -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <!-- 正在记录的日志文档的路径及文档名 -->
    <file>${logging.path}/web_info.log</file>
    <!--日志文档输出格式-->
    <encoder>
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        <charset>UTF-8</charset>
    </encoder>
    <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <!-- 每天日志归档路径以及格式 -->
        <fileNamePattern>${logging.path}/web-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
        <timeBasedFileNamingAndTriggeringPolicy
                class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>100MB</maxFileSize>
        </timeBasedFileNamingAndTriggeringPolicy>
        <!--日志文档保留天数-->
        <maxHistory>15</maxHistory>
    </rollingPolicy>
    <!-- 此日志文档只记录info级别的 -->
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
        <level>info</level>
        <onMatch>ACCEPT</onMatch>
        <onMismatch>DENY</onMismatch>
    </filter>
</appender>

<!-- 2.3 level为 WARN 日志,时间滚动输出  -->
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <!-- 正在记录的日志文档的路径及文档名 -->
    <file>${logging.path}/web_warn.log</file>
    <!--日志文档输出格式-->
    <encoder>
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        <charset>UTF-8</charset> <!-- 此处设置字符集 -->
    </encoder>
    <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <fileNamePattern>${logging.path}/web-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
        <timeBasedFileNamingAndTriggeringPolicy
                class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>100MB</maxFileSize>
        </timeBasedFileNamingAndTriggeringPolicy>
        <!--日志文档保留天数-->
        <maxHistory>15</maxHistory>
    </rollingPolicy>
    <!-- 此日志文档只记录warn级别的 -->
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
        <level>warn</level>
        <onMatch>ACCEPT</onMatch>
        <onMismatch>DENY</onMismatch>
    </filter>
</appender>

<!-- 2.4 level为 ERROR 日志,时间滚动输出  -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <!-- 正在记录的日志文档的路径及文档名 -->
    <file>${logging.path}/web_error.log</file>
    <!--日志文档输出格式-->
    <encoder>
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        <charset>UTF-8</charset> <!-- 此处设置字符集 -->
    </encoder>
    <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <fileNamePattern>${logging.path}/web-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
        <timeBasedFileNamingAndTriggeringPolicy
                class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>100MB</maxFileSize>
        </timeBasedFileNamingAndTriggeringPolicy>
        <!--日志文档保留天数-->
        <maxHistory>15</maxHistory>
    </rollingPolicy>
    <!-- 此日志文档只记录ERROR级别的 -->
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
        <level>ERROR</level>
        <onMatch>ACCEPT</onMatch>
        <onMismatch>DENY</onMismatch>
    </filter>
</appender>





<!--
  <logger>用来设置某一个包或者具体的某一个类的日志打印级别、
  以及指定<appender>。<logger>仅有一个name属性,
  一个可选的level和一个可选的addtivity属性。
  name:用来指定受此logger约束的某一个包或者具体的某一个类。
  level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
        还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。
        如果未设置此属性,那么当前logger将会继承上级的级别。
  addtivity:是否向上级logger传递打印信息。默认是true。
  <logger name="org.springframework.web" level="info"/>
  <logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>

–>

<!--
    使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
    第一种把<root level="info">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
    第二种就是单独给dao下目录配置debug模式,代码如下,这样配置sql语句会打印,其他还是正常info级别:
    【logging.level.org.mybatis=debug logging.level.dao=debug】
 -->

<!--
    root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
    level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
    不能设置为INHERITED或者同义词NULL。默认是DEBUG
    可以包含零个或多个元素,标识这个appender将会添加到这个logger。
-->



<!-- 4. 最终的策略 -->
<!-- 4.1 开发环境:打印控制台-->
<!-- <springProfile name="dev">
     <logger name="com.cic.analysis.business.dao" level="debug"/>&lt;!&ndash; 修改此处扫描包名 &ndash;&gt;
 </springProfile>-->

<!--
    root指定最基础的日志输出级别,level属性指定
    appender-ref标识的appender将会添加到这个logger
-->
<root level="info">
    <appender-ref ref="CONSOLE"/>
    <appender-ref ref="DEBUG_FILE"/>
    <appender-ref ref="INFO_FILE"/>
    <appender-ref ref="WARN_FILE"/>
    <appender-ref ref="ERROR_FILE"/>
</root>

<!-- 4.2 生产环境:输出到文档
<springProfile name="pro">
    <root level="info">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="DEBUG_FILE" />
        <appender-ref ref="INFO_FILE" />
        <appender-ref ref="ERROR_FILE" />
        <appender-ref ref="WARN_FILE" />
    </root>
</springProfile> -->
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐