Skip to content

Commit 30d60b9

Browse files
authored
Update Jedis 4.x plugin to support Sharding and Cluster models. (#677)
1 parent a751e32 commit 30d60b9

File tree

15 files changed

+478
-8
lines changed

15 files changed

+478
-8
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Release Notes.
1919
* Fix a bug in Spring Cloud Gateway if HttpClientFinalizer#send does not invoke, the span created at NettyRoutingFilterInterceptor can not stop.
2020
* Fix not tracing in HttpClient v5 when HttpHost(arg[0]) is null but `RoutingSupport#determineHost` works.
2121
* Support across thread tracing for SOFA-RPC.
22+
* Update Jedis 4.x plugin to support Sharding and Cluster models.
2223

2324
#### Documentation
2425
* Update docs to describe `expired-plugins`.

apm-sniffer/apm-sdk-plugin/jedis-plugins/jedis-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jedis/v4/AbstractConnectionInterceptor.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package org.apache.skywalking.apm.plugin.jedis.v4;
1919

2020
import org.apache.skywalking.apm.agent.core.context.ContextManager;
21+
import org.apache.skywalking.apm.agent.core.context.tag.StringTag;
2122
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
2223
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
2324
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
@@ -39,6 +40,8 @@ public abstract class AbstractConnectionInterceptor implements InstanceMethodsAr
3940

4041
private static final String CACHE_TYPE = "Redis";
4142

43+
private static final StringTag TAG_ARGS = new StringTag("actual_target");
44+
4245
@Override
4346
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
4447
Iterator<Rawable> iterator = getCommands(allArguments);
@@ -49,12 +52,15 @@ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allAr
4952
// Use lowercase to make config compatible with jedis-2.x-3.x plugin
5053
// Refer to `plugin.jedis.operation_mapping_read`, `plugin.jedis.operation_mapping_write` config item in agent.config
5154
String cmd = protocolCommand == null ? UNKNOWN : protocolCommand.toLowerCase();
52-
String peer = String.valueOf(objInst.getSkyWalkingDynamicField());
55+
ConnectionInformation connectionData = (ConnectionInformation) objInst.getSkyWalkingDynamicField();
56+
// Use cluster information to adapt Virtual Cache if exists, otherwise use real server host
57+
String peer = StringUtil.isBlank(connectionData.getClusterNodes()) ? connectionData.getActualTarget() : connectionData.getClusterNodes();
5358
AbstractSpan span = ContextManager.createExitSpan("Jedis/" + cmd, peer);
5459
span.setComponent(ComponentsDefine.JEDIS);
5560
readKeyIfNecessary(iterator).ifPresent(key -> Tags.CACHE_KEY.set(span, key));
5661
Tags.CACHE_CMD.set(span, cmd);
5762
Tags.CACHE_TYPE.set(span, CACHE_TYPE);
63+
TAG_ARGS.set(span, connectionData.getActualTarget());
5864
parseOperation(cmd).ifPresent(op -> Tags.CACHE_OP.set(span, op));
5965
SpanLayer.asCache(span);
6066
}

apm-sniffer/apm-sdk-plugin/jedis-plugins/jedis-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jedis/v4/ConnectionConstructorInterceptor.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ public class ConnectionConstructorInterceptor implements InstanceConstructorInte
2626
@Override
2727
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) throws Throwable {
2828
HostAndPort hostAndPort = ((DefaultJedisSocketFactory) allArguments[0]).getHostAndPort();
29-
objInst.setSkyWalkingDynamicField(hostAndPort.getHost() + ":" + hostAndPort.getPort());
29+
ConnectionInformation connectionData = new ConnectionInformation();
30+
connectionData.setActualTarget(hostAndPort.toString());
31+
objInst.setSkyWalkingDynamicField(connectionData);
3032
}
3133
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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+
package org.apache.skywalking.apm.plugin.jedis.v4;
19+
20+
import lombok.Data;
21+
22+
@Data
23+
public class ConnectionInformation {
24+
private String clusterNodes;
25+
private String actualTarget;
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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+
package org.apache.skywalking.apm.plugin.jedis.v4;
19+
20+
import java.util.Collection;
21+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
22+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
23+
import org.apache.skywalking.apm.util.StringUtil;
24+
import redis.clients.jedis.HostAndPort;
25+
26+
public class ConnectionProviderConstructorInterceptor implements InstanceConstructorInterceptor {
27+
@Override
28+
public void onConstruct(final EnhancedInstance objInst, final Object[] allArguments) throws Throwable {
29+
if (objInst.getSkyWalkingDynamicField() != null) {
30+
return;
31+
}
32+
Object arg = allArguments[0];
33+
if (arg instanceof Collection) {
34+
Collection<?> collection = (Collection<?>) arg;
35+
final String[] array = collection.stream().map(Object::toString).toArray(String[]::new);
36+
objInst.setSkyWalkingDynamicField(StringUtil.join(',', array));
37+
}
38+
if (arg instanceof HostAndPort) {
39+
objInst.setSkyWalkingDynamicField(arg.toString());
40+
}
41+
}
42+
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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+
package org.apache.skywalking.apm.plugin.jedis.v4;
19+
20+
import java.lang.reflect.Method;
21+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
22+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
23+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
24+
25+
public class ConnectionProviderGetConnectionInterceptor implements InstanceMethodsAroundInterceptor {
26+
@Override
27+
public void beforeMethod(final EnhancedInstance objInst,
28+
final Method method,
29+
final Object[] allArguments,
30+
final Class<?>[] argumentsTypes,
31+
final MethodInterceptResult result) throws Throwable {
32+
33+
}
34+
35+
@Override
36+
public Object afterMethod(final EnhancedInstance objInst,
37+
final Method method,
38+
final Object[] allArguments,
39+
final Class<?>[] argumentsTypes,
40+
final Object ret) throws Throwable {
41+
if (ret instanceof EnhancedInstance) {
42+
EnhancedInstance connection = (EnhancedInstance) ret;
43+
if (connection.getSkyWalkingDynamicField() != null
44+
&& connection.getSkyWalkingDynamicField() instanceof ConnectionInformation) {
45+
((ConnectionInformation) connection.getSkyWalkingDynamicField()).setClusterNodes(
46+
(String) objInst.getSkyWalkingDynamicField());
47+
}
48+
}
49+
return ret;
50+
}
51+
52+
@Override
53+
public void handleMethodException(final EnhancedInstance objInst,
54+
final Method method,
55+
final Object[] allArguments,
56+
final Class<?>[] argumentsTypes,
57+
final Throwable t) {
58+
59+
}
60+
}

apm-sniffer/apm-sdk-plugin/jedis-plugins/jedis-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jedis/v4/JedisMethodInterceptor.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package org.apache.skywalking.apm.plugin.jedis.v4;
1919

2020
import org.apache.skywalking.apm.agent.core.context.ContextManager;
21+
import org.apache.skywalking.apm.agent.core.context.tag.StringTag;
2122
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
2223
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
2324
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
@@ -27,18 +28,23 @@
2728
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
2829

2930
import java.lang.reflect.Method;
31+
import org.apache.skywalking.apm.util.StringUtil;
3032

3133
public class JedisMethodInterceptor implements InstanceMethodsAroundInterceptor {
34+
private static final StringTag TAG_ARGS = new StringTag("actual_target");
3235

3336
@Override
3437
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
3538
MethodInterceptResult result) throws Throwable {
36-
String peer = String.valueOf(objInst.getSkyWalkingDynamicField());
39+
final ConnectionInformation connectionData = (ConnectionInformation) objInst.getSkyWalkingDynamicField();
40+
// Use cluster information to adapt Virtual Cache if exists, otherwise use real server host
41+
String peer = StringUtil.isBlank(connectionData.getClusterNodes()) ? connectionData.getActualTarget() : connectionData.getClusterNodes();
3742
AbstractSpan span = ContextManager.createExitSpan("Jedis/" + method.getName(), peer);
3843
span.setComponent(ComponentsDefine.JEDIS);
3944
SpanLayer.asCache(span);
4045
Tags.CACHE_TYPE.set(span, "Redis");
4146
Tags.CACHE_CMD.set(span, "BATCH_EXECUTE");
47+
TAG_ARGS.set(span, connectionData.getActualTarget());
4248
}
4349

4450
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
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+
package org.apache.skywalking.apm.plugin.jedis.v4.define;
19+
20+
import net.bytebuddy.description.method.MethodDescription;
21+
import net.bytebuddy.matcher.ElementMatcher;
22+
import net.bytebuddy.matcher.ElementMatchers;
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.match.ClassMatch;
26+
27+
import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
28+
import static net.bytebuddy.matcher.ElementMatchers.named;
29+
import static org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch.byHierarchyMatch;
30+
31+
public class ConnectionProviderInstrumentation extends AbstractWitnessInstrumentation {
32+
33+
private static final String ENHANCE_INTERFACE = "redis.clients.jedis.providers.ConnectionProvider";
34+
private static final String CONNECTION_PROVIDER_CONSTRUCTION_INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.jedis.v4.ConnectionProviderConstructorInterceptor";
35+
private static final String CONNECTION_PROVIDER_GET_CONNECTION_INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.jedis.v4.ConnectionProviderGetConnectionInterceptor";
36+
37+
@Override
38+
protected ClassMatch enhanceClass() {
39+
return byHierarchyMatch(ENHANCE_INTERFACE);
40+
}
41+
42+
@Override
43+
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
44+
return new ConstructorInterceptPoint[]{
45+
new ConstructorInterceptPoint() {
46+
@Override
47+
public ElementMatcher<MethodDescription> getConstructorMatcher() {
48+
return ElementMatchers.takesArgument(0, named("redis.clients.jedis.HostAndPort"))
49+
.or(ElementMatchers.takesArgument(0, hasSuperType(named("java.util.Collection"))));
50+
}
51+
52+
@Override
53+
public String getConstructorInterceptor() {
54+
return CONNECTION_PROVIDER_CONSTRUCTION_INTERCEPT_CLASS;
55+
}
56+
}
57+
};
58+
}
59+
60+
@Override
61+
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
62+
return new InstanceMethodsInterceptPoint[] {
63+
new InstanceMethodsInterceptPoint() {
64+
@Override
65+
public ElementMatcher<MethodDescription> getMethodsMatcher() {
66+
return named("getConnection");
67+
}
68+
69+
@Override
70+
public String getMethodsInterceptor() {
71+
return CONNECTION_PROVIDER_GET_CONNECTION_INTERCEPT_CLASS;
72+
}
73+
74+
@Override
75+
public boolean isOverrideArgs() {
76+
return false;
77+
}
78+
}
79+
};
80+
}
81+
}

apm-sniffer/apm-sdk-plugin/jedis-plugins/jedis-4.x-plugin/src/main/resources/skywalking-plugin.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@
1616

1717
jedis-4.x=org.apache.skywalking.apm.plugin.jedis.v4.define.ConnectionInstrumentation
1818
jedis-4.x=org.apache.skywalking.apm.plugin.jedis.v4.define.PipelineInstrumentation
19-
jedis-4.x=org.apache.skywalking.apm.plugin.jedis.v4.define.TransactionConstructorInstrumentation
19+
jedis-4.x=org.apache.skywalking.apm.plugin.jedis.v4.define.TransactionConstructorInstrumentation
20+
jedis-4.x=org.apache.skywalking.apm.plugin.jedis.v4.define.ConnectionProviderInstrumentation

0 commit comments

Comments
 (0)