缺点
优点
继承CommonsRequestLoggingFilter过滤器,实现部分自己的逻辑
package com.yp.basic.log.filter;import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.yp.store.base.biz.common.constant.CommonConstant;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.web.filter.CommonsRequestLoggingFilter;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;/*** 自定义的请求日志打印过滤器,打印所有接口请求参数、耗时等日志
** 对比其他两种方式:
* * - 1、aop的方式:必须要到controller层,才会打印, 有些接口在 过滤器、拦截器层被拦截
* - 2、拦截器的方式:request.getInputStream()只能调用一次,解决的方法为copy一份流,个人感觉在代码逻辑层面不太清晰
*
** 缺点:
* * - 1、无法获取返回值,适合一些不关心返回值的场景。
* - 2. 内部使用的是ContentCachingRequestWrapper读取的request.getInputStream(),必须要先调用@RequstBody,才能取到值。
*
** 优点:
* * - 1、 实现简单,代码层次逻辑清晰。
*
** @author: wcong* @date: 2022/11/25 15:17*/
@Slf4j
public class RequestLogPrintFilter extends CommonsRequestLoggingFilter {/*** 接口日志 开始 请求前缀,建议放在公共的工具类中*/public final static String BEFORE_REQUEST_PREFIX = "### Before request[";/*** 接口 结束 请求前缀,建议放在公共的工具类中*/public final static String AFTER_REQUEST_PREFIX = "### After request[";/*** 重写父类方法:封装打印消息的格式*/@Overrideprotected String createMessage(HttpServletRequest request, String prefix, String suffix) {final StringBuilder messageInfo = getMessageInfo(request, prefix, suffix);// 请求开始还是结束if (BEFORE_REQUEST_PREFIX.equals(prefix)) {// 请求开始MDC.put("logStartTime", String.valueOf(System.currentTimeMillis()));} else {// 请求结束,记录耗时final Long logStartTime = Convert.toLong(MDC.get("logStartTime"), 0L);messageInfo.append("\r\n接口耗时:").append(System.currentTimeMillis() - logStartTime).append("ms");}return messageInfo.toString();}/*** 重写父类方法:请求前调用逻辑*/@Overrideprotected void beforeRequest(HttpServletRequest request, String message) {doPrintLog(message);}/*** 重写父类方法:请求后调用逻辑*/@Overrideprotected void afterRequest(HttpServletRequest request, String message) {doPrintLog(message);}/*** 重写父类方法:是否打印日志*/@Overrideprotected boolean shouldLog(HttpServletRequest request) {// 父类中的逻辑是:logger.isDebugEnabled()return true;}/*** 统一封装打印的日志格式** @param request javax.servlet.http.HttpServletRequest* @param prefix 打印前缀* @param suffix 打印后缀* @return 封装好的日志格式*/private StringBuilder getMessageInfo(HttpServletRequest request, String prefix, String suffix) {StringBuilder msg = new StringBuilder();msg.append(prefix);msg.append(StrUtil.format("method={}; ", request.getMethod().toLowerCase()));msg.append("uri=").append(request.getRequestURI());if (isIncludeClientInfo()) {String client = request.getRemoteAddr();if (StrUtil.isNotBlank(client)) {msg.append("; client=").append(client);}HttpSession session = request.getSession(false);if (session != null) {msg.append("; session=").append(session.getId());}String user = request.getRemoteUser();if (user != null) {msg.append("; user=").append(user);}}if (isIncludeQueryString()) {String queryString = request.getQueryString();if (queryString != null) {msg.append("; ").append('?').append(queryString);}}if (isIncludePayload()) {String payload = getMessagePayload(request);if (payload != null) {msg.append("; payload=").append(payload);}}msg.append(suffix);return msg;}/*** 具体打印的方法** @param message 打印的消息*/private void doPrintLog(String message) {// 生产环境打印debug级别if (CommonConstant.IS_PRODUCT_ENVIRONMENT) {log.debug(message);} else {log.info(message);}}}
注册过滤器
package com.yp.basic.log;import com.yp.basic.jackson.JsonUtil;
import com.yp.basic.log.aspect.SysLogAspect;
import com.yp.basic.log.event.SysLogListener;
import com.yp.basic.log.filter.RequestLogPrintFilter;
import com.yp.basic.log.monitor.PointUtil;
import com.yp.basic.log.properties.OptLogProperties;
import lombok.AllArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.filter.CommonsRequestLoggingFilter;/*** 日志自动配置** @author: wcong* @date: 2022/11/25 15:17*/
@EnableAsync
@Configuration
@ConditionalOnWebApplication
@EnableConfigurationProperties(OptLogProperties.class)
public class LogAutoConfiguration {@Bean@ConditionalOnProperty(prefix = OptLogProperties.PREFIX, name = "enable-http-log", havingValue = "true", matchIfMissing = true)public FilterRegistrationBean logFilterRegistration() {CommonsRequestLoggingFilter filter = new RequestLogPrintFilter();// 是否打印header中的内容,参数很多filter.setIncludeHeaders(false);// 是否打印查询字符串内容filter.setIncludeQueryString(true);// 是否打印 payLoad内容,内部使用的是ContentCachingRequestWrapper读取的request.getInputStream(),必须要先调用@RequstBody,才能取到值。filter.setIncludePayload(true);// 是否打印客户端信息(ip、session、remoteUser)filter.setIncludeClientInfo(true);// 1024字节(1kb),超出部分截取// 在UTF-8编码方案中,一个英文字符占用一个字节,一个汉字字符占用三个字节的空间。filter.setMaxPayloadLength(1024);// 设置 before request 日志前缀,默认为:Before request [filter.setBeforeMessagePrefix(RequestLogPrintFilter.BEFORE_REQUEST_PREFIX);// 设置 before request 日志后缀,默认为:]filter.setBeforeMessageSuffix("]");// 设置 before request 日志前缀,默认为:After request [filter.setAfterMessagePrefix(RequestLogPrintFilter.AFTER_REQUEST_PREFIX);// 设置 after request 日志后缀,默认为:]filter.setAfterMessageSuffix("]");FilterRegistrationBean registration = new FilterRegistrationBean<>(filter);registration.addUrlPatterns("/*");registration.setOrder(0);registration.setName("commonsRequestLoggingFilter");return registration;}}