puzhibing
2026-04-11 eed1f52fe5157aa640ceee2f897ddb68bde33c63
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/config/log/FeignLoggingAspect.java
@@ -1,138 +1,83 @@
//package com.xiaopeng.trafficControl.config.log;
//
//import com.alibaba.fastjson2.JSON;
//import com.xiaopeng.common.log.config.LogHeaderProperties;
//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.reflect.MethodSignature;
//import org.springframework.beans.factory.annotation.Autowired;
//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.lang.reflect.Method;
//import java.util.Arrays;
//import java.util.Enumeration;
//import java.util.List;
//
///**
// * Feign 调用日志切面
// *
// * <p>拦截所有带 @FeignClient 注解的接口方法,记录:
// * <ul>
// *   <li>调用的接口类名 + 方法名</li>
// *   <li>入参(JSON 序列化)</li>
// *   <li>出参(JSON 序列化)</li>
// *   <li>耗时(ms)</li>
// *   <li>异常信息(含完整堆栈)</li>
// * </ul>
// */
//@Slf4j
//@Aspect
//@Component
//public class FeignLoggingAspect {
//
//    @Autowired
//    private LogHeaderProperties logHeaderProperties;
//
//    /**
//     * 拦截所有带 @FeignClient 注解的接口的所有方法
//     */
//    @Around("within(@org.springframework.cloud.openfeign.FeignClient *)")
//    public Object logFeignCall(ProceedingJoinPoint pjp) throws Throwable {
//        return doLog(pjp);
//    }
//
//    private Object doLog(ProceedingJoinPoint pjp) throws Throwable {
//        MethodSignature signature = (MethodSignature) pjp.getSignature();
//        Method method = signature.getMethod();
//        // 使用接口声明类名,避免打印动态代理类名(如 $Proxy270)
//        String className = signature.getDeclaringType().getSimpleName();
//        String methodName = method.getName();
//        String fullMethod = className + "#" + methodName;
//
//        Object[] args = pjp.getArgs();
//        String argsJson = safeToJson(args);
//        String headerStr = extractCurrentHeaders();
//
//        if (headerStr != null) {
//            log.info("[Feign] >>> 调用开始 | method={} | headers={} | args={}", fullMethod, headerStr, argsJson);
//        } else {
//            log.info("[Feign] >>> 调用开始 | method={} | args={}", fullMethod, argsJson);
//        }
//
//        long start = System.currentTimeMillis();
//        try {
//            Object result = pjp.proceed();
//            long elapsed = System.currentTimeMillis() - start;
//            String resultJson = safeToJson(result);
//            log.info("[Feign] <<< 调用成功 | method={} | elapsed={}ms | result={}", fullMethod, elapsed, resultJson);
//            return result;
//        } catch (Throwable ex) {
//            long elapsed = System.currentTimeMillis() - start;
//            log.error("[Feign] <<< 调用异常 | method={} | elapsed={}ms | error={} | args={}",
//                    fullMethod, elapsed, ex.getMessage(), argsJson, ex);
//            throw ex;
//        }
//    }
//
//    /**
//     * 安全序列化为 JSON,避免序列化失败导致日志切面本身抛异常
//     */
//    private String safeToJson(Object obj) {
//        if (obj == null) {
//            return "null";
//        }
//        try {
//            if (obj instanceof Object[]) {
//                return JSON.toJSONString(Arrays.asList((Object[]) obj));
//            }
//            return JSON.toJSONString(obj);
//        } catch (Exception e) {
//            return "[序列化失败: " + obj.getClass().getSimpleName() + "]";
//        }
//    }
//
//    /**
//     * 从当前请求上下文中提取请求头信息
//     */
//    private String extractCurrentHeaders() {
//        if (!logHeaderProperties.isEnabled()) {
//            return null;
//        }
//        try {
//            ServletRequestAttributes attrs = (ServletRequestAttributes)
//                    RequestContextHolder.getRequestAttributes();
//            if (attrs == null) return "{}";
//            HttpServletRequest request = attrs.getRequest();
//            List<String> names = logHeaderProperties.getNames();
//            StringBuilder sb = new StringBuilder("{");
//            boolean first = true;
//            if (names != null && !names.isEmpty()) {
//                for (String name : names) {
//                    String value = request.getHeader(name);
//                    if (value != null) {
//                        if (!first) sb.append(", ");
//                        first = false;
//                        sb.append(name).append("=").append(value);
//                    }
//                }
//            } else {
//                Enumeration<String> headerNames = request.getHeaderNames();
//                while (headerNames != null && headerNames.hasMoreElements()) {
//                    String name = headerNames.nextElement();
//                    String value = request.getHeader(name);
//                    if (!first) sb.append(", ");
//                    first = false;
//                    sb.append(name).append("=").append(value);
//                }
//            }
//            return sb.append("}").toString();
//        } catch (Exception e) {
//            return "{error: " + e.getMessage() + "}";
//        }
//    }
//}
package com.xiaopeng.trafficControl.config.log;
import com.alibaba.fastjson2.JSON;
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.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
 * Feign 调用日志切面
 *
 * <p>拦截所有带 @FeignClient 注解的接口方法,记录:
 * <ul>
 *   <li>调用的接口类名 + 方法名</li>
 *   <li>入参(JSON 序列化)</li>
 *   <li>出参(JSON 序列化)</li>
 *   <li>耗时(ms)</li>
 *   <li>异常信息(含完整堆栈)</li>
 * </ul>
 */
@Slf4j
@Aspect
@Component
public class FeignLoggingAspect {
    /**
     * 拦截所有带 @FeignClient 注解的接口的所有方法
     */
    @Around("within(@org.springframework.cloud.openfeign.FeignClient *)")
    public Object logFeignCall(ProceedingJoinPoint pjp) throws Throwable {
        return doLog(pjp);
    }
    private Object doLog(ProceedingJoinPoint pjp) throws Throwable {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        // 使用接口声明类名,避免打印动态代理类名(如 $Proxy270)
        String className = signature.getDeclaringType().getSimpleName();
        String methodName = method.getName();
        String fullMethod = className + "#" + methodName;
        Object[] args = pjp.getArgs();
        String argsJson = safeToJson(args);
        log.info("[Feign] >>> 调用开始 | method={} | args={}", fullMethod, argsJson);
        long start = System.currentTimeMillis();
        try {
            Object result = pjp.proceed();
            long elapsed = System.currentTimeMillis() - start;
            String resultJson = safeToJson(result);
            log.info("[Feign] <<< 调用成功 | method={} | elapsed={}ms | result={}", fullMethod, elapsed, resultJson);
            return result;
        } catch (Throwable ex) {
            long elapsed = System.currentTimeMillis() - start;
            log.error("[Feign] <<< 调用异常 | method={} | elapsed={}ms | error={} | args={}",
                    fullMethod, elapsed, ex.getMessage(), argsJson, ex);
            throw ex;
        }
    }
    /**
     * 安全序列化为 JSON,避免序列化失败导致日志切面本身抛异常
     */
    private String safeToJson(Object obj) {
        if (obj == null) {
            return "null";
        }
        try {
            if (obj instanceof Object[]) {
                return JSON.toJSONString(Arrays.asList((Object[]) obj));
            }
            return JSON.toJSONString(obj);
        } catch (Exception e) {
            return "[序列化失败: " + obj.getClass().getSimpleName() + "]";
        }
    }
}