spring-boot集成logback

        spring集成logback在之前的文章spring mvc集成logback日志功能已经介绍过。spring-boot作为单独的一个系列,集成日志稍微有些不同。幸运的是,spring-boot已经帮我们做了许多工作,集成日志功能比spring mvc要简单得许多。在不需要特殊定制的情况下,logback的配置足够简单就可以正常工作。如果想要满足一些特殊的需求的话,还是需要提供一个logback的配置文件。本文就从这两方面进行介绍。

基本配置

       如果使用的是starter的依赖,spring boot默认使用的就是logback来打印日志。

        logging.file

        默认情况下,日志是打印到console的,如果想打印到文件中,在application.properties添加logging.file参数,例如:

#日志文件地址
#logging.file=d:\\spring-boot-demo.log

      logging.file.max-history

      日志最大保存数(根据pattern计算),具体含义可以参考后面的Logback介绍。

     logging.pattern.console

   控制台下的日志格式,例如:

#日志格式
#logging.pattern.console=%d{yyyy/MM/dd-HH:mm:ss} [%thread] %-5level %logger- %msg%n

logging.pattern.file

日志文件中的格式,例如:

#logging.pattern.file=%d{yyyy/MM/dd-HH:mm} [%thread] %-5level %logger- %msg%n

日志级别定义

 spring boot日志级别定义非常方便,通过类似于包名的定义格式就可以指定相应Logger的日志打印级别,例如:

logging.level.root=WARN
logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate=ERROR

自定义配置

        要启用自定义配置,首先需要在applicaiton.properties文件中设置属性logging.config=classpath:logback-spring.xml。如下所示:

#==================== 启用自定义logback配置  ============================
logging.config=classpath:logback-spring.xml

       profile

       针对不同的环境,spring boot提供了<springProfile>标签来表示不同的配置,例如:

<springProfile name="!production">
	<!-- configuration to be enabled when the "production" profile is not active -->
</springProfile>

   属性读取

      如果想要读取application.properties文件中的配置,可以通过<springProperty>来读取,例如:

<springProperty scope="context" name="serverName" source="myapp.server.name"
		defaultValue="demo"/>
<appender name="rollingfile" class="ch.qos.logback.more.appenders.rollingFileAppender">
	<file>../${serverName}/demo.log</file>
	...
</appender>

Logback通用知识

       自定义配置其实和spring mvc集成logback基本上没有区别,主要内容其实都是logback的知识了。鉴于之前的文章只讲了集成,没有介绍logback的知识,这里算是做一个补充。当然这里我们以实践所需为主,会屏蔽掉一些不那么重要的知识。

Logger,Appender、Layout

       这大概是logback里面最基础的三个对象了。Looger是我们最常接触到的对象,打日志就是通过它来的,例如:

Logger logger = LoggerFactory.getLogger(MathController.class);
logger.info("这是一条info日志");

如果你使用的是lombok,那么看起来就是这个样子:

@Slf4j
public class MathController {
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public int add(int a, int b) {
        log.info("{}+{}={}", a, b, a + b);
        return a + b;
    }
    
}

        在上面代码中,通过@Slf4j注解,我们省去了获取logger的代码,可以直接使用log打印日志。
        打印日志有TRACE-->DEBUG-->INFO-->WRAN-->ERROR几个级别,越往后越高,并对应着Logger的几个方法。打印日志还可以进行参数化打印,{}为参数占位符。

       我们可以把Appender当作日志的输出对象,最常用的就是输出到console和日志文件当中去。一个Logger下面可以跟多个appender。如果没有配置appender话,spring-boot默认就是输出到console里面去的,如下图所示:

       上面的日志是按照一定格式来输出的,如何控制这个格式,靠的就是我们的layou对象了。通过配置,我们可以让日志按照一定的的格式打印出来,而且还可以添加一些其他的信息。上述三个对象中,除了Logger外,剩下的两个都是需要通过配置文件配置的。

       先来看一个最简单的配置:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!--输出到控制台-->
    <appender name="consoleOut" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!--root logger-->
    <root level="info">
        <appender-ref ref="consoleOut"/>
    </root>
</configuration>

      logger有继承关系,类似于我们的packge命名一样。root logger是所有logger的根logger,我们设置其日志级别为info级别。通过logger.info("这是一条info日志");打印出来的日志就是下面这个样子:

       root logger下面跟了一个名为consoleOut的appender,consoleOut是类ch.qos.logback.core.ConsoleAppender的实例,表示将日志输出到控制台。日志格式%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n,分别表示时间,线程,日志级别,logger类,日志内容。

        root logger日志级别设置成了info级别,由于有继承和优先级关系,这表示整个应用的最低级别至少都是Info级别,所以当你使用log.debug()的时候,日志是不会打出来的。

       到此我们心中已经有一个大致的基本概念了,接下来就是深入一点的东西了。所有的配置都是在这个最简单配置上进行改造。

设置配置文件默认地址

        设置配置文件默认地址,对于多工程的应用来说非常方便,这样所有的工程都使用同一份配置文件,不用再单独每个工程放一份。logback的配置文件,默认是class path下的logback.xml文件。在spring mvc中我们可以启动应用时,通过-Dlogback.configurationFile系统参数配置默认的配置文件地址。在spring boot中,我们通过-Dlogging.config配置默认配置文件的地址,这与application.properties中的logging.config如出一辙。

自动重载配置

       当配置<configruation scan="true">后,默认每隔一分钟便会扫描配置文件,如果有变动则重载整个配置。这样就不用重启应用了。

Logger配置

       logger配置比较简单,具体到包名或类名就可以了,例如:

 <!--logger-->
    <logger name="com.gameloft9.demo.Controllers.MathController" level="info">
        <appender-ref ref="consoleOut" />
    </logger>

     上述logger管理范围就是com.gameloft9.demo.Controllers.MathController下的日志,打印级别为Info级别。输出appender为consoleOut,也就是我们之前定义的输出到console环境。一般需要定义单独的日志级别或者输出到不同的地方时,才会用到单独的Logger,否则root logger已经满足大部分需求了。

       当我们把这段配置加上去后,会发现MathController下的日志会打两次。

   这是因为logger会将日志输出到所有的appender中去,包括logger的父辈logger中的appender。com.gameloft9.demo.Controllers.MathController、root这两个Logger都绑定了consoleOut这个appender,因此就会打印两遍。那么如何只打印一遍呢?通过设置Logger的additivity属性可以做到,例如:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!--输出到控制台-->
    <appender name="consoleOut" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!--logger-->
    <logger name="com.gameloft9.demo.Controllers.MathController" level="info" additivity="false">
        <appender-ref ref="consoleOut" />
    </logger>

    <!--root logger-->
    <root level="info">
        <appender-ref ref="consoleOut"/>
    </root>
</configuration>

       更改配置后我们重新运行,然后可以看到日志仅仅打印了一行。

       这个appender的累加效应有什么用呢?其实,这个MathController可以理解为某个重要的logger,我们需要将其定向到别的地方,例如日志文件中。这样运行的时候,除了console会打印一次外,日志文件也会打印一次,这才是正确的使用方式。如果觉得日志冗余了,可以加上刚才的additivity=false,让这部分重要的日志仅仅定向输出到日志文件中去。

Appender配置

      之前说过,appender就是定义不同的输出目标。最简单的appender就是我们的consoleAppender,它表示将日志输出到控制台。另外一个最常用的appender就是我们的rollingFileAppender。rollingFileAppender继承了fileAppender,它最大的好处就是可以滚动记录日志,例如新的一天的日志按日期格式保存到新的文件中去。

       rollingFileAppender最重要的两个组件就是滚动策略组件和触发策略组件。分别表示何时触发日志滚动,以及如何进行日志滚动。定义一个rollingFileAppender必须同时提供这两个策略,而我们接下来要介绍的timeBasedRollingPolicy同时实现这两个接口。

<configuration>
  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>logFile.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <!-- daily rollover -->
      <fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>

      <!-- keep 30 days' worth of history capped at 3GB total size -->
      <maxHistory>30</maxHistory>
      <totalSizeCap>3GB</totalSizeCap>

    </rollingPolicy>

    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender> 

  <root level="DEBUG">
    <appender-ref ref="FILE" />
  </root>
</configuration>

       上面是一个标准的rollingFileAppender的定义,日志文件名称为logFile.log,可以带路径。滚动策略是基于时间的滚动策略,当滚动触发时,新的日志文件将会以<fileNamePattern>定义的格式命名,例如logFile.2018-08-21.log。滚动触发时间也是根据这个格式来推算的,这里就是按天进行滚动。<maxHistory>指定日志最长存储时间(时间间隔根据格式进行推算),这里是30天。<totalSizeCap>指定所有日志最大存储容量。

LayOut配置

       在上面的配置中,我们并没有看到layout的身影,而是一个<encoder>参数。在Logback 0.9.19之后,用encoder对layout做了一层封装,使用encoder即可,底层的东西还是layout的配置。下面将会介绍PatternLayout的配置,因为它是最有用的。

       %logger{}

       用于打印logger的名称,后面可以跟长度,例如%logger{35}。对于超过长度的,会进行缩写,但包名至少会有一个字母,而不会出现直接省略掉某个包名的情况。效果如下图所示:

      %d{}

       用于打印日期,后面跟格式,例如:%d{HH:mm:ss.SSS}。格式是按照SimpleDateFormat的格式来的,大家应该很熟悉。如果没有指定格式的话,默认是IOS8601格式,例如:2006-10-20 14:06:49,812。

    %caller{}

     用于打印调用方,后面跟打印调用深度,类似于errorStackTrace,例如:%caller{2},效果如下图所示:

使用%caller的好处是可以快速定位到打日志的地方,坏处就是日志量会增加不少。

  %msg{}

   用于打印消息,后面跟长度。我们真正的日志内容就是通过%msg来打印的,例如:log.info("日志内容")。

 %n

  用于换行。

%level

 用于打印日志级别,如下图所示:

%thread

  用于打印触发日志的线程名称。如下图所示:

%X{}

       用于打印MDC里面的内容。例如我们将用户名userName,traceId等放进mdc里面,然后就可以通过%X{userName},%{traceId}来获取内容。例如:

private final static ThreadLocal<Object> tlUser = new ThreadLocal<Object>();

    /**user key*/
    public static final String KEY_USER = "sysUser";//

    public static void setUser(Object user) {
        tlUser.set(user);
        // 把需要打印日志的用户信息放到slf4j MDC
        MDC.put(KEY_USER, user.toString());
    }

   我们将用户信息放入了MDC中,然后在logback配置里就可以使用了:

<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
	<encoder>
		<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%.15thread] %logger{36}:%X{sysUser} - %.-4096msg%n</pattern>
	</encoder>
</appender>

格式修饰符

对于layout的配置,我们可以通过格式修饰符来美化格式。修饰符很简单就两个:点(.)和横杠(-)。

.:表示如果长度超了,会从开头进行截取。

-:表示反向对齐,也就是右对齐。

.和-可以进行组合。先来看 个例子:

<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
	<encoder>
		<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%.15thread] %logger{36}:%X{sysUser} - %.-4096msg%n</pattern>
	</encoder>
</appender>

      %-5level表示长度为5,右对齐。%.15thread表示长度15,如果超了则从开头截取。%.-4096表示长度4096个字符,长度超了则从末尾截取。

条件修饰

       logback提供if else的条件逻辑。在不同环境下,配置有区别,通过If..else可以分别定义好,而不用定义到单独的文件中去。例如:

<!-- if-then form -->
   <if condition="some conditional expression">
    <then>
      ...
    </then>
  </if>
  
  <!-- if-then-else form -->
  <if condition="some conditional expression">
    <then>
      ...
    </then>
    <else>
      ...
    </else>    
  </if>

    condition中的条件表达式只能访问自己定义的context的property和system property。表达式中最常用的是isDefined()和property()两个方法。顾名思义,isDefined()检查某个属性是否定义了,property()则可以获取某个属性的值。例如:

<!-- 如果定义了运行环境(比如tomcat启动时export到环境变量run_env),则启用下面的配置 -->
<if condition='isDefined("run_env")'>
	<then>
		<appender>
            ...省略
        </appender>
		<root level="INFO">
			<appender-ref ref="rollingFile" />
		</root>
	</then>

....省略

      已经讲了很多,基本覆盖了基本的知识点,如果想要更深入的了解logback,请参考官网文档:logback官网文档

      最后再放一个生产环境常用的配置:

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

	<property scope="context" name="AppName" value="${SERVER_NAME}" />
	<property scope="context" name="ServerName" value="${SERVER_NAME}" />

	<logger name="com.gameloft9.demo" level="INFO" />
	<logger name="com.alibaba.dubbo" level="ERROR" />
	<logger name="com.alibaba.dubbo.monitor" level="OFF" />

	<!-- Print log in console for local testing -->
	<if condition='isDefined("run_env")'>
		<then>
			<appender name="rollingFile"
				class="ch.qos.logback.core.rolling.RollingFileAppender">
				<file>../log/${ServerName}/${AppName}.log</file>
				<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
					<fileNamePattern>../log/${ServerName}/${AppName}.log.%d{yyyy-MM-dd}
					</fileNamePattern>
					<maxHistory>7</maxHistory>
				</rollingPolicy>
				<encoder>
					<pattern>%d{HH:mm:ss.SSS} %-5level [%.15thread][%X{traceId}] %logger{36} - %.-4096msg%n</pattern>
				</encoder>
			</appender>

			<root level="INFO">
				<appender-ref ref="rollingFile" />
			</root>
		</then>
		<else>
			<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
				<encoder>
					<pattern>%d{HH:mm:ss.SSS} %-5level [%.15thread][%X{traceId}] %logger{36} - %.-4096msg%n</pattern>
				</encoder>
			</appender>

			<root level="INFO">
				<appender-ref ref="console" />
			</root>
		</else>
	</if>
</configuration>

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值