Spring Boot - 自定义Aspect打印请求日志

通常我们自定义一个Aspect用于记录请求日志,方便问题排查。

主要记录了如下信息:

  • 请求方法及请求地址
  • 客户端IP地址
  • 调用的控制器类及方法名
  • 请求头信息
  • 请求参数
  • 处理耗时

代码实现

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

@Slf4j
@Aspect
@Component
public class WebLogAspect {

    private final String LOCALHOST_IPV4 = "127.0.0.1";
    private final String LOCALHOST_IPV6 = "0:0:0:0:0:0:0:1";

    // 切入点
    @Pointcut("execution(public * demo.controller..*(..)))")
    public void pointCut() {
    }

    @Around("pointCut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // 开始处理时间
        long startTime = System.currentTimeMillis();
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 构建成一条长日志,避免并发下日志输出错乱
        StringBuilder sb = new StringBuilder(300);
        // 日志参数
        List reqArgs = new ArrayList<>();
        sb.append("
================ Start  ================
");
        // 打印路由
        sb.append("===> {}: {}
");
        String requestMethod = request.getMethod();
        reqArgs.add(requestMethod);
        reqArgs.add(request.getRequestURL().toString());
        // IP
        sb.append("===> IP: {}
");
        reqArgs.add(getClientIp(request));
        // 打印调用 controller 的全路径以及执行方法
        sb.append("===> Class Method: {}.{}
");
        reqArgs.add(joinPoint.getSignature().getDeclaringTypeName());
        reqArgs.add(joinPoint.getSignature().getName());
        // 打印请求头
        Enumeration headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            sb.append("=== Headers ===  {}: {}
");
            String headerName = headerNames.nextElement();
            reqArgs.add(headerName);
            reqArgs.add(StrUtil.join("", request.getHeader(headerName)));
        }
        // 打印请求入参
        sb.append("===> request params: {}
");
        reqArgs.add(JSONUtil.toJsonStr(joinPoint.getArgs()));
//        List args = Arrays.asList(joinPoint.getArgs());
//        log.info("Request Args   : {}", new Gson().toJson(args));
        Object result = joinPoint.proceed();
//        // 打印出参
//        log.info("Response Args  : {}", new Gson().toJson(result));
//        // 打印处理耗时
        sb.append(StrUtil.format("处理耗时: {} ms 
", System.currentTimeMillis() - startTime));
        sb.append("================ End  =================
");
        // 打印
        log.info(sb.toString(), reqArgs.toArray());
        return result;
    }

    // 获取客户端IP
    public String getClientIp(HttpServletRequest request) {
        String ipAddress = request.getHeader("X-Forwarded-For");
        if (StrUtil.isEmpty(ipAddress) || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if (StrUtil.isEmpty(ipAddress) || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if (StrUtil.isEmpty(ipAddress) || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
            if (LOCALHOST_IPV4.equals(ipAddress) || LOCALHOST_IPV6.equals(ipAddress)) {
                try {
                    InetAddress inetAddress = InetAddress.getLocalHost();
                    ipAddress = inetAddress.getHostAddress();
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
            }
        }
        if (!StrUtil.isEmpty(ipAddress)
                && ipAddress.length() > 15
                && ipAddress.indexOf(",") > 0) {
            ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
        }
        return ipAddress;
    }

}



发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章