前言:
日志的作用是什么?调试,问题定位,数据分析。日志很重要,要保证统一的样式,分级别,请求可追溯。
1. springboot 自带的logback
如果你是 ieda 开发工具,并且是maven工程,
可以点开 pom 文件,右键 -> maven -> Show Dependencies ,可以查看整个项目的依赖关系,其中有 logback
2.配置 logback.xml 文件
这个文件配置好放在 resources 目录下即可(不需要其他任何地方的配置),工程可自动识别,仔细阅读文件注解。
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--每个logger都关联到logger上下文,默认上下文名称为“default”,用于区分不同应用程序的记录。一旦设置,不能修改 -->
<contextName>${APP_NAME}</contextName>
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="./logs" />
<property name="APP_NAME" value="log"/>
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{requestId}] %-5level %logger{50} - %msg%n"/>
<!-- 控制台输出 -->
<appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>
<appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/${APP_NAME}.info.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
<!-- totalSizeCap:该类文件最大空间,超过后会删除而不会管是否在保存时间内 -->
<totalSizeCap>30MB</totalSizeCap>
<!-- 是否启动时清理过期日志,默认false -->
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>
<appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<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.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/${APP_NAME}.error.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>10</MaxHistory>
<!-- totalSizeCap:该类文件最大空间,超过后会删除而不会管是否在保存时间内 -->
<totalSizeCap>8MB</totalSizeCap>
<!-- 是否启动时清理过期日志,默认false -->
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>
<appender name="fileWarnLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/${APP_NAME}.warn.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>10</MaxHistory>
<!-- totalSizeCap:该类文件最大空间,超过后会删除而不会管是否在保存时间内 -->
<totalSizeCap>8MB</totalSizeCap>
<!-- 是否启动时清理过期日志,默认false -->
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>
<appender name="fileDebugLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/${APP_NAME}.debug.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>10</MaxHistory>
<totalSizeCap>1MB</totalSizeCap>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>
<!-- 日志输出级别 -->
<root level="INFO">
<appender-ref ref="consoleLog" />
<appender-ref ref="fileErrorLog" />
<appender-ref ref="fileInfoLog"/>
<appender-ref ref="fileWarnLog" />
<appender-ref ref="fileDebugLog" />
</root>
</configuration>
3.写个controller 测试一下
日志记录用的是 lombok 里面的小插件,也可以使用其他的。
@RestController
@Slf4j
public class LogController {
@GetMapping("/search")
public Object getInfo(
@RequestParam(value = "keyword", required = false) String keyword) {
String error = "这是error级别log";
log.error("this is error log,{}", error);
String warn = "这是warn级别log";
log.warn("this is warn log,{}", warn);
String info = "这是info级别log";
log.info("this is info log,{}", info);
Map<String, String> response = new HashMap<>();
response.put("requestId", RequestIdUtil.getRequestId()); // 这块下面讲
response.put("body", "body");
return response;
}
}
在服务器上运行以后可以发现在当前目录下生成 log 文件夹,里面有4个级别的log文件,如下
4.增加请求可追溯功能
在步骤 2 和 3 里面都有一个关键词 requestId,它的作用是给每次请求加一个唯一标识,这样请求在系统流转就会带着这个唯一id打印日志,定位问题和分析很有用。
- 主流方式是MDC,有兴趣的可以查一下,这里直接贴代码
- 先写一个类用于操作MDC
import org.slf4j.MDC;
import java.util.UUID;
public class RequestIdUtil {
public static final String REQUEST_ID = "requestId";
public static void setRequestId() {
MDC.put(REQUEST_ID, UUID.randomUUID().toString());
}
public static String getRequestId() {
return MDC.get(REQUEST_ID);
}
public static void clear() {
MDC.clear();
}
}
- 再写一个过滤器,用于记录每次请求
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class RequestIdFilter implements Filter {
private static final String REQUEST_ID_HEADER = "RequestId";
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
RequestIdUtil.setRequestId(); // 这行是核心
HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
String requestId = RequestIdUtil.getRequestId();
httpResponse.setHeader(REQUEST_ID_HEADER, requestId); // 把请求id写到响应头里面
try {
filterChain.doFilter(servletRequest, servletResponse);
} finally {
RequestIdUtil.clear();
}
}
}
- 测试
看一下步骤 3 的返回结果
{"requestId":"651a0b9b-1691-4fb2-a95f-e37275ee19e9","body":"body"}
查看一下日志内容:
2020-09-14 20:06:39.997 [http-nio-8088-exec-1] [651a0b9b-1691-4fb2-a95f-e37275ee19e9] INFO log.test.controller.LogController - this is info log,这是info级别log
5 参考文档
花了 20 分钟写的代码,比较粗糙,想了解更多的可以参考下面文档
版权声明:本文为qingquanyingyue原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。