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提供了
属性读取
如果想要读取application.properties文件中的配置,可以通过
../${serverName}/demo.log
...
自定义配置其实和spring mvc集成logback基本上没有区别,主要内容其实都是logback的知识了。鉴于之前的文章只讲了集成,没有介绍logback的知识,这里算是做一个补充。当然这里我们以实践所需为主,会屏蔽掉一些不那么重要的知识。
这大概是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外,剩下的两个都是需要通过配置文件配置的。
先来看一个最简单的配置:
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
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如出一辙。
当配置
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属性可以做到,例如:
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
更改配置后我们重新运行,然后可以看到日志仅仅打印了一行。
这个appender的累加效应有什么用呢?其实,这个MathController可以理解为某个重要的logger,我们需要将其定向到别的地方,例如日志文件中。这样运行的时候,除了console会打印一次外,日志文件也会打印一次,这才是正确的使用方式。如果觉得日志冗余了,可以加上刚才的additivity=false,让这部分重要的日志仅仅定向输出到日志文件中去。
之前说过,appender就是定义不同的输出目标。最简单的appender就是我们的consoleAppender,它表示将日志输出到控制台。另外一个最常用的appender就是我们的rollingFileAppender。rollingFileAppender继承了fileAppender,它最大的好处就是可以滚动记录日志,例如新的一天的日志按日期格式保存到新的文件中去。
rollingFileAppender最重要的两个组件就是滚动策略组件和触发策略组件。分别表示何时触发日志滚动,以及如何进行日志滚动。定义一个rollingFileAppender必须同时提供这两个策略,而我们接下来要介绍的timeBasedRollingPolicy同时实现这两个接口。
logFile.log
logFile.%d{yyyy-MM-dd}.log
30
3GB
%-4relative [%thread] %-5level %logger{35} - %msg%n
上面是一个标准的rollingFileAppender的定义,日志文件名称为logFile.log,可以带路径。滚动策略是基于时间的滚动策略,当滚动触发时,新的日志文件将会以
在上面的配置中,我们并没有看到layout的身影,而是一个
%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
我们将用户信息放入了MDC中,然后在logback配置里就可以使用了:
%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%.15thread] %logger{36}:%X{sysUser} - %.-4096msg%n
对于layout的配置,我们可以通过格式修饰符来美化格式。修饰符很简单就两个:点(.)和横杠(-)。
.:表示如果长度超了,会从开头进行截取。
-:表示反向对齐,也就是右对齐。
.和-可以进行组合。先来看 个例子:
%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%.15thread] %logger{36}:%X{sysUser} - %.-4096msg%n
%-5level表示长度为5,右对齐。%.15thread表示长度15,如果超了则从开头截取。%.-4096表示长度4096个字符,长度超了则从末尾截取。
logback提供if else的条件逻辑。在不同环境下,配置有区别,通过If..else可以分别定义好,而不用定义到单独的文件中去。例如:
...
...
...
condition中的条件表达式只能访问自己定义的context的property和system property。表达式中最常用的是isDefined()和property()两个方法。顾名思义,isDefined()检查某个属性是否定义了,property()则可以获取某个属性的值。例如:
...省略
....省略
已经讲了很多,基本覆盖了基本的知识点,如果想要更深入的了解logback,请参考官网文档:logback官网文档
最后再放一个生产环境常用的配置:
../log/${ServerName}/${AppName}.log
../log/${ServerName}/${AppName}.log.%d{yyyy-MM-dd}
7
%d{HH:mm:ss.SSS} %-5level [%.15thread][%X{traceId}] %logger{36} - %.-4096msg%n
%d{HH:mm:ss.SSS} %-5level [%.15thread][%X{traceId}] %logger{36} - %.-4096msg%n