From 627358ee9e511e6b2e014f5ae9d76a748d9332fb Mon Sep 17 00:00:00 2001 From: zifeihan Date: Thu, 15 Oct 2020 21:55:20 +0800 Subject: [PATCH] Fix duplicate ExitSpan, Maybe this will cause some error message not recorded. because "feign load balance" mechanism will retry execute. (#5667) --- .../v9/LoadBalancerHttpClientInterceptor.java | 102 ++++++++++++++++++ .../define/NetflixFeignInstrumentation.java | 2 +- ...oadBalancerFeignClientInstrumentation.java | 2 +- 3 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 apm-sniffer/apm-sdk-plugin/feign-default-http-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/feign/http/v9/LoadBalancerHttpClientInterceptor.java diff --git a/apm-sniffer/apm-sdk-plugin/feign-default-http-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/feign/http/v9/LoadBalancerHttpClientInterceptor.java b/apm-sniffer/apm-sdk-plugin/feign-default-http-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/feign/http/v9/LoadBalancerHttpClientInterceptor.java new file mode 100644 index 000000000..000c28191 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/feign-default-http-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/feign/http/v9/LoadBalancerHttpClientInterceptor.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.apm.plugin.feign.http.v9; + +import feign.Request; +import feign.Response; +import java.lang.reflect.Method; +import java.net.URL; +import org.apache.skywalking.apm.agent.core.context.ContextManager; +import org.apache.skywalking.apm.agent.core.context.tag.Tags; +import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan; +import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; +import org.apache.skywalking.apm.network.trace.component.ComponentsDefine; + +/** + * {@link LoadBalancerHttpClientInterceptor} intercept the implementation of http calls by the Feign LoadBalancer. + */ +public class LoadBalancerHttpClientInterceptor implements InstanceMethodsAroundInterceptor { + + /** + * @param method intercept method + * @param result change this result, if you want to truncate the method. + * @throws Throwable NoSuchFieldException or IllegalArgumentException + */ + @Override + public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, + MethodInterceptResult result) throws Throwable { + Request request = (Request) allArguments[0]; + URL url = new URL(request.url()); + String operationName = url.getPath(); + FeignResolvedURL feignResolvedURL = PathVarInterceptor.URL_CONTEXT.get(); + if (feignResolvedURL != null) { + try { + operationName = operationName.replace(feignResolvedURL.getUrl(), feignResolvedURL.getOriginUrl()); + } finally { + PathVarInterceptor.URL_CONTEXT.remove(); + } + } + if (operationName.length() == 0) { + operationName = "/"; + } + AbstractSpan span = ContextManager.createLocalSpan("Balancer" + operationName); + span.setComponent(ComponentsDefine.FEIGN); + Tags.HTTP.METHOD.set(span, request.method()); + Tags.URL.set(span, request.url()); + SpanLayer.asHttp(span); + } + + /** + * Get the status code from {@link Response}, when status code greater than 400, it means there was some errors in + * the server. Finish the {@link AbstractSpan}. + * + * @param method intercept method + * @param ret the method's original return value. + * @return origin ret + */ + @Override + public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, + Object ret) { + Response response = (Response) ret; + if (response != null) { + int statusCode = response.status(); + + AbstractSpan span = ContextManager.activeSpan(); + if (statusCode >= 400) { + span.errorOccurred(); + Tags.STATUS_CODE.set(span, Integer.toString(statusCode)); + } + } + + ContextManager.stopSpan(); + + return ret; + } + + @Override + public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, + Class[] argumentsTypes, Throwable t) { + AbstractSpan activeSpan = ContextManager.activeSpan(); + activeSpan.log(t); + activeSpan.errorOccurred(); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-cloud/netflix-plugins/spring-cloud-feign-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/netflix/feign/v11/define/NetflixFeignInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-cloud/netflix-plugins/spring-cloud-feign-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/netflix/feign/v11/define/NetflixFeignInstrumentation.java index 6a3c5d96e..72cde3d9a 100644 --- a/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-cloud/netflix-plugins/spring-cloud-feign-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/netflix/feign/v11/define/NetflixFeignInstrumentation.java +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-cloud/netflix-plugins/spring-cloud-feign-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/netflix/feign/v11/define/NetflixFeignInstrumentation.java @@ -37,7 +37,7 @@ public class NetflixFeignInstrumentation extends ClassInstanceMethodsEnhancePlug /** * Intercept class. */ - private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.feign.http.v9.DefaultHttpClientInterceptor"; + private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.feign.http.v9.LoadBalancerHttpClientInterceptor"; @Override protected ClassMatch enhanceClass() { diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-cloud/spring-cloud-feign-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/string/cloud/netflix/feign/v2/define/LoadBalancerFeignClientInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-cloud/spring-cloud-feign-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/string/cloud/netflix/feign/v2/define/LoadBalancerFeignClientInstrumentation.java index 12f03d2f6..aba02f2b4 100644 --- a/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-cloud/spring-cloud-feign-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/string/cloud/netflix/feign/v2/define/LoadBalancerFeignClientInstrumentation.java +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-cloud/spring-cloud-feign-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/string/cloud/netflix/feign/v2/define/LoadBalancerFeignClientInstrumentation.java @@ -32,7 +32,7 @@ public class LoadBalancerFeignClientInstrumentation extends ClassInstanceMethods public static final String ENHANCE_CLASS = "org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient"; - private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.feign.http.v9.DefaultHttpClientInterceptor"; + private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.feign.http.v9.LoadBalancerHttpClientInterceptor"; @Override protected ClassMatch enhanceClass() {