diff --git a/.github/workflows/plugins-jdk17-test.1.yaml b/.github/workflows/plugins-jdk17-test.1.yaml
index 418da87f35..d1c10f8734 100644
--- a/.github/workflows/plugins-jdk17-test.1.yaml
+++ b/.github/workflows/plugins-jdk17-test.1.yaml
@@ -65,6 +65,7 @@ jobs:
- c3p0-0.9.2.x-0.10.x-scenario
- spring-scheduled-6.x-scenario
- caffeine-3.x-scenario
+ - lettuce-webflux-6x-scenario
steps:
- uses: actions/checkout@v2
with:
diff --git a/.github/workflows/plugins-test.1.yaml b/.github/workflows/plugins-test.1.yaml
index 2c012792fc..4f28cfed8c 100644
--- a/.github/workflows/plugins-test.1.yaml
+++ b/.github/workflows/plugins-test.1.yaml
@@ -73,6 +73,7 @@ jobs:
- kotlin-coroutine-scenario
- lettuce-scenario
- lettuce-6.5.x-scenario
+ - lettuce-webflux-5x-scenario
- mongodb-3.x-scenario
- mongodb-4.x-scenario
- netty-socketio-scenario
diff --git a/CHANGES.md b/CHANGES.md
index 979502ce7a..9eaae86646 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -29,6 +29,7 @@ Release Notes.
* Add `eclipse-temurin:25-jre` as another base image.
* Add JDK25 plugin tests for Spring 6.
* Ignore classes starting with "sun.nio.cs" in bytebuddy due to potential class loading deadlock.
+* Added support for Lettuce reactive Redis commands.
All issues and pull requests are [here](https://github.com/apache/skywalking/milestone/242?closed=1)
diff --git a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisChannelWriterInterceptor.java b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisChannelWriterInterceptor.java
index f8b66f1349..5dde7dfcb3 100644
--- a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisChannelWriterInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisChannelWriterInterceptor.java
@@ -57,12 +57,17 @@ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allAr
}
EnhancedInstance enhancedCommand = (EnhancedInstance) spanCarrierCommand;
+ RedisCommandEnhanceInfo redisCommandEnhanceInfo = (RedisCommandEnhanceInfo) enhancedCommand.getSkyWalkingDynamicField();
+
+ if (redisCommandEnhanceInfo == null) {
+ redisCommandEnhanceInfo = new RedisCommandEnhanceInfo();
+ }
+
// command has been handle by another channel writer (cluster or sentinel case)
- if (enhancedCommand.getSkyWalkingDynamicField() != null) {
+ if (redisCommandEnhanceInfo.getSpan() != null) {
//set peer in last channel writer (delegate)
if (peer != null) {
- AbstractSpan span = (AbstractSpan) enhancedCommand.getSkyWalkingDynamicField();
- span.setPeer(peer);
+ redisCommandEnhanceInfo.getSpan().setPeer(peer);
}
return;
}
@@ -82,6 +87,15 @@ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allAr
command = "BATCH_WRITE";
}
AbstractSpan span = ContextManager.createExitSpan(operationName, peer);
+
+ if (redisCommandEnhanceInfo.getSnapshot() != null) {
+ if (!ContextManager.isActive()) {
+ AbstractSpan localSpan = ContextManager.createLocalSpan("RedisReactive/local");
+ localSpan.setComponent(ComponentsDefine.LETTUCE);
+ }
+ ContextManager.continued(redisCommandEnhanceInfo.getSnapshot());
+ }
+
span.setComponent(ComponentsDefine.LETTUCE);
Tags.CACHE_TYPE.set(span, "Redis");
if (StringUtil.isNotEmpty(key)) {
@@ -92,7 +106,7 @@ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allAr
SpanLayer.asCache(span);
span.prepareForAsync();
ContextManager.stopSpan();
- enhancedCommand.setSkyWalkingDynamicField(span);
+ enhancedCommand.setSkyWalkingDynamicField(redisCommandEnhanceInfo.setSpan(span));
}
private String getArgsKey(RedisCommand, ?, ?> redisCommand) {
@@ -124,7 +138,7 @@ public void handleMethodException(EnhancedInstance objInst, Method method, Objec
RedisCommand, ?, ?> redisCommand = getSpanCarrierCommand(allArguments[0]);
if (redisCommand instanceof EnhancedInstance && ((EnhancedInstance) redisCommand).getSkyWalkingDynamicField() != null) {
EnhancedInstance enhancedRedisCommand = (EnhancedInstance) redisCommand;
- AbstractSpan abstractSpan = (AbstractSpan) enhancedRedisCommand.getSkyWalkingDynamicField();
+ AbstractSpan abstractSpan = ((RedisCommandEnhanceInfo) enhancedRedisCommand.getSkyWalkingDynamicField()).getSpan();
enhancedRedisCommand.setSkyWalkingDynamicField(null);
abstractSpan.log(t);
abstractSpan.asyncFinish();
diff --git a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisCommandCancelMethodInterceptor.java b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisCommandCancelMethodInterceptor.java
index 7fb9f3c943..82f4d6e55d 100644
--- a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisCommandCancelMethodInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisCommandCancelMethodInterceptor.java
@@ -37,7 +37,7 @@ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allAr
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) {
if (objInst.getSkyWalkingDynamicField() != null) {
- AbstractSpan span = (AbstractSpan) objInst.getSkyWalkingDynamicField();
+ AbstractSpan span = ((RedisCommandEnhanceInfo) objInst.getSkyWalkingDynamicField()).getSpan();
span.errorOccurred();
span.tag(new StringTag(CANCEL_SIGNAL_TAG), COMMAND_CANCEL_VALUE);
span.asyncFinish();
@@ -49,7 +49,7 @@ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allA
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
if (objInst.getSkyWalkingDynamicField() != null) {
- AbstractSpan span = (AbstractSpan) objInst.getSkyWalkingDynamicField();
+ AbstractSpan span = ((RedisCommandEnhanceInfo) objInst.getSkyWalkingDynamicField()).getSpan();
span.log(t);
}
}
diff --git a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisCommandCompleteExceptionallyMethodInterceptor.java b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisCommandCompleteExceptionallyMethodInterceptor.java
index bdde0712df..022c2622ee 100644
--- a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisCommandCompleteExceptionallyMethodInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisCommandCompleteExceptionallyMethodInterceptor.java
@@ -35,7 +35,7 @@ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allAr
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) {
if (objInst.getSkyWalkingDynamicField() != null) {
Throwable t = (Throwable) allArguments[0];
- AbstractSpan span = (AbstractSpan) objInst.getSkyWalkingDynamicField();
+ AbstractSpan span = ((RedisCommandEnhanceInfo) objInst.getSkyWalkingDynamicField()).getSpan();
span.log(t);
span.asyncFinish();
objInst.setSkyWalkingDynamicField(null);
@@ -46,7 +46,7 @@ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allA
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
if (objInst.getSkyWalkingDynamicField() != null) {
- AbstractSpan span = (AbstractSpan) objInst.getSkyWalkingDynamicField();
+ AbstractSpan span = ((RedisCommandEnhanceInfo) objInst.getSkyWalkingDynamicField()).getSpan();
span.log(t);
}
}
diff --git a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisCommandCompleteMethodInterceptor.java b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisCommandCompleteMethodInterceptor.java
index d2ede33ba7..725f2742bd 100644
--- a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisCommandCompleteMethodInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisCommandCompleteMethodInterceptor.java
@@ -34,7 +34,7 @@ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allAr
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) {
if (objInst.getSkyWalkingDynamicField() != null) {
- AbstractSpan span = (AbstractSpan) objInst.getSkyWalkingDynamicField();
+ AbstractSpan span = ((RedisCommandEnhanceInfo) objInst.getSkyWalkingDynamicField()).getSpan();
span.asyncFinish();
objInst.setSkyWalkingDynamicField(null);
}
@@ -45,7 +45,7 @@ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allA
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
Class>[] argumentsTypes, Throwable t) {
if (objInst.getSkyWalkingDynamicField() != null) {
- AbstractSpan span = (AbstractSpan) objInst.getSkyWalkingDynamicField();
+ AbstractSpan span = ((RedisCommandEnhanceInfo) objInst.getSkyWalkingDynamicField()).getSpan();
span.log(t);
}
}
diff --git a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisCommandEnhanceInfo.java b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisCommandEnhanceInfo.java
new file mode 100644
index 0000000000..45d09599cd
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisCommandEnhanceInfo.java
@@ -0,0 +1,59 @@
+/*
+ * 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.lettuce.common;
+
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+
+/**
+ * RedisCommandEnhanceInfo holds SkyWalking tracing data for Lettuce commands
+ * executed in different asynchronous models.
+ *
+ *
The {@link AbstractSpan} is used for non-reactive (blocking) commands
+ * that are executed asynchronously, where the span needs to be created
+ * at command submission time and finished when the command completes.
+ *
+ *
The {@link ContextSnapshot} is used for reactive commands, where the
+ * tracing context is captured from Reactor {@code Context} and later
+ * continued at subscription or execution time to bridge reactive
+ * boundaries.
+ */
+class RedisCommandEnhanceInfo {
+
+ private AbstractSpan span;
+ private ContextSnapshot snapshot;
+
+ public AbstractSpan getSpan() {
+ return span;
+ }
+
+ public RedisCommandEnhanceInfo setSpan(AbstractSpan span) {
+ this.span = span;
+ return this;
+ }
+
+ public ContextSnapshot getSnapshot() {
+ return snapshot;
+ }
+
+ public RedisCommandEnhanceInfo setSnapshot(ContextSnapshot snapshot) {
+ this.snapshot = snapshot;
+ return this;
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisSubscriptionConstructorInterceptor.java b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisSubscriptionConstructorInterceptor.java
new file mode 100644
index 0000000000..7c79ebde93
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisSubscriptionConstructorInterceptor.java
@@ -0,0 +1,39 @@
+/*
+ * 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.lettuce.common;
+
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
+
+/**
+ * Interceptor for RedisSubscription constructor.
+ *
+ * This interceptor captures the {@link io.lettuce.core.protocol.RedisCommand} instance
+ * at subscription construction time and stores it into SkyWalking dynamic field.
+ *
+ */
+public class RedisSubscriptionConstructorInterceptor implements InstanceConstructorInterceptor {
+
+ @Override
+ public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
+ // allArguments[1] is the RedisCommand passed to the RedisSubscription constructor
+ objInst.setSkyWalkingDynamicField(allArguments[1]);
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisSubscriptionSubscribeMethodInterceptor.java b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisSubscriptionSubscribeMethodInterceptor.java
new file mode 100644
index 0000000000..0ea108a247
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/RedisSubscriptionSubscribeMethodInterceptor.java
@@ -0,0 +1,61 @@
+/*
+ * 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.lettuce.common;
+
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.InstanceMethodsAroundInterceptorV2;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.MethodInvocationContext;
+import reactor.core.CoreSubscriber;
+
+import java.lang.reflect.Method;
+
+/**
+ * Interceptor for {@code RedisPublisher.RedisSubscription#subscribe(Subscriber)} method.
+ *
+ *
+ * This interceptor works together with the constructor interceptor of
+ * {@code RedisSubscription}:
+ *
+ */
+public class RedisSubscriptionSubscribeMethodInterceptor implements InstanceMethodsAroundInterceptorV2 {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInvocationContext context) {
+ if (allArguments[0] instanceof CoreSubscriber) {
+ CoreSubscriber> subscriber = (CoreSubscriber>) allArguments[0];
+ // get ContextSnapshot from reactor context, the snapshot is set to reactor context by any other plugin
+ // such as DispatcherHandlerHandleMethodInterceptor in spring-webflux-5.x-plugin
+ Object skywalkingContextSnapshot = subscriber.currentContext().getOrDefault("SKYWALKING_CONTEXT_SNAPSHOT", null);
+ if (skywalkingContextSnapshot != null) {
+ ((EnhancedInstance) objInst.getSkyWalkingDynamicField()).setSkyWalkingDynamicField(new RedisCommandEnhanceInfo()
+ .setSnapshot((ContextSnapshot) skywalkingContextSnapshot));
+ }
+ }
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret, MethodInvocationContext context) {
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t, MethodInvocationContext context) {
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/define/RedisSubscriptionInstrumentation.java b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/define/RedisSubscriptionInstrumentation.java
new file mode 100644
index 0000000000..7e7ccc7632
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/java/org/apache/skywalking/apm/plugin/lettuce/common/define/RedisSubscriptionInstrumentation.java
@@ -0,0 +1,86 @@
+/*
+ * 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.lettuce.common.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.ClassInstanceMethodsEnhancePluginDefineV2;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.v2.InstanceMethodsInterceptV2Point;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
+import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
+
+/**
+ *
+ */
+public class RedisSubscriptionInstrumentation extends ClassInstanceMethodsEnhancePluginDefineV2 {
+
+ private static final String ENHANCE_CLASS = "io.lettuce.core.RedisPublisher$RedisSubscription";
+
+ private static final String REDIS_SUBSCRIPTION_SUBSCRIBE_METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.lettuce.common.RedisSubscriptionSubscribeMethodInterceptor";
+ private static final String REDIS_SUBSCRIPTION_CONST_METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.lettuce.common.RedisSubscriptionConstructorInterceptor";
+
+ @Override
+ public InstanceMethodsInterceptV2Point[] getInstanceMethodsInterceptV2Points() {
+ return new InstanceMethodsInterceptV2Point[]{
+ new InstanceMethodsInterceptV2Point() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("subscribe");
+ }
+
+ @Override
+ public String getMethodsInterceptorV2() {
+ return REDIS_SUBSCRIPTION_SUBSCRIBE_METHOD_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+
+ @Override
+ public ClassMatch enhanceClass() {
+ return byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any().and(takesArgument(1, named("io.lettuce.core.protocol.RedisCommand")));
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return REDIS_SUBSCRIPTION_CONST_METHOD_INTERCEPTOR;
+ }
+ }
+ };
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/resources/skywalking-plugin.def
index e0521938a7..e17d02461c 100644
--- a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/resources/skywalking-plugin.def
+++ b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/src/main/resources/skywalking-plugin.def
@@ -15,4 +15,5 @@
# limitations under the License.
lettuce-common=org.apache.skywalking.apm.plugin.lettuce.common.define.DefaultEndpointInstrumentation
-lettuce-common=org.apache.skywalking.apm.plugin.lettuce.common.define.RedisCommandInstrumentation
\ No newline at end of file
+lettuce-common=org.apache.skywalking.apm.plugin.lettuce.common.define.RedisCommandInstrumentation
+lettuce-common=org.apache.skywalking.apm.plugin.lettuce.common.define.RedisSubscriptionInstrumentation
\ No newline at end of file
diff --git a/test/plugin/scenarios/lettuce-webflux-5x-scenario/bin/startup.sh b/test/plugin/scenarios/lettuce-webflux-5x-scenario/bin/startup.sh
new file mode 100644
index 0000000000..d719f14162
--- /dev/null
+++ b/test/plugin/scenarios/lettuce-webflux-5x-scenario/bin/startup.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# 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.
+
+home="$(cd "$(dirname $0)"; pwd)"
+
+java -Dredis.host=${REDIS_SERVERS} -jar -Dskywalking.plugin.lettuce.trace_redis_parameters=true ${agent_opts} ${home}/../libs/lettuce-webflux-5x-scenario.jar &
\ No newline at end of file
diff --git a/test/plugin/scenarios/lettuce-webflux-5x-scenario/config/expectedData.yaml b/test/plugin/scenarios/lettuce-webflux-5x-scenario/config/expectedData.yaml
new file mode 100644
index 0000000000..3e9b59d5de
--- /dev/null
+++ b/test/plugin/scenarios/lettuce-webflux-5x-scenario/config/expectedData.yaml
@@ -0,0 +1,119 @@
+# 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.
+segmentItems:
+ - serviceName: lettuce-webflux-5x-scenario
+ segmentSize: nq 0
+ segments:
+ - segmentId: not null
+ spans:
+ - operationName: /case/healthCheck
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: not null
+ endTime: not null
+ componentId: 67
+ isError: false
+ spanType: Entry
+ peer: ''
+ skipAnalysis: false
+ tags:
+ - {key: url, value: 'http://localhost:8080/case/healthCheck'}
+ - {key: http.method, value: HEAD}
+ - {key: http.status_code, value: '200'}
+ - segmentId: not null
+ spans:
+ - operationName: Lettuce/GET
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Cache
+ startTime: not null
+ endTime: not null
+ componentId: 57
+ isError: false
+ spanType: Exit
+ peer: not null
+ skipAnalysis: false
+ tags:
+ - {key: cache.type, value: Redis}
+ - {key: cache.key, value: key}
+ - {key: cache.cmd, value: GET}
+ - {key: cache.op, value: read}
+ refs:
+ - { parentEndpoint: /case/lettuce-case, networkAddress: '', refType: CrossThread,
+ parentSpanId: 0, parentTraceSegmentId: not null, parentServiceInstance: not
+ null, parentService: not null, traceId: not null }
+ - segmentId: not null
+ spans:
+ - operationName: Lettuce/SET
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Cache
+ startTime: not null
+ endTime: not null
+ componentId: 57
+ isError: false
+ spanType: Exit
+ peer: not null
+ skipAnalysis: false
+ tags:
+ - { key: cache.type, value: Redis }
+ - { key: cache.key, value: key0 }
+ - { key: cache.cmd, value: SET }
+ - { key: cache.op, value: write }
+ refs:
+ - { parentEndpoint: /case/lettuce-case, networkAddress: '', refType: CrossThread,
+ parentSpanId: 0, parentTraceSegmentId: not null, parentServiceInstance: not
+ null, parentService: not null, traceId: not null }
+ - segmentId: not null
+ spans:
+ - operationName: Lettuce/SET
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Cache
+ startTime: not null
+ endTime: not null
+ componentId: 57
+ isError: false
+ spanType: Exit
+ peer: not null
+ skipAnalysis: false
+ tags:
+ - { key: cache.type, value: Redis }
+ - { key: cache.key, value: key1 }
+ - { key: cache.cmd, value: SET }
+ - { key: cache.op, value: write }
+ refs:
+ - { parentEndpoint: /case/lettuce-case, networkAddress: '', refType: CrossThread,
+ parentSpanId: 0, parentTraceSegmentId: not null, parentServiceInstance: not
+ null, parentService: not null, traceId: not null }
+ - segmentId: not null
+ spans:
+ - operationName: /case/lettuce-case
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: not null
+ endTime: not null
+ componentId: 67
+ isError: false
+ spanType: Entry
+ peer: ''
+ skipAnalysis: false
+ tags:
+ - {key: url, value: 'http://localhost:8080/case/lettuce-case'}
+ - {key: http.method, value: GET}
+ - {key: http.status_code, value: '200'}
diff --git a/test/plugin/scenarios/lettuce-webflux-5x-scenario/configuration.yml b/test/plugin/scenarios/lettuce-webflux-5x-scenario/configuration.yml
new file mode 100644
index 0000000000..d016d55400
--- /dev/null
+++ b/test/plugin/scenarios/lettuce-webflux-5x-scenario/configuration.yml
@@ -0,0 +1,30 @@
+# 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.
+
+type: jvm
+entryService: http://localhost:8080/case/lettuce-case
+healthCheck: http://localhost:8080/case/healthCheck
+startScript: ./bin/startup.sh
+withPlugins: apm-spring-webflux-5.x-*.jar
+runningMode: with_optional
+environment:
+ - REDIS_SERVERS=redis-server:6379
+depends_on:
+ - redis-server
+dependencies:
+ redis-server:
+ image: redis:3.2.9-alpine
+ hostname: redis-server
diff --git a/test/plugin/scenarios/lettuce-webflux-5x-scenario/pom.xml b/test/plugin/scenarios/lettuce-webflux-5x-scenario/pom.xml
new file mode 100644
index 0000000000..bf393539a2
--- /dev/null
+++ b/test/plugin/scenarios/lettuce-webflux-5x-scenario/pom.xml
@@ -0,0 +1,98 @@
+
+
+
+ 4.0.0
+
+ org.apache.skywalking
+ lettuce-webflux-5x-scenario
+ 5.0.0
+
+
+ UTF-8
+ 1.8
+ 3.8.1
+ 5.1.8.RELEASE
+ ${test.framework.version}
+ 2.1.6.RELEASE
+
+
+ skywalking-lettuce-webflux-5x-scenario
+
+
+
+ io.lettuce
+ lettuce-core
+ ${test.framework.version}
+
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+ ${spring.boot.version}
+
+
+
+
+ lettuce-webflux-5x-scenario
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring.boot.version}
+
+
+
+ repackage
+
+
+
+
+
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+ ${compiler.version}
+ ${compiler.version}
+ ${project.build.sourceEncoding}
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+ assemble
+ package
+
+ single
+
+
+
+ src/main/assembly/assembly.xml
+
+ ./target/
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/plugin/scenarios/lettuce-webflux-5x-scenario/src/main/assembly/assembly.xml b/test/plugin/scenarios/lettuce-webflux-5x-scenario/src/main/assembly/assembly.xml
new file mode 100644
index 0000000000..ffc45011aa
--- /dev/null
+++ b/test/plugin/scenarios/lettuce-webflux-5x-scenario/src/main/assembly/assembly.xml
@@ -0,0 +1,41 @@
+
+
+
+
+ zip
+
+
+
+
+ ./bin
+ 0775
+
+
+
+
+
+ ${project.build.directory}/lettuce-webflux-5x-scenario.jar
+ ./libs
+ 0775
+
+
+
diff --git a/test/plugin/scenarios/lettuce-webflux-5x-scenario/src/main/java/org/apache/skywalking/apm/testcase/lettuce/Application.java b/test/plugin/scenarios/lettuce-webflux-5x-scenario/src/main/java/org/apache/skywalking/apm/testcase/lettuce/Application.java
new file mode 100644
index 0000000000..dae1948397
--- /dev/null
+++ b/test/plugin/scenarios/lettuce-webflux-5x-scenario/src/main/java/org/apache/skywalking/apm/testcase/lettuce/Application.java
@@ -0,0 +1,34 @@
+/*
+ * 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.testcase.lettuce;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ try {
+ SpringApplication.run(Application.class, args);
+ } catch (Exception e) {
+ // Never do this
+ }
+ }
+}
diff --git a/test/plugin/scenarios/lettuce-webflux-5x-scenario/src/main/java/org/apache/skywalking/apm/testcase/lettuce/RedisClientConfig.java b/test/plugin/scenarios/lettuce-webflux-5x-scenario/src/main/java/org/apache/skywalking/apm/testcase/lettuce/RedisClientConfig.java
new file mode 100644
index 0000000000..0898d08338
--- /dev/null
+++ b/test/plugin/scenarios/lettuce-webflux-5x-scenario/src/main/java/org/apache/skywalking/apm/testcase/lettuce/RedisClientConfig.java
@@ -0,0 +1,37 @@
+/*
+ * 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.testcase.lettuce;
+
+import io.lettuce.core.RedisClient;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ *
+ */
+@Configuration
+public class RedisClientConfig {
+
+ @Bean(destroyMethod = "shutdown")
+ public RedisClient redisClient(@Value("${redis.servers:127.0.0.1:6379}") String address) {
+
+ return RedisClient.create("redis://" + address);
+ }
+}
diff --git a/test/plugin/scenarios/lettuce-webflux-5x-scenario/src/main/java/org/apache/skywalking/apm/testcase/lettuce/controller/LettuceReactiveController.java b/test/plugin/scenarios/lettuce-webflux-5x-scenario/src/main/java/org/apache/skywalking/apm/testcase/lettuce/controller/LettuceReactiveController.java
new file mode 100644
index 0000000000..2664bd2713
--- /dev/null
+++ b/test/plugin/scenarios/lettuce-webflux-5x-scenario/src/main/java/org/apache/skywalking/apm/testcase/lettuce/controller/LettuceReactiveController.java
@@ -0,0 +1,68 @@
+/*
+ * 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.testcase.lettuce.controller;
+
+import io.lettuce.core.RedisClient;
+import io.lettuce.core.api.reactive.RedisReactiveCommands;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import javax.annotation.Resource;
+
+@RestController
+@RequestMapping("/case")
+@PropertySource("classpath:application.properties")
+public class LettuceReactiveController {
+
+ @Value("${redis.servers:127.0.0.1:6379}")
+ private String address;
+
+ @Resource
+ private RedisClient redisClient;
+
+ @GetMapping("/lettuce-case")
+ public Mono lettuceCase() {
+
+ return Mono.usingWhen(
+ Mono.fromCallable(() -> redisClient.connect()),
+ connection -> {
+ RedisReactiveCommands cmd = connection.reactive();
+ return cmd.get("key")
+ .then(Flux.concat(
+ cmd.set("key0", "value0"),
+ cmd.set("key1", "value1")
+ ).then())
+ .thenReturn("Success");
+ },
+ connection -> Mono.fromFuture(connection.closeAsync()),
+ connection -> Mono.fromFuture(connection.closeAsync()),
+ connection -> Mono.fromFuture(connection.closeAsync())
+ );
+ }
+
+ @GetMapping("/healthCheck")
+ public Mono healthCheck() {
+ return Mono.just("healthCheck");
+ }
+}
diff --git a/test/plugin/scenarios/lettuce-webflux-5x-scenario/src/main/resources/application.properties b/test/plugin/scenarios/lettuce-webflux-5x-scenario/src/main/resources/application.properties
new file mode 100644
index 0000000000..d3b193de12
--- /dev/null
+++ b/test/plugin/scenarios/lettuce-webflux-5x-scenario/src/main/resources/application.properties
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+#
+server.port=8080
diff --git a/test/plugin/scenarios/lettuce-webflux-5x-scenario/src/main/resources/log4j2.xml b/test/plugin/scenarios/lettuce-webflux-5x-scenario/src/main/resources/log4j2.xml
new file mode 100644
index 0000000000..9849ed5a8a
--- /dev/null
+++ b/test/plugin/scenarios/lettuce-webflux-5x-scenario/src/main/resources/log4j2.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/plugin/scenarios/lettuce-webflux-5x-scenario/support-version.list b/test/plugin/scenarios/lettuce-webflux-5x-scenario/support-version.list
new file mode 100644
index 0000000000..a7e848bbbf
--- /dev/null
+++ b/test/plugin/scenarios/lettuce-webflux-5x-scenario/support-version.list
@@ -0,0 +1,19 @@
+# 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.
+
+5.1.8.RELEASE
+5.2.1.RELEASE
+6.1.4.RELEASE
\ No newline at end of file
diff --git a/test/plugin/scenarios/lettuce-webflux-6x-scenario/bin/startup.sh b/test/plugin/scenarios/lettuce-webflux-6x-scenario/bin/startup.sh
new file mode 100644
index 0000000000..686b12f52a
--- /dev/null
+++ b/test/plugin/scenarios/lettuce-webflux-6x-scenario/bin/startup.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# 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.
+
+home="$(cd "$(dirname $0)"; pwd)"
+
+java -Dredis.host=${REDIS_SERVERS} -jar -Dskywalking.plugin.lettuce.trace_redis_parameters=true ${agent_opts} ${home}/../libs/lettuce-webflux-6x-scenario.jar &
\ No newline at end of file
diff --git a/test/plugin/scenarios/lettuce-webflux-6x-scenario/config/expectedData.yaml b/test/plugin/scenarios/lettuce-webflux-6x-scenario/config/expectedData.yaml
new file mode 100644
index 0000000000..5ccd79aa70
--- /dev/null
+++ b/test/plugin/scenarios/lettuce-webflux-6x-scenario/config/expectedData.yaml
@@ -0,0 +1,119 @@
+# 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.
+segmentItems:
+ - serviceName: lettuce-webflux-6x-scenario
+ segmentSize: nq 0
+ segments:
+ - segmentId: not null
+ spans:
+ - operationName: /case/healthCheck
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: not null
+ endTime: not null
+ componentId: 67
+ isError: false
+ spanType: Entry
+ peer: ''
+ skipAnalysis: false
+ tags:
+ - {key: url, value: 'http://localhost:8080/case/healthCheck'}
+ - {key: http.method, value: HEAD}
+ - {key: http.status_code, value: '200'}
+ - segmentId: not null
+ spans:
+ - operationName: Lettuce/GET
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Cache
+ startTime: not null
+ endTime: not null
+ componentId: 57
+ isError: false
+ spanType: Exit
+ peer: not null
+ skipAnalysis: false
+ tags:
+ - {key: cache.type, value: Redis}
+ - {key: cache.key, value: key}
+ - {key: cache.cmd, value: GET}
+ - {key: cache.op, value: read}
+ refs:
+ - { parentEndpoint: /case/lettuce-case, networkAddress: '', refType: CrossThread,
+ parentSpanId: 0, parentTraceSegmentId: not null, parentServiceInstance: not
+ null, parentService: not null, traceId: not null }
+ - segmentId: not null
+ spans:
+ - operationName: Lettuce/SET
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Cache
+ startTime: not null
+ endTime: not null
+ componentId: 57
+ isError: false
+ spanType: Exit
+ peer: not null
+ skipAnalysis: false
+ tags:
+ - { key: cache.type, value: Redis }
+ - { key: cache.key, value: key0 }
+ - { key: cache.cmd, value: SET }
+ - { key: cache.op, value: write }
+ refs:
+ - { parentEndpoint: /case/lettuce-case, networkAddress: '', refType: CrossThread,
+ parentSpanId: 0, parentTraceSegmentId: not null, parentServiceInstance: not
+ null, parentService: not null, traceId: not null }
+ - segmentId: not null
+ spans:
+ - operationName: Lettuce/SET
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Cache
+ startTime: not null
+ endTime: not null
+ componentId: 57
+ isError: false
+ spanType: Exit
+ peer: not null
+ skipAnalysis: false
+ tags:
+ - { key: cache.type, value: Redis }
+ - { key: cache.key, value: key1 }
+ - { key: cache.cmd, value: SET }
+ - { key: cache.op, value: write }
+ refs:
+ - { parentEndpoint: /case/lettuce-case, networkAddress: '', refType: CrossThread,
+ parentSpanId: 0, parentTraceSegmentId: not null, parentServiceInstance: not
+ null, parentService: not null, traceId: not null }
+ - segmentId: not null
+ spans:
+ - operationName: /case/lettuce-case
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: not null
+ endTime: not null
+ componentId: 67
+ isError: false
+ spanType: Entry
+ peer: ''
+ skipAnalysis: false
+ tags:
+ - {key: url, value: 'http://localhost:8080/case/lettuce-case'}
+ - {key: http.method, value: GET}
+ - {key: http.status_code, value: '200'}
diff --git a/test/plugin/scenarios/lettuce-webflux-6x-scenario/configuration.yml b/test/plugin/scenarios/lettuce-webflux-6x-scenario/configuration.yml
new file mode 100644
index 0000000000..a3eecec7bb
--- /dev/null
+++ b/test/plugin/scenarios/lettuce-webflux-6x-scenario/configuration.yml
@@ -0,0 +1,30 @@
+# 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.
+
+type: jvm
+entryService: http://localhost:8080/case/lettuce-case
+healthCheck: http://localhost:8080/case/healthCheck
+startScript: ./bin/startup.sh
+withPlugins: apm-spring-webflux-6.x-*.jar
+runningMode: with_optional
+environment:
+ - REDIS_SERVERS=redis-server:6379
+depends_on:
+ - redis-server
+dependencies:
+ redis-server:
+ image: redis:3.2.9-alpine
+ hostname: redis-server
diff --git a/test/plugin/scenarios/lettuce-webflux-6x-scenario/pom.xml b/test/plugin/scenarios/lettuce-webflux-6x-scenario/pom.xml
new file mode 100644
index 0000000000..5aa92d35b1
--- /dev/null
+++ b/test/plugin/scenarios/lettuce-webflux-6x-scenario/pom.xml
@@ -0,0 +1,105 @@
+
+
+
+ 4.0.0
+
+ org.apache.skywalking
+ lettuce-webflux-6x-scenario
+ 5.0.0
+
+
+ UTF-8
+ 17
+ 3.8.1
+ 6.4.2.RELEASE
+ ${test.framework.version}
+ 3.0.0
+
+
+ skywalking-lettuce-webflux-6x-scenario
+
+
+
+ io.lettuce
+ lettuce-core
+ ${test.framework.version}
+
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+ ${spring.boot.version}
+
+
+ ch.qos.logback
+ logback-classic
+
+
+
+
+
+
+
+ lettuce-webflux-6x-scenario
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring.boot.version}
+
+
+
+ repackage
+
+
+
+
+
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+ ${compiler.version}
+ ${compiler.version}
+ ${project.build.sourceEncoding}
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+ assemble
+ package
+
+ single
+
+
+
+ src/main/assembly/assembly.xml
+
+ ./target/
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/plugin/scenarios/lettuce-webflux-6x-scenario/src/main/assembly/assembly.xml b/test/plugin/scenarios/lettuce-webflux-6x-scenario/src/main/assembly/assembly.xml
new file mode 100644
index 0000000000..87c9882cab
--- /dev/null
+++ b/test/plugin/scenarios/lettuce-webflux-6x-scenario/src/main/assembly/assembly.xml
@@ -0,0 +1,41 @@
+
+
+
+
+ zip
+
+
+
+
+ ./bin
+ 0775
+
+
+
+
+
+ ${project.build.directory}/lettuce-webflux-6x-scenario.jar
+ ./libs
+ 0775
+
+
+
diff --git a/test/plugin/scenarios/lettuce-webflux-6x-scenario/src/main/java/org/apache/skywalking/apm/testcase/lettuce/Application.java b/test/plugin/scenarios/lettuce-webflux-6x-scenario/src/main/java/org/apache/skywalking/apm/testcase/lettuce/Application.java
new file mode 100644
index 0000000000..dae1948397
--- /dev/null
+++ b/test/plugin/scenarios/lettuce-webflux-6x-scenario/src/main/java/org/apache/skywalking/apm/testcase/lettuce/Application.java
@@ -0,0 +1,34 @@
+/*
+ * 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.testcase.lettuce;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ try {
+ SpringApplication.run(Application.class, args);
+ } catch (Exception e) {
+ // Never do this
+ }
+ }
+}
diff --git a/test/plugin/scenarios/lettuce-webflux-6x-scenario/src/main/java/org/apache/skywalking/apm/testcase/lettuce/RedisClientConfig.java b/test/plugin/scenarios/lettuce-webflux-6x-scenario/src/main/java/org/apache/skywalking/apm/testcase/lettuce/RedisClientConfig.java
new file mode 100644
index 0000000000..0898d08338
--- /dev/null
+++ b/test/plugin/scenarios/lettuce-webflux-6x-scenario/src/main/java/org/apache/skywalking/apm/testcase/lettuce/RedisClientConfig.java
@@ -0,0 +1,37 @@
+/*
+ * 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.testcase.lettuce;
+
+import io.lettuce.core.RedisClient;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ *
+ */
+@Configuration
+public class RedisClientConfig {
+
+ @Bean(destroyMethod = "shutdown")
+ public RedisClient redisClient(@Value("${redis.servers:127.0.0.1:6379}") String address) {
+
+ return RedisClient.create("redis://" + address);
+ }
+}
diff --git a/test/plugin/scenarios/lettuce-webflux-6x-scenario/src/main/java/org/apache/skywalking/apm/testcase/lettuce/controller/LettuceReactiveController.java b/test/plugin/scenarios/lettuce-webflux-6x-scenario/src/main/java/org/apache/skywalking/apm/testcase/lettuce/controller/LettuceReactiveController.java
new file mode 100644
index 0000000000..c10fb7d03f
--- /dev/null
+++ b/test/plugin/scenarios/lettuce-webflux-6x-scenario/src/main/java/org/apache/skywalking/apm/testcase/lettuce/controller/LettuceReactiveController.java
@@ -0,0 +1,65 @@
+/*
+ * 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.testcase.lettuce.controller;
+
+import io.lettuce.core.RedisClient;
+import io.lettuce.core.api.reactive.RedisReactiveCommands;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+@RestController
+@RequestMapping("/case")
+@PropertySource("classpath:application.properties")
+public class LettuceReactiveController {
+
+ @Value("${redis.servers:127.0.0.1:6379}")
+ private String address;
+
+ @Autowired
+ private RedisClient redisClient;
+
+ @GetMapping("/lettuce-case")
+ public Mono lettuceCase() {
+
+ return Mono.usingWhen(
+ Mono.fromCallable(() -> redisClient.connect()),
+ connection -> {
+ RedisReactiveCommands cmd = connection.reactive();
+ return cmd.get("key")
+ .then(Flux.concat(
+ cmd.set("key0", "value0"),
+ cmd.set("key1", "value1")
+ ).then())
+ .thenReturn("Success");
+ },
+ connection -> Mono.fromFuture(connection.closeAsync())
+ );
+ }
+
+ @GetMapping("/healthCheck")
+ public Mono healthCheck() {
+ return Mono.just("healthCheck");
+ }
+}
diff --git a/test/plugin/scenarios/lettuce-webflux-6x-scenario/src/main/resources/application.properties b/test/plugin/scenarios/lettuce-webflux-6x-scenario/src/main/resources/application.properties
new file mode 100644
index 0000000000..afdb52cef7
--- /dev/null
+++ b/test/plugin/scenarios/lettuce-webflux-6x-scenario/src/main/resources/application.properties
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+#
+server.port=8080
\ No newline at end of file
diff --git a/test/plugin/scenarios/lettuce-webflux-6x-scenario/src/main/resources/log4j2.xml b/test/plugin/scenarios/lettuce-webflux-6x-scenario/src/main/resources/log4j2.xml
new file mode 100644
index 0000000000..9849ed5a8a
--- /dev/null
+++ b/test/plugin/scenarios/lettuce-webflux-6x-scenario/src/main/resources/log4j2.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/plugin/scenarios/lettuce-webflux-6x-scenario/support-version.list b/test/plugin/scenarios/lettuce-webflux-6x-scenario/support-version.list
new file mode 100644
index 0000000000..2cba7f3294
--- /dev/null
+++ b/test/plugin/scenarios/lettuce-webflux-6x-scenario/support-version.list
@@ -0,0 +1,20 @@
+# 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.
+
+6.4.2.RELEASE
+6.5.5.RELEASE
+6.6.0.RELEASE
+6.7.1.RELEASE
\ No newline at end of file