请求拦截

/**
 * 服务间header传递配置
 */
@Slf4j
@Configuration //由各个项目自己配置
public class FeignConfiguration implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        if (UserContext.getHeaders()!=null) {
            UserContext.getHeaders().forEach(template::header);
        }
        try {
            // 服务调用异常辅助信息
            Target<?> target = template.feignTarget();
            FeignMetaVO feignMetaVO = new FeignMetaVO(target.name(), target.type().getSimpleName(), template.url(), template.method(),
                    JSON.toJSONString(template.queries()), new String(template.body(), StandardCharsets.UTF_8));
            UserContext.setExtra(UserContextExtraKeyEnum.FEIGN_META.getCode(), JSON.toJSONString(feignMetaVO));
            // 以下部分,保留一段时间后删除,仅服务调用异常时打印
            FeignMetaVO simpleInfo = ConvertUtils.sourceToTarget(feignMetaVO, FeignMetaVO.class);
            simpleInfo.setBody("仅服务调用异常时打印此字段"); // 请求体内容可能很多,所以平时不打印,仅服务调用异常时打印
            log.info("Feign调用调试信息:{}", simpleInfo);
            UserContext.addCallChainNode(target.name()); // 添加调用链路节点,用于打印调用链路
        } catch (Exception e) {
            // 忽略异常
        }
    }
}

响应拦截

方式一

注入自定义解码器

@Slf4j
@Configuration
@ConditionalOnClass({Feign.class})
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class FeignConfig {

	@Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;

	@Bean
	public Decoder feignDecoder() {
		return new OptionalDecoder(new ResponseEntityDecoder(new MyDecoder(this.messageConverters)));
	}
}

继承SpringDecoder自定义解码器

class MyDecoder extends SpringDecoder {

	MyDecoder(ObjectFactory<HttpMessageConverters> messageConverters) {
		super(messageConverters);
	}

	@Override
	public Object decode(Response response, Type type) throws IOException, FeignException {

		// 这里可以从response对象里面获取响应头和响应体

        // 获取响应头
		Map<String, Collection<String>> headers = response.headers();

		return super.decode(response, type);
	}
}

方式二

https://zhuanlan.zhihu.com/p/528834129

提取堆栈摘要

 private String compressStack(RuntimeException ex) {
        String stacktrace = ExceptionUtil.stacktraceToString(ex, 3000);// 只保留有效堆栈,限制3000字符(经验值),不够再改
        String format = stacktrace.replace("  ", "");
        String repack = Arrays.stream(format.split("\n")).filter(row -> !row.startsWith("at") || row.contains("xianniu")).collect(Collectors.joining("\n"));
        return repack;
    }