背景
我一直对于自己做的学习项目中的日志输出不是很满意,想着对日志进行一个优化。
优化方向
1、将SQL日志单独提出来打印
2、加入traceId跟踪请求的走向,快速定位bug
MDC介绍
Logback的MDC(Mapped Diagnostic Context)提供了一种在多线程环境中跟踪特定信息的方法。 MDC用于在日志中存储上下文信息,并使该信息可用于整个请求处理的所有阶段,从而更好地诊断和调试问题。MDC使用一个映射表(类似于Java中的Map)来存储键值对,这些键值对可以是任何类型的数据,例如请求ID、用户ID、IP地址等。
当一个线程启动时,它可以将一个或多个键值对存储在MDC中。然后,在同一线程上运行的任何代码都可以轻松地访问这些键值对。例如,当处理Web请求时,可以将请求ID存储在MDC中,并在处理请求的每个阶段将其添加到日志记录中。这样,在日志中查看请求的整个处理过程时,可以很容易地跟踪请求ID。
在Logback中,可以使用MDC.put(key, value)方法向MDC添加键值对,使用MDC.get(key)方法获取键值对,使用MDC.remove(key)方法删除键值对。MDC的典型用法是在应用程序的入口点设置一些上下文信息,如请求ID、用户ID等,然后在应用程序中的任何地方记录这些信息。
话不多说,上代码
SQL日志单独打印
这个就是改一下logback.xml就行了
可以根据实际情况对于文件大小和保留天数进行修正
<appender name="SQL-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/sql.log</file>
<encoder>
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId}] %-5level %logger{50} -%msg%n</Pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${LOG_PATH}/sql/sql-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>150MB</maxFileSize>
<!--日志文件保留天数-->
<maxHistory>20</maxHistory>
</rollingPolicy>
</appender>
指定mybatis和mapper下的包打印到SQL-OUT
<logger name="org.mybatis" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="STDOUT"/>
<appender-ref ref="SQL-OUT"/>
</logger>
<logger name="com.shuizhao.easydatahub.mapper" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="STDOUT"/>
<appender-ref ref="SQL-OUT"/>
</logger>
加入traceId
使用过滤器在MDC中放入自定义变量traceId即可
也可以放入请求的IP地址,登陆认证后的用户Id等
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import java.io.IOException;
import java.util.UUID;
/**
* @author shuizhao
*/
@Component
public class TraceIdFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 生成一个 traceId
String traceId = (String) request.getAttribute("traceId");
if (StringUtils.isBlank(traceId)) {
traceId = UUID.randomUUID().toString();
request.setAttribute("traceId", traceId);
}
// 设置到 MDC 中
MDC.put("traceId", traceId);
try {
// 继续处理请求
chain.doFilter(request, response);
} finally {
// 清空 MDC
MDC.clear();
}
}
}
放入之后直接在logback.xml中使用%X{traceId}来调用即可
<encoder>
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId}] %-5level %logger{50} -%msg%n</Pattern>
<charset>UTF-8</charset>
</encoder>
完整的logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds">
<property name="LOG_PATH" value="./logs"/>
<appender name="INFO-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/tiny.log</file>
<encoder>
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId}] %-5level %logger{50} -%msg%n</Pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${LOG_PATH}/tiny/tiny-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>150MB</maxFileSize>
<!--日志文件保留天数-->
<maxHistory>20</maxHistory>
</rollingPolicy>
</appender>
<appender name="ERROR-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/error.log</file>
<encoder>
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId}] %-5level %logger{50} -%msg%n</Pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 只打印错误日志 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<!--日志文件保留天数-->
<maxHistory>20</maxHistory>
</rollingPolicy>
</appender>
<appender name="SQL-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/sql.log</file>
<encoder>
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId}] %-5level %logger{50} -%msg%n</Pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${LOG_PATH}/sql/sql-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>150MB</maxFileSize>
<!--日志文件保留天数-->
<maxHistory>20</maxHistory>
</rollingPolicy>
</appender>
<!-- 彩色日志 -->
<!-- 彩色日志依赖的渲染类 -->
<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{HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr([%X{traceId}]){magenta} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<!--输出到控制台-->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoder defaults to ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
</appender>
<!--日志打印的包的范围,及分类日志文件存储 -->
<logger name="com.shuizhao.easydatahub" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="STDOUT"/>
<appender-ref ref="INFO-OUT"/>
<appender-ref ref="ERROR-OUT"/>
</logger>
<logger name="org.mybatis" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="STDOUT"/>
<appender-ref ref="SQL-OUT"/>
</logger>
<logger name="com.shuizhao.easydatahub.mapper" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="STDOUT"/>
<appender-ref ref="SQL-OUT"/>
</logger>
<root level="INFO">
<appender-ref ref="STDOUT"/>
<appender-ref ref="INFO-OUT"/>
<appender-ref ref="ERROR-OUT"/>
</root>
</configuration>
效果
cat tiny.log | grep ‘61f03cb1-8bb6-43e9-bc27-a0e705f9b3b4’
cat sql.log | grep ‘61f03cb1-8bb6-43e9-bc27-a0e705f9b3b4’