本文简介
前篇侧重 Log4j2 的配置,本篇侧重统一日志处理的应用,以下包含 HTTP 请求的日志处理、Exception 异常日志处理。
HTTP 请求日志
1、明确日志记录的内容
示例:用户、IP地址、Method、URI、请求参数、请求体
2、全局拦截 MDCFilter.java
package com.anoyi.config.server;import lombok.extern.log4j.Log4j2;import org.slf4j.MDC;import org.springframework.http.HttpMethod;import org.springframework.stereotype.Component;import org.springframework.web.filter.OncePerRequestFilter;import javax.servlet.FilterChain;import javax.servlet.ReadListener;import javax.servlet.ServletException;import javax.servlet.ServletInputStream;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequestWrapper;import javax.servlet.http.HttpServletResponse;import java.io.*;/** * 拦截请求信息,添加到日志 */@Component@Log4j2public class MDCFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { try { MDC.put("user", request.getRemoteUser()); String query = request.getQueryString() != null ? "?" + request.getQueryString() : ""; if (request.getMethod().equals(HttpMethod.POST.name())) { MultiReadHttpServletRequest multiReadHttpServletRequest = new MultiReadHttpServletRequest(request); log.info("IP:{}, Method:{}, URI:{} Body:{}", request.getRemoteAddr(), request.getMethod(), request.getRequestURI() + query, multiReadHttpServletRequest.getRequestBody()); chain.doFilter(multiReadHttpServletRequest, response); } else { log.info("IP:{}, Method:{}, URI:{}", request.getRemoteAddr(), request.getMethod(), request.getRequestURI() + query); chain.doFilter(request, response); } } finally { MDC.clear(); } } /** * HttpServletRequest 请求体多读 */ class MultiReadHttpServletRequest extends HttpServletRequestWrapper { // 缓存 RequestBody private String requestBody; MultiReadHttpServletRequest(HttpServletRequest request) { super(request); requestBody = ""; try { StringBuilder stringBuilder = new StringBuilder(); InputStream inputStream = request.getInputStream(); byte[] bs = new byte[1024]; int len; while ((len = inputStream.read(bs)) != -1) { stringBuilder.append(new String(bs, 0, len)); } requestBody = stringBuilder.toString(); } catch (IOException e) { e.printStackTrace(); } } @Override public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(requestBody.getBytes()); return new ServletInputStream() { public int read() throws IOException { return byteArrayInputStream.read(); } @Override public boolean isFinished() { return byteArrayInputStream.available() == 0; } @Override public boolean isReady() { return true; } @Override public void setReadListener(ReadListener readListener) { } }; } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(this.getInputStream())); } String getRequestBody() { return requestBody.replaceAll("\n", ""); } } }
3、配置日志 Pattern
logging: pattern: console: "%d{yyyy-MM-dd HH:mm:ss.SSS} %5p [%15.15t] %-40.40c{1.} [%X{user}] : %m%n%xwEx"
说明:
MDC.put("user", request.getRemoteUser());
=>%X{user}
Exception 异常日志
1、全局异常处理 ExceptionController.java
package com.anoyi.controller;import com.anoyi.bean.ResponseBean;import lombok.AllArgsConstructor;import lombok.extern.log4j.Log4j2;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.ResponseBody; @ControllerAdvice@Log4j2 @AllArgsConstructor public class ExceptionController { /** * 抛出错误前,打印错误日志 * **/ @ExceptionHandler(Exception.class) @ResponseBody public ResponseBean handleException(Exception exception){ log.error(exception.getMessage(), exception); return ResponseBean.error(exception); } }
作者:Anoyi
链接:https://www.jianshu.com/p/c883b86c34fa