springboot学习4使用日志:logback

时间:2023-03-09 20:39:24
springboot学习4使用日志:logback

springboot学习4使用日志:logback

一、基本知识说明

java中常用的几个日志级别

ERROR、WARN、INFO、DEBUG。 ERROR是这四个中级别最高的。

SpringBoot默认使用logback作为日志框架 ,所以引入起步依赖后就可以直接使用logback,不需要其他依赖。

SpringBoot会默认加载classpath:logback.xml或者classpath:logback-spring.xml 作为日志的配置文件,在springboot项目中可以直接把日志配置文件放在resources目录下。

简单使用时也可以不使用日志配置文件,将日志相关的配置直接放在application.yml中,如下

#日志设置
logging:
file: root.log
level:
com:
lyy:
dao: debug

其中file选项用来指定日志文件输出的位置,可以是相对路径,也可以是绝对路径。

level选项用来指定日志的级别,可以指定总的级别level: info,也可以像上边这样指定某个包中日志的输出级别。

二、代码示例

loback中支持使用slf4j来记录日志,所以可以使用如下的方式来记录日志

2.1 创建日志记录器

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

这里需要导入以下两个类,都是slf4j中的类

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

2.2 记录日志

使用日志记录器来记录日志

logger.info("com.lyy.service.impl.CategoryDataServiceImpl.findAll is run");

三、输出mybatis的sql到日志文件中

springboot整合mbatis后如何把sql语句输出到日志文件中,

因为mybatis输出sql的日志级别默认是debug,所以这里有两种实现方式:

(1) 把整个工程的日志级别都调整成debug,按一中的方法level: info,

(2) 指定dao接口所在的包的日志输出级别是debug

#日志设置
logging:
file: root.log
level:
com:
lyy:
dao: debug

按上面的方法配置后就可以把mybatis的sql输出到日志文件中

四、使用配置文件来配置logback

上面的示例是使用springboot的配置文件来对logback进行简单的配置就可以使用,这是因为springboot进行了一些自动配置。如果需要定制化的日志功能,就需要使用logback的配置文件来进行配置。

springboot工程中logaback配置文件的名称可以是logback.xml,直接放在resources目录下就可以使用。使用配置文件后就可以删掉yml配置文件中的日志配置。

以下是一个配置文件的内容示例

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false"> <!--格式化输出:%d表示日期,%thread表示线程名,%X表示获取MDC, %-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
<property name="pattern" value="%d{yyyy-MM-dd:HH:mm:ss} [%thread] [%X{MDC_VALUE}] %-5level [%logger.%M %line] %msg%n"/> <!--
Appender: 设置日志信息的去向,常用的有以下几个
ch.qos.logback.core.ConsoleAppender (控制台)
ch.qos.logback.core.rolling.RollingFileAppender (满足指定的策略时就新建一个文件来记录)
ch.qos.logback.core.FileAppender (文件)
-->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- 字符串System.out(默认)或者System.err -->
<target>System.out</target>
<!-- 对记录事件进行格式化 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}</pattern>
</encoder>
</appender> <appender name="allLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--滚动策略-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天轮转,规则就是根据时间表达式指定的文件名 -->
<fileNamePattern>root.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 保存 30 天的历史记录,最大大小为 30GB -->
<maxHistory>30</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
</rollingPolicy> <!-- 对记录事件进行格式化 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}</pattern>
</encoder>
</appender> <!--指定某个包的日志输出级别,这里是指定dao包的日志级别-->
<logger name="com.lyy.dao" level="debug">
<appender-ref ref="STDOUT"/>
</logger> <!--
和<logger>元素类似,但是它是根logger。默认debug
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
<root>可以包含零个或多个<appender-ref>元素,标识这个appender将会添加到这个logger。
-->
<root level="info">
<appender-ref ref="STDOUT"/>
<appender-ref ref="allLog"/>
</root> </configuration>

这个配置文件精简后由以下标签组成

<configuration>
定义一个变量,可以在当前配置文件中引用
<property></property>
日志记录器
<appender></appender>
指定某个包或者某个类的输出级别
<logger></logger>
指定根日志输出级别,没有特殊指定的包的日志输出全使用这个级别
<root></root>
</configuration>

这里使用的是带滚动策略的日志记录器,可以根据规则自动创建新的日志文件。

五、使用MDC来定位日志

5.1 什么是MDC

MDC是 log4j 和 logback 提供的一种方便在多线程条件下记录日志的功能,是一种轻量级的日志跟踪工具。

MDC应用在应用内的线程级别,不是分布式的应用层级别,所以仅靠它无法做到分布式应用调用链路跟踪的需求。它要解决的问题主要是可以在海量日志数据中快速捞到可用的日志信息。

5.2 实现原理

通过ThreadLocal来实现,每一个请求到来时都给当前线程的ThreadLocal中放入一个标识,然后输出日志时把这个标识一起输出,这样就可以在日志中快速筛选中一次请求中输出的日志。

5.3 具体使用

从线程中拿出标识并拼接到日志上这个过程日志框架已经帮我们处理了,只需要在日志框架的配置文件中定义日志格式时使用%X{MDC_KEY}拿出MDC_KEY对应的值

<property name="pattern" value="%d{yyyy-MM-dd:HH:mm:ss} [%thread] [%X{MDC_VALUE}] %-5level [%logger.%M %line]  %msg%n"/>

其中MDC_KEY是自定义的MDC键名称,日志框架根据它来取对应的值。

给ThreadLocal中放入这个值的过程需要我们自己完成,可以使用过滤器或者spring的aop来拦截请求,给请求的线程中放入这个值。

@Around("mdcValuePointcut()")
public Object mdcValueSet(ProceedingJoinPoint point) throws Throwable{
String mdcValue= UUID.randomUUID().toString();
System.out.println("mdcValueSet is run");
MDC.put("MDC_VALUE", mdcValue);
return point.proceed(point.getArgs());
}