package com.xiaopeng.pushMessage.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.*; /** * Feign 调用日志切面 * *

拦截所有带 @FeignClient 注解的接口方法,记录: *

*/ @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 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 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() + "}"; } } }