Skip to content

Commit 88d8e63

Browse files
authored
Support to trace redisson lock (#567)
1 parent 7005f2d commit 88d8e63

8 files changed

Lines changed: 303 additions & 1 deletion

File tree

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ Callable {
140140
* Add WebSphere Liberty 23.x plugin
141141
* Add Plugin to support aerospike Java client
142142
* Add ClickHouse parsing to the jdbc-common plugin.
143+
* Support to trace redisson lock
143144

144145
#### Documentation
145146

apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/tag/Tags.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,22 @@ public static final class HTTP {
139139

140140
public static final StringTag SQL_PARAMETERS = new StringTag(19, "db.sql.parameters");
141141

142+
/**
143+
* LOCK_NAME records the lock name such as redisson lock name
144+
*/
145+
public static final StringTag LOCK_NAME = new StringTag(21, "lock.name");
146+
147+
/**
148+
* LEASE_TIME represents the maximum time to hold the lock after it's acquisition
149+
* in redisson plugin,it's unit is ms
150+
*/
151+
public static final StringTag LEASE_TIME = new StringTag(22, "lease.time");
152+
153+
/**
154+
* THREAD_ID records the thread id
155+
*/
156+
public static final StringTag THREAD_ID = new StringTag(23, "thread.id");
157+
142158
/**
143159
* Creates a {@code StringTag} with the given key and cache it, if it's created before, simply return it without
144160
* creating a new one.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
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.redisson.v3;
20+
21+
import org.apache.skywalking.apm.agent.core.context.ContextManager;
22+
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
23+
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
24+
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
25+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
26+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
27+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
28+
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
29+
import org.redisson.api.RLock;
30+
31+
import java.lang.reflect.Method;
32+
import java.util.concurrent.TimeUnit;
33+
34+
public class RedissonHighLevelLockInterceptor implements InstanceMethodsAroundInterceptor {
35+
36+
@Override
37+
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
38+
AbstractSpan span = ContextManager.createLocalSpan("Redisson/LOCK");
39+
span.setComponent(ComponentsDefine.REDISSON);
40+
SpanLayer.asCache(span);
41+
RLock rLock = (RLock) objInst;
42+
Tags.LOCK_NAME.set(span, rLock.getName());
43+
Tags.CACHE_TYPE.set(span, "Redis");
44+
TimeUnit unit = (TimeUnit) allArguments[2];
45+
Tags.LEASE_TIME.set(span, String.valueOf(unit.toMillis((Long) allArguments[1])));
46+
Tags.THREAD_ID.set(span, String.valueOf(allArguments[3]));
47+
}
48+
49+
@Override
50+
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {
51+
ContextManager.stopSpan();
52+
return ret;
53+
}
54+
55+
@Override
56+
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
57+
ContextManager.activeSpan().log(t);
58+
}
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
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.redisson.v3;
20+
21+
import org.apache.skywalking.apm.agent.core.context.ContextManager;
22+
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
23+
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
24+
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
25+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
26+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
27+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
28+
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
29+
import org.redisson.api.RLock;
30+
31+
import java.lang.reflect.Method;
32+
import java.util.concurrent.TimeUnit;
33+
34+
public class RedissonLockInterceptor implements InstanceMethodsAroundInterceptor {
35+
36+
@Override
37+
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
38+
AbstractSpan span = ContextManager.createLocalSpan("Redisson/LOCK");
39+
span.setComponent(ComponentsDefine.REDISSON);
40+
SpanLayer.asCache(span);
41+
RLock rLock = (RLock) objInst;
42+
Tags.LOCK_NAME.set(span, rLock.getName());
43+
Tags.CACHE_TYPE.set(span, "Redis");
44+
TimeUnit unit = (TimeUnit) allArguments[1];
45+
Tags.LEASE_TIME.set(span, String.valueOf(unit.toMillis((Long) allArguments[0])));
46+
Tags.THREAD_ID.set(span, String.valueOf(allArguments[2]));
47+
}
48+
49+
@Override
50+
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {
51+
ContextManager.stopSpan();
52+
return ret;
53+
}
54+
55+
@Override
56+
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
57+
ContextManager.activeSpan().log(t);
58+
}
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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.redisson.v3.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.HierarchyMatch;
28+
import org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch;
29+
import org.apache.skywalking.apm.agent.core.plugin.match.logical.LogicalMatchOperation;
30+
31+
import static net.bytebuddy.matcher.ElementMatchers.named;
32+
import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
33+
34+
public class RedissonLockInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
35+
36+
private static final String REDISSON_LOCK_CLASS = "org.redisson.RedissonLock";
37+
38+
private static final String REDISSON_SPIN_LOCK_CLASS = "org.redisson.RedissonSpinLock";
39+
40+
private static final String REDISSON_LOCK_INTERCEPTOR = "org.apache.skywalking.apm.plugin.redisson.v3.RedissonLockInterceptor";
41+
42+
private static final String REDISSON_HIGH_LEVEL_LOCK_INTERCEPTOR = "org.apache.skywalking.apm.plugin.redisson.v3.RedissonHighLevelLockInterceptor";
43+
44+
@Override
45+
protected ClassMatch enhanceClass() {
46+
return LogicalMatchOperation.or(HierarchyMatch.byHierarchyMatch(REDISSON_LOCK_CLASS), MultiClassNameMatch.byMultiClassMatch(REDISSON_LOCK_CLASS, REDISSON_SPIN_LOCK_CLASS));
47+
}
48+
49+
@Override
50+
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
51+
return new ConstructorInterceptPoint[0];
52+
}
53+
54+
@Override
55+
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
56+
return new InstanceMethodsInterceptPoint[]{
57+
new InstanceMethodsInterceptPoint() {
58+
@Override
59+
public ElementMatcher<MethodDescription> getMethodsMatcher() {
60+
return named("tryLockInnerAsync").and(takesArgumentWithType(1, "java.util.concurrent.TimeUnit"));
61+
}
62+
63+
@Override
64+
public String getMethodsInterceptor() {
65+
return REDISSON_LOCK_INTERCEPTOR;
66+
}
67+
68+
@Override
69+
public boolean isOverrideArgs() {
70+
return false;
71+
}
72+
},
73+
new InstanceMethodsInterceptPoint() {
74+
@Override
75+
public ElementMatcher<MethodDescription> getMethodsMatcher() {
76+
return named("tryLockInnerAsync").and(takesArgumentWithType(2, "java.util.concurrent.TimeUnit"));
77+
}
78+
79+
@Override
80+
public String getMethodsInterceptor() {
81+
return REDISSON_HIGH_LEVEL_LOCK_INTERCEPTOR;
82+
}
83+
84+
@Override
85+
public boolean isOverrideArgs() {
86+
return false;
87+
}
88+
}
89+
};
90+
}
91+
}

apm-sniffer/apm-sdk-plugin/redisson-3.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
redisson-3.x=org.apache.skywalking.apm.plugin.redisson.v3.define.ConnectionManagerInstrumentation
1818
redisson-3.x=org.apache.skywalking.apm.plugin.redisson.v3.define.RedisConnectionInstrumentation
19-
redisson-3.x=org.apache.skywalking.apm.plugin.redisson.v3.define.RedisClientInstrumentation
19+
redisson-3.x=org.apache.skywalking.apm.plugin.redisson.v3.define.RedisClientInstrumentation
20+
redisson-3.x=org.apache.skywalking.apm.plugin.redisson.v3.define.RedissonLockInstrumentation

test/plugin/scenarios/redisson-scenario/config/expectedData.yaml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,70 @@ segmentItems:
5151
- {key: cache.instance, value: not null}
5252
- {key: cache.cmd, value: BATCH_EXECUTE}
5353
skipAnalysis: 'false'
54+
- operationName: Redisson/EVAL
55+
parentSpanId: 3
56+
spanId: nq 0
57+
spanLayer: Cache
58+
startTime: not null
59+
endTime: not null
60+
componentId: 56
61+
isError: false
62+
spanType: Exit
63+
peer: not null
64+
tags:
65+
- { key: cache.type, value: Redis }
66+
- { key: cache.instance, value: not null }
67+
- { key: cache.cmd, value: EVAL }
68+
- { key: cache.key, value: not null }
69+
skipAnalysis: 'false'
70+
- operationName: Redisson/LOCK
71+
parentSpanId: 0
72+
spanId: nq 0
73+
spanLayer: Cache
74+
startTime: not null
75+
endTime: not null
76+
componentId: 56
77+
isError: false
78+
spanType: Local
79+
peer: ''
80+
tags:
81+
- { key: lock.name, value: lock_a }
82+
- { key: cache.type, value: Redis }
83+
- { key: lease.time, value: not null }
84+
- { key: thread.id, value: not null }
85+
skipAnalysis: false
86+
- operationName: Redisson/EVAL
87+
parentSpanId: 5
88+
spanId: nq 0
89+
spanLayer: Cache
90+
startTime: not null
91+
endTime: not null
92+
componentId: 56
93+
isError: false
94+
spanType: Exit
95+
peer: not null
96+
tags:
97+
- { key: cache.type, value: Redis }
98+
- { key: cache.instance, value: not null }
99+
- { key: cache.cmd, value: EVAL }
100+
- { key: cache.key, value: not null }
101+
skipAnalysis: 'false'
102+
- operationName: Redisson/LOCK
103+
parentSpanId: 0
104+
spanId: nq 0
105+
spanLayer: Cache
106+
startTime: not null
107+
endTime: not null
108+
componentId: 56
109+
isError: false
110+
spanType: Local
111+
peer: ''
112+
tags:
113+
- { key: lock.name, value: lock_b }
114+
- { key: cache.type, value: Redis }
115+
- { key: lease.time, value: not null }
116+
- { key: thread.id, value: not null }
117+
skipAnalysis: false
54118
- operationName: GET:/case/redisson-case
55119
parentSpanId: -1
56120
spanId: 0

test/plugin/scenarios/redisson-scenario/src/main/java/test/apache/skywalking/apm/testcase/redisson/controller/CaseController.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.redisson.Redisson;
2424
import org.redisson.api.RBatch;
2525
import org.redisson.api.RBucket;
26+
import org.redisson.api.RLock;
2627
import org.redisson.api.RedissonClient;
2728
import org.redisson.config.Config;
2829
import org.springframework.beans.factory.annotation.Value;
@@ -58,6 +59,16 @@ public String redissonCase() {
5859
batch.getBucket("batch_k_b").setAsync("batch_v_b");
5960
batch.getBucket("batch_k_b").expireAsync(20, TimeUnit.SECONDS);
6061
batch.execute();
62+
63+
RLock lockA = client.getLock("lock_a");
64+
lockA.lock(10L, TimeUnit.SECONDS);
65+
RLock lockB = client.getLock("lock_b");
66+
try {
67+
lockB.tryLock(10L, 20L, TimeUnit.MILLISECONDS);
68+
} catch (InterruptedException e) {
69+
e.printStackTrace();
70+
}
71+
6172
return "Success";
6273
}
6374

0 commit comments

Comments
 (0)