Skip to content

Commit 466f173

Browse files
authored
Fix not tracing in HttpClient v5 when HttpHost(arg[0]) is null but RoutingSupport#determineHost works. (#674)
Skywalking hc5 plugin worked the same as hc4 plugin: if the arg[0] is null, skip creating the exitSpan. this will cause a bug in hc5: when the HttpHost is null but InternalHttpClient determines the host from ClassicHttpRequest, InternalHttpClient will send the request but Skywalking will not record it.
1 parent f227543 commit 466f173

File tree

9 files changed

+431
-12
lines changed

9 files changed

+431
-12
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Release Notes.
1717
* Support for ActiveMQ-Artemis messaging tracing.
1818
* Archive the expired plugins `impala-jdbc-2.6.x-plugin`.
1919
* Fix a bug in Spring Cloud Gateway if HttpClientFinalizer#send does not invoke, the span created at NettyRoutingFilterInterceptor can not stop.
20+
* Fix not tracing in HttpClient v5 when HttpHost(arg[0]) is null but `RoutingSupport#determineHost` works.
2021

2122
#### Documentation
2223
* Update docs to describe `expired-plugins`.

apm-sniffer/apm-sdk-plugin/httpclient-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpclient/v5/HttpClientDoExecuteInterceptor.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,19 @@
3838
import java.net.MalformedURLException;
3939
import java.net.URL;
4040

41-
public class HttpClientDoExecuteInterceptor implements InstanceMethodsAroundInterceptor {
41+
public abstract class HttpClientDoExecuteInterceptor implements InstanceMethodsAroundInterceptor {
4242
private static final String ERROR_URI = "/_blank";
4343

4444
private static final ILog LOGGER = LogManager.getLogger(HttpClientDoExecuteInterceptor.class);
4545

4646
@Override
4747
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
4848
MethodInterceptResult result) throws Throwable {
49-
if (allArguments[0] == null || allArguments[1] == null) {
49+
if (skipIntercept(objInst, method, allArguments, argumentsTypes)) {
5050
// illegal args, can't trace. ignore.
5151
return;
5252
}
53-
final HttpHost httpHost = (HttpHost) allArguments[0];
53+
final HttpHost httpHost = getHttpHost(objInst, method, allArguments, argumentsTypes);
5454
ClassicHttpRequest httpRequest = (ClassicHttpRequest) allArguments[1];
5555
final ContextCarrier contextCarrier = new ContextCarrier();
5656

@@ -75,10 +75,18 @@ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allAr
7575
}
7676
}
7777

78+
protected boolean skipIntercept(EnhancedInstance objInst, Method method, Object[] allArguments,
79+
Class<?>[] argumentsTypes) {
80+
return allArguments[1] == null || getHttpHost(objInst, method, allArguments, argumentsTypes) == null;
81+
}
82+
83+
protected abstract HttpHost getHttpHost(EnhancedInstance objInst, Method method, Object[] allArguments,
84+
Class<?>[] argumentsTypes) ;
85+
7886
@Override
7987
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
8088
Object ret) throws Throwable {
81-
if (allArguments[0] == null || allArguments[1] == null) {
89+
if (skipIntercept(objInst, method, allArguments, argumentsTypes)) {
8290
return ret;
8391
}
8492

@@ -100,6 +108,9 @@ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allA
100108
@Override
101109
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
102110
Class<?>[] argumentsTypes, Throwable t) {
111+
if (skipIntercept(objInst, method, allArguments, argumentsTypes)) {
112+
return;
113+
}
103114
AbstractSpan activeSpan = ContextManager.activeSpan();
104115
activeSpan.log(t);
105116
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package org.apache.skywalking.apm.plugin.httpclient.v5;
20+
21+
import org.apache.hc.client5.http.routing.RoutingSupport;
22+
import org.apache.hc.core5.http.HttpHost;
23+
import org.apache.hc.core5.http.HttpRequest;
24+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
25+
26+
import java.lang.reflect.Method;
27+
28+
public class InternalClientDoExecuteInterceptor extends HttpClientDoExecuteInterceptor {
29+
30+
@Override
31+
protected HttpHost getHttpHost(EnhancedInstance objInst, Method method, Object[] allArguments,
32+
Class<?>[] argumentsTypes) {
33+
HttpHost httpHost = (HttpHost) allArguments[0];
34+
if (httpHost != null) {
35+
return httpHost;
36+
}
37+
try {
38+
return RoutingSupport.determineHost((HttpRequest) allArguments[1]);
39+
} catch (Exception ignore) {
40+
// ignore
41+
return null;
42+
}
43+
}
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package org.apache.skywalking.apm.plugin.httpclient.v5;
20+
21+
import org.apache.hc.core5.http.HttpHost;
22+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
23+
24+
import java.lang.reflect.Method;
25+
26+
public class MinimalClientDoExecuteInterceptor extends HttpClientDoExecuteInterceptor {
27+
28+
@Override
29+
protected HttpHost getHttpHost(EnhancedInstance objInst, Method method, Object[] allArguments,
30+
Class<?>[] argumentsTypes) {
31+
return (HttpHost) allArguments[0];
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package org.apache.skywalking.apm.plugin.httpclient.v5.define;
20+
21+
import net.bytebuddy.description.method.MethodDescription;
22+
import net.bytebuddy.matcher.ElementMatcher;
23+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
24+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
25+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
26+
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
27+
import org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch;
28+
29+
import static net.bytebuddy.matcher.ElementMatchers.named;
30+
31+
public class InternalHttpClientInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
32+
33+
private static final String ENHANCE_CLASS_MINIMAL = "org.apache.hc.client5.http.impl.classic.InternalHttpClient";
34+
private static final String METHOD_NAME = "doExecute";
35+
private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.httpclient.v5.InternalClientDoExecuteInterceptor";
36+
37+
@Override
38+
public ClassMatch enhanceClass() {
39+
return MultiClassNameMatch.byMultiClassMatch(ENHANCE_CLASS_MINIMAL);
40+
}
41+
42+
@Override
43+
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
44+
return new ConstructorInterceptPoint[0];
45+
}
46+
47+
@Override
48+
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
49+
return new InstanceMethodsInterceptPoint[]{
50+
new InstanceMethodsInterceptPoint() {
51+
@Override
52+
public ElementMatcher<MethodDescription> getMethodsMatcher() {
53+
return named(METHOD_NAME);
54+
}
55+
56+
@Override
57+
public String getMethodsInterceptor() {
58+
return INTERCEPT_CLASS;
59+
}
60+
61+
@Override
62+
public boolean isOverrideArgs() {
63+
return false;
64+
}
65+
}
66+
};
67+
}
68+
}

apm-sniffer/apm-sdk-plugin/httpclient-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpclient/v5/define/HttpClientInstrumentation.java renamed to apm-sniffer/apm-sdk-plugin/httpclient-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpclient/v5/define/MinimalHttpClientInstrumentation.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,20 @@
2828

2929
import static net.bytebuddy.matcher.ElementMatchers.named;
3030

31-
public class HttpClientInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
31+
public class MinimalHttpClientInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
3232

3333
private static final String ENHANCE_CLASS_MINIMAL = "org.apache.hc.client5.http.impl.classic.MinimalHttpClient";
34-
private static final String ENHANCE_CLASS_INTERNAL = "org.apache.hc.client5.http.impl.classic.InternalHttpClient";
3534
private static final String METHOD_NAME = "doExecute";
36-
private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.httpclient.v5.HttpClientDoExecuteInterceptor";
35+
private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.httpclient.v5.MinimalClientDoExecuteInterceptor";
3736

3837
@Override
3938
public ClassMatch enhanceClass() {
40-
return MultiClassNameMatch.byMultiClassMatch(ENHANCE_CLASS_MINIMAL, ENHANCE_CLASS_INTERNAL);
39+
return MultiClassNameMatch.byMultiClassMatch(ENHANCE_CLASS_MINIMAL);
4140
}
4241

4342
@Override
4443
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
45-
return null;
44+
return new ConstructorInterceptPoint[0];
4645
}
4746

4847
@Override

apm-sniffer/apm-sdk-plugin/httpclient-5.x-plugin/src/main/resources/skywalking-plugin.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
# See the License for the specific language governing permissions and
1515
# limitations under the License.
1616

17-
httpclient-5.x=org.apache.skywalking.apm.plugin.httpclient.v5.define.HttpClientInstrumentation
17+
httpclient-5.x=org.apache.skywalking.apm.plugin.httpclient.v5.define.MinimalHttpClientInstrumentation
18+
httpclient-5.x=org.apache.skywalking.apm.plugin.httpclient.v5.define.InternalHttpClientInstrumentation
1819
httpclient-5.x=org.apache.skywalking.apm.plugin.httpclient.v5.define.HttpAsyncClientInstrumentation
1920
httpclient-5.x=org.apache.skywalking.apm.plugin.httpclient.v5.define.IOSessionImplInstrumentation

0 commit comments

Comments
 (0)