Skip to content

Commit 4bb2c2f

Browse files
authored
Add support gRPC 1.59.x and 1.70.x server interceptor trace (#764)
Root cause, grpc/grpc-java@050ae18 made changes to AbstractServerImplBuilder, which causes a functional issue with the gRPC tracing plugin.
1 parent eec4132 commit 4bb2c2f

File tree

38 files changed

+2800
-7
lines changed

38 files changed

+2800
-7
lines changed

.github/workflows/plugins-test.0.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ jobs:
8080
- gateway-2.1.x-scenario
8181
- gateway-2.0.x-scenario
8282
- grpc-scenario
83+
- grpc-1.59.x-1.70.x-scenario
84+
- grpc-1.30.x-1.39.x-scenario
8385
- gson-scenario
8486
- guava-cache-scenario
8587
- elasticjob-3.x-scenario

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Release Notes.
1616
* Fix RabbitMQ Consumer could not receive handleCancelOk callback.
1717
* Support for tracking in lettuce versions 6.5.x and above.
1818
* Upgrade byte-buddy version to 1.17.6.
19+
* Support gRPC 1.59.x and 1.70.x server interceptor trace
1920

2021
All issues and pull requests are [here](https://github.com/apache/skywalking/milestone/236?closed=1)
2122

apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/define/AbstractServerImplBuilderInstrumentation.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,13 @@
2424
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
2525
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
2626
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
27+
import org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch;
2728

2829
import static net.bytebuddy.matcher.ElementMatchers.named;
2930
import static net.bytebuddy.matcher.ElementMatchers.takesNoArguments;
30-
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
3131

3232
public class AbstractServerImplBuilderInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
3333

34-
public static final String ENHANCE_CLASS = "io.grpc.internal.AbstractServerImplBuilder";
3534
public static final String ENHANCE_METHOD = "build";
3635
public static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.grpc.v1.server.AbstractServerImplBuilderInterceptor";
3736

@@ -64,6 +63,9 @@ public boolean isOverrideArgs() {
6463

6564
@Override
6665
protected ClassMatch enhanceClass() {
67-
return byName(ENHANCE_CLASS);
66+
return MultiClassNameMatch.byMultiClassMatch(
67+
"io.grpc.internal.AbstractServerImplBuilder", //grpc version <= 1.58.1
68+
"io.grpc.internal.ServerImplBuilder" //grpc version >= 1.59.0
69+
);
6870
}
6971
}

apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/server/AbstractServerImplBuilderInterceptor.java

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@
2020

2121
import io.grpc.ServerBuilder;
2222

23+
import java.lang.reflect.Field;
2324
import java.lang.reflect.Method;
25+
import java.util.HashMap;
26+
import java.util.List;
27+
import java.util.Map;
2428

2529
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
2630
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
@@ -30,14 +34,26 @@
3034
* {@link AbstractServerImplBuilderInterceptor} add the {@link ServerInterceptor} interceptor for every ServerService.
3135
*/
3236
public class AbstractServerImplBuilderInterceptor implements InstanceMethodsAroundInterceptor {
37+
private final static Map<Class<?>, Field> FIELD_CACHE = new HashMap<>();
38+
3339
@Override
3440
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
35-
MethodInterceptResult result) {
41+
MethodInterceptResult result) throws Throwable {
3642
if (objInst.getSkyWalkingDynamicField() == null) {
3743
ServerBuilder<?> builder = (ServerBuilder) objInst;
38-
ServerInterceptor interceptor = new ServerInterceptor();
39-
builder.intercept(interceptor);
40-
objInst.setSkyWalkingDynamicField(interceptor);
44+
Field field = findField(builder.getClass());
45+
if (field != null) {
46+
List<?> interceptors = (List<?>) field.get(builder);
47+
boolean hasCustomInterceptor = interceptors.stream()
48+
.anyMatch(i -> i.getClass() == ServerInterceptor.class);
49+
50+
if (!hasCustomInterceptor) {
51+
ServerInterceptor interceptor = new ServerInterceptor();
52+
builder.intercept(interceptor);
53+
objInst.setSkyWalkingDynamicField(interceptor);
54+
}
55+
56+
}
4157
}
4258
}
4359

@@ -52,4 +68,31 @@ public void handleMethodException(EnhancedInstance objInst, Method method, Objec
5268
Class<?>[] argumentsTypes, Throwable t) {
5369

5470
}
71+
72+
private static Field findField(Class<?> clazz) {
73+
if (FIELD_CACHE.containsKey(clazz)) {
74+
return FIELD_CACHE.get(clazz);
75+
}
76+
synchronized (AbstractServerImplBuilderInterceptor.class) {
77+
if (FIELD_CACHE.containsKey(clazz)) {
78+
return FIELD_CACHE.get(clazz);
79+
}
80+
Field field = doFindField(clazz);
81+
FIELD_CACHE.put(clazz, field);
82+
return field;
83+
}
84+
}
85+
86+
private static Field doFindField(Class<?> clazz) {
87+
while (clazz != null) {
88+
for (Field f : clazz.getDeclaredFields()) {
89+
if (f.getName().equals("interceptors")) {
90+
f.setAccessible(true);
91+
return f;
92+
}
93+
}
94+
clazz = clazz.getSuperclass();
95+
}
96+
return null;
97+
}
5598
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/bin/bash
2+
#
3+
# Licensed to the Apache Software Foundation (ASF) under one
4+
# or more contributor license agreements. See the NOTICE file
5+
# distributed with this work for additional information
6+
# regarding copyright ownership. The ASF licenses this file
7+
# to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance
9+
# with the License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing, software
14+
# distributed under the License is distributed on an "AS IS" BASIS,
15+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
# See the License for the specific language governing permissions and
17+
# limitations under the License.
18+
19+
home="$(cd "$(dirname $0)"; pwd)"
20+
21+
java -jar ${agent_opts} ${home}/../libs/grpc-1.30.x-1.39.x-scenario.jar &

0 commit comments

Comments
 (0)