From d1a74373c5fd9d9f280d066b3919c18c25bfbd2a Mon Sep 17 00:00:00 2001 From: SylvainJuge <763082+SylvainJuge@users.noreply.github.com> Date: Mon, 15 Sep 2025 18:30:53 +0200 Subject: [PATCH] make lettuce indy-ready (#14663) --- .../LettuceAsyncCommandInstrumentation.java | 13 ++--- .../LettuceAsyncCommandsInstrumentation.java | 35 ++++++++---- .../v4_0/LettuceConnectInstrumentation.java | 33 +++++++---- .../v4_0/LettuceInstrumentationModule.java | 9 ++- .../lettuce/v4_0/LettuceSingletons.java | 5 ++ .../LettuceAsyncCommandInstrumentation.java | 14 ++--- .../LettuceAsyncCommandsInstrumentation.java | 57 ++++++++++++------- .../v5_0/LettuceClientInstrumentation.java | 45 +++++++++------ .../v5_0/LettuceInstrumentationModule.java | 9 ++- .../lettuce/v5_0/LettuceSingletons.java | 5 ++ ...ettuceReactiveCommandsInstrumentation.java | 17 ++++-- .../LettuceAsyncCommandInstrumentation.java | 13 ++--- .../v5_1/LettuceInstrumentationModule.java | 9 ++- .../lettuce/v5_1/LettuceSingletons.java | 18 ++++++ 14 files changed, 194 insertions(+), 88 deletions(-) create mode 100644 instrumentation/lettuce/lettuce-5.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_1/LettuceSingletons.java diff --git a/instrumentation/lettuce/lettuce-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v4_0/LettuceAsyncCommandInstrumentation.java b/instrumentation/lettuce/lettuce-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v4_0/LettuceAsyncCommandInstrumentation.java index bd277dfae3..58f4e8e8b6 100644 --- a/instrumentation/lettuce/lettuce-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v4_0/LettuceAsyncCommandInstrumentation.java +++ b/instrumentation/lettuce/lettuce-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v4_0/LettuceAsyncCommandInstrumentation.java @@ -5,6 +5,7 @@ package io.opentelemetry.javaagent.instrumentation.lettuce.v4_0; +import static io.opentelemetry.javaagent.instrumentation.lettuce.v4_0.LettuceSingletons.CONTEXT; import static net.bytebuddy.matcher.ElementMatchers.isConstructor; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; @@ -12,7 +13,6 @@ import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; import com.lambdaworks.redis.protocol.AsyncCommand; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; -import io.opentelemetry.instrumentation.api.util.VirtualField; import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; @@ -44,7 +44,7 @@ public class LettuceAsyncCommandInstrumentation implements TypeInstrumentation { Context context = Java8BytecodeBridge.currentContext(); // get the context that submitted this command and attach it, it will be used to run callbacks context = context.get(LettuceSingletons.COMMAND_CONTEXT_KEY); - VirtualField.find(AsyncCommand.class, Context.class).set(asyncCommand, context); + CONTEXT.set(asyncCommand, context); } } @@ -52,14 +52,13 @@ public class LettuceAsyncCommandInstrumentation implements TypeInstrumentation { public static class RestoreContextAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.This AsyncCommand asyncCommand, @Advice.Local("otelScope") Scope scope) { - Context context = VirtualField.find(AsyncCommand.class, Context.class).get(asyncCommand); - scope = context.makeCurrent(); + public static Scope onEnter(@Advice.This AsyncCommand asyncCommand) { + Context context = CONTEXT.get(asyncCommand); + return context.makeCurrent(); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void onExit(@Advice.Local("otelScope") Scope scope) { + public static void onExit(@Advice.Enter Scope scope) { scope.close(); } } diff --git a/instrumentation/lettuce/lettuce-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v4_0/LettuceAsyncCommandsInstrumentation.java b/instrumentation/lettuce/lettuce-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v4_0/LettuceAsyncCommandsInstrumentation.java index 7e3bce290e..a16468a35c 100644 --- a/instrumentation/lettuce/lettuce-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v4_0/LettuceAsyncCommandsInstrumentation.java +++ b/instrumentation/lettuce/lettuce-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v4_0/LettuceAsyncCommandsInstrumentation.java @@ -17,6 +17,7 @@ import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import javax.annotation.Nullable; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; @@ -40,16 +41,32 @@ public class LettuceAsyncCommandsInstrumentation implements TypeInstrumentation @SuppressWarnings("unused") public static class DispatchAdvice { + public static class AdviceScope { + private final Context context; + private final Scope scope; + + public AdviceScope(Context context, Scope scope) { + this.context = context; + this.scope = scope; + } + + public void end( + @Nullable Throwable throwable, + RedisCommand command, + AsyncCommand asyncCommand) { + scope.close(); + InstrumentationPoints.afterCommand(command, context, throwable, asyncCommand); + } + } + @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(0) RedisCommand command, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { + public static AdviceScope onEnter(@Advice.Argument(0) RedisCommand command) { + Context parentContext = currentContext(); - context = instrumenter().start(parentContext, command); + Context context = instrumenter().start(parentContext, command); // remember the context that called dispatch, it is used in LettuceAsyncCommandInstrumentation context = context.with(LettuceSingletons.COMMAND_CONTEXT_KEY, parentContext); - scope = context.makeCurrent(); + return new AdviceScope(context, context.makeCurrent()); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) @@ -57,10 +74,8 @@ public class LettuceAsyncCommandsInstrumentation implements TypeInstrumentation @Advice.Argument(0) RedisCommand command, @Advice.Thrown Throwable throwable, @Advice.Return AsyncCommand asyncCommand, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - scope.close(); - InstrumentationPoints.afterCommand(command, context, throwable, asyncCommand); + @Advice.Enter AdviceScope adviceScope) { + adviceScope.end(throwable, command, asyncCommand); } } } diff --git a/instrumentation/lettuce/lettuce-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v4_0/LettuceConnectInstrumentation.java b/instrumentation/lettuce/lettuce-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v4_0/LettuceConnectInstrumentation.java index 74741929c5..aa1d094f94 100644 --- a/instrumentation/lettuce/lettuce-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v4_0/LettuceConnectInstrumentation.java +++ b/instrumentation/lettuce/lettuce-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v4_0/LettuceConnectInstrumentation.java @@ -15,6 +15,7 @@ import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import javax.annotation.Nullable; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; @@ -36,23 +37,33 @@ public class LettuceConnectInstrumentation implements TypeInstrumentation { @SuppressWarnings("unused") public static class ConnectAdvice { + public static class AdviceScope { + private final Context context; + private final Scope scope; + + public AdviceScope(Context context, Scope scope) { + this.context = context; + this.scope = scope; + } + + public void end(Throwable throwable, RedisURI redisUri) { + scope.close(); + connectInstrumenter().end(context, redisUri, null, throwable); + } + } + @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(1) RedisURI redisUri, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - context = connectInstrumenter().start(currentContext(), redisUri); - scope = context.makeCurrent(); + public static AdviceScope onEnter(@Advice.Argument(1) RedisURI redisUri) { + Context context = connectInstrumenter().start(currentContext(), redisUri); + return new AdviceScope(context, context.makeCurrent()); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void onExit( @Advice.Argument(1) RedisURI redisUri, - @Advice.Thrown Throwable throwable, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - scope.close(); - connectInstrumenter().end(context, redisUri, null, throwable); + @Advice.Thrown @Nullable Throwable throwable, + @Advice.Enter AdviceScope adviceScope) { + adviceScope.end(throwable, redisUri); } } } diff --git a/instrumentation/lettuce/lettuce-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v4_0/LettuceInstrumentationModule.java b/instrumentation/lettuce/lettuce-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v4_0/LettuceInstrumentationModule.java index 24f721e3d0..1540b8ba5f 100644 --- a/instrumentation/lettuce/lettuce-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v4_0/LettuceInstrumentationModule.java +++ b/instrumentation/lettuce/lettuce-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v4_0/LettuceInstrumentationModule.java @@ -10,10 +10,12 @@ import static java.util.Arrays.asList; import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule; import java.util.List; @AutoService(InstrumentationModule.class) -public class LettuceInstrumentationModule extends InstrumentationModule { +public class LettuceInstrumentationModule extends InstrumentationModule + implements ExperimentalInstrumentationModule { public LettuceInstrumentationModule() { super("lettuce", "lettuce-4.0"); } @@ -25,4 +27,9 @@ public class LettuceInstrumentationModule extends InstrumentationModule { new LettuceAsyncCommandsInstrumentation(), new LettuceConnectInstrumentation()); } + + @Override + public boolean isIndyReady() { + return true; + } } diff --git a/instrumentation/lettuce/lettuce-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v4_0/LettuceSingletons.java b/instrumentation/lettuce/lettuce-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v4_0/LettuceSingletons.java index 3c445a7474..44b55c6133 100644 --- a/instrumentation/lettuce/lettuce-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v4_0/LettuceSingletons.java +++ b/instrumentation/lettuce/lettuce-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v4_0/LettuceSingletons.java @@ -6,6 +6,7 @@ package io.opentelemetry.javaagent.instrumentation.lettuce.v4_0; import com.lambdaworks.redis.RedisURI; +import com.lambdaworks.redis.protocol.AsyncCommand; import com.lambdaworks.redis.protocol.RedisCommand; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.context.Context; @@ -17,6 +18,7 @@ import io.opentelemetry.instrumentation.api.incubator.semconv.net.PeerServiceAtt import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor; import io.opentelemetry.instrumentation.api.semconv.network.ServerAttributesExtractor; +import io.opentelemetry.instrumentation.api.util.VirtualField; import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig; import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig; @@ -29,6 +31,9 @@ public final class LettuceSingletons { public static final ContextKey COMMAND_CONTEXT_KEY = ContextKey.named("opentelemetry-lettuce-v4_0-context-key"); + public static final VirtualField, Context> CONTEXT = + VirtualField.find(AsyncCommand.class, Context.class); + static { LettuceDbAttributesGetter dbAttributesGetter = new LettuceDbAttributesGetter(); diff --git a/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceAsyncCommandInstrumentation.java b/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceAsyncCommandInstrumentation.java index 7662aaf89d..328d4dd5cc 100644 --- a/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceAsyncCommandInstrumentation.java +++ b/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceAsyncCommandInstrumentation.java @@ -5,6 +5,7 @@ package io.opentelemetry.javaagent.instrumentation.lettuce.v5_0; +import static io.opentelemetry.javaagent.instrumentation.lettuce.v5_0.LettuceSingletons.CONTEXT; import static net.bytebuddy.matcher.ElementMatchers.isConstructor; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; @@ -12,7 +13,6 @@ import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; import io.lettuce.core.protocol.AsyncCommand; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; -import io.opentelemetry.instrumentation.api.util.VirtualField; import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; @@ -44,7 +44,7 @@ public class LettuceAsyncCommandInstrumentation implements TypeInstrumentation { Context context = Java8BytecodeBridge.currentContext(); // get the context that submitted this command and attach it, it will be used to run callbacks context = context.get(LettuceSingletons.COMMAND_CONTEXT_KEY); - VirtualField.find(AsyncCommand.class, Context.class).set(asyncCommand, context); + CONTEXT.set(asyncCommand, context); } } @@ -52,14 +52,14 @@ public class LettuceAsyncCommandInstrumentation implements TypeInstrumentation { public static class RestoreContextAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.This AsyncCommand asyncCommand, @Advice.Local("otelScope") Scope scope) { - Context context = VirtualField.find(AsyncCommand.class, Context.class).get(asyncCommand); - scope = context.makeCurrent(); + public static Scope onEnter(@Advice.This AsyncCommand asyncCommand) { + + Context context = CONTEXT.get(asyncCommand); + return context.makeCurrent(); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void onExit(@Advice.Local("otelScope") Scope scope) { + public static void onExit(@Advice.Enter Scope scope) { scope.close(); } } diff --git a/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceAsyncCommandsInstrumentation.java b/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceAsyncCommandsInstrumentation.java index 80f4e7fce9..3b395f5f89 100644 --- a/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceAsyncCommandsInstrumentation.java +++ b/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceAsyncCommandsInstrumentation.java @@ -18,6 +18,7 @@ import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import javax.annotation.Nullable; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; @@ -41,39 +42,53 @@ public class LettuceAsyncCommandsInstrumentation implements TypeInstrumentation @SuppressWarnings("unused") public static class DispatchAdvice { + public static class AdviceScope { + private final Context context; + private final Scope scope; + + public AdviceScope(Context context, Scope scope) { + this.context = context; + this.scope = scope; + } + + public void end( + @Nullable Throwable throwable, + RedisCommand command, + AsyncCommand asyncCommand) { + scope.close(); + + if (throwable != null) { + instrumenter().end(context, command, null, throwable); + return; + } + + // close spans on error or normal completion + if (expectsResponse(command)) { + asyncCommand.handleAsync(new EndCommandAsyncBiFunction<>(context, command)); + } else { + instrumenter().end(context, command, null, null); + } + } + } + @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(0) RedisCommand command, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { + public static AdviceScope onEnter(@Advice.Argument(0) RedisCommand command) { Context parentContext = currentContext(); - context = instrumenter().start(parentContext, command); + Context context = instrumenter().start(parentContext, command); // remember the context that called dispatch, it is used in LettuceAsyncCommandInstrumentation context = context.with(LettuceSingletons.COMMAND_CONTEXT_KEY, parentContext); - scope = context.makeCurrent(); + return new AdviceScope(context, context.makeCurrent()); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void stopSpan( @Advice.Argument(0) RedisCommand command, - @Advice.Thrown Throwable throwable, + @Advice.Thrown @Nullable Throwable throwable, @Advice.Return AsyncCommand asyncCommand, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - scope.close(); + @Advice.Enter AdviceScope adviceScope) { - if (throwable != null) { - instrumenter().end(context, command, null, throwable); - return; - } - - // close spans on error or normal completion - if (expectsResponse(command)) { - asyncCommand.handleAsync(new EndCommandAsyncBiFunction<>(context, command)); - } else { - instrumenter().end(context, command, null, null); - } + adviceScope.end(throwable, command, asyncCommand); } } } diff --git a/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceClientInstrumentation.java b/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceClientInstrumentation.java index a4506a2e21..c8d697023f 100644 --- a/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceClientInstrumentation.java +++ b/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceClientInstrumentation.java @@ -21,6 +21,7 @@ import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import javax.annotation.Nullable; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; @@ -47,29 +48,41 @@ public class LettuceClientInstrumentation implements TypeInstrumentation { @SuppressWarnings("unused") public static class ConnectAdvice { + public static class AdviceScope { + private final Context context; + private final Scope scope; + + public AdviceScope(Context context, Scope scope) { + this.context = context; + this.scope = scope; + } + + public void end( + @Nullable Throwable throwable, RedisURI redisUri, ConnectionFuture connectionFuture) { + + scope.close(); + + if (throwable != null) { + connectInstrumenter().end(context, redisUri, null, throwable); + return; + } + connectionFuture.handleAsync(new EndConnectAsyncBiFunction<>(context, redisUri)); + } + } + @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(1) RedisURI redisUri, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - context = connectInstrumenter().start(currentContext(), redisUri); - scope = context.makeCurrent(); + public static AdviceScope onEnter(@Advice.Argument(1) RedisURI redisUri) { + Context context = connectInstrumenter().start(currentContext(), redisUri); + return new AdviceScope(context, context.makeCurrent()); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void stopSpan( @Advice.Argument(1) RedisURI redisUri, - @Advice.Thrown Throwable throwable, + @Advice.Thrown @Nullable Throwable throwable, @Advice.Return ConnectionFuture connectionFuture, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - scope.close(); - - if (throwable != null) { - connectInstrumenter().end(context, redisUri, null, throwable); - return; - } - connectionFuture.handleAsync(new EndConnectAsyncBiFunction<>(context, redisUri)); + @Advice.Enter AdviceScope adviceScope) { + adviceScope.end(throwable, redisUri, connectionFuture); } } } diff --git a/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceInstrumentationModule.java b/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceInstrumentationModule.java index 7f2eb62aaa..15f438baee 100644 --- a/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceInstrumentationModule.java +++ b/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceInstrumentationModule.java @@ -12,12 +12,14 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule; import io.opentelemetry.javaagent.instrumentation.lettuce.v5_0.rx.LettuceReactiveCommandsInstrumentation; import java.util.List; import net.bytebuddy.matcher.ElementMatcher; @AutoService(InstrumentationModule.class) -public class LettuceInstrumentationModule extends InstrumentationModule { +public class LettuceInstrumentationModule extends InstrumentationModule + implements ExperimentalInstrumentationModule { public LettuceInstrumentationModule() { super("lettuce", "lettuce-5.0"); } @@ -35,4 +37,9 @@ public class LettuceInstrumentationModule extends InstrumentationModule { new LettuceClientInstrumentation(), new LettuceReactiveCommandsInstrumentation()); } + + @Override + public boolean isIndyReady() { + return true; + } } diff --git a/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceSingletons.java b/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceSingletons.java index ac81faa4db..e8661ad8a8 100644 --- a/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceSingletons.java +++ b/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceSingletons.java @@ -6,6 +6,7 @@ package io.opentelemetry.javaagent.instrumentation.lettuce.v5_0; import io.lettuce.core.RedisURI; +import io.lettuce.core.protocol.AsyncCommand; import io.lettuce.core.protocol.RedisCommand; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.context.Context; @@ -17,6 +18,7 @@ import io.opentelemetry.instrumentation.api.incubator.semconv.net.PeerServiceAtt import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor; import io.opentelemetry.instrumentation.api.semconv.network.ServerAttributesExtractor; +import io.opentelemetry.instrumentation.api.util.VirtualField; import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig; import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig; @@ -29,6 +31,9 @@ public final class LettuceSingletons { public static final ContextKey COMMAND_CONTEXT_KEY = ContextKey.named("opentelemetry-lettuce-v5_0-context-key"); + public static final VirtualField, Context> CONTEXT = + VirtualField.find(AsyncCommand.class, Context.class); + static { LettuceDbAttributesGetter dbAttributesGetter = new LettuceDbAttributesGetter(); diff --git a/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/rx/LettuceReactiveCommandsInstrumentation.java b/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/rx/LettuceReactiveCommandsInstrumentation.java index 600557602f..688c44413e 100644 --- a/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/rx/LettuceReactiveCommandsInstrumentation.java +++ b/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/rx/LettuceReactiveCommandsInstrumentation.java @@ -19,6 +19,7 @@ import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import java.util.function.Supplier; import net.bytebuddy.asm.Advice; +import net.bytebuddy.asm.Advice.AssignReturned; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; import org.reactivestreams.Subscription; @@ -61,10 +62,11 @@ public class LettuceReactiveCommandsInstrumentation implements TypeInstrumentati // throwables wouldn't matter here, because no spans have been started due to redis command not // being run until the user subscribes to the Mono publisher + @AssignReturned.ToReturned @Advice.OnMethodExit(suppress = Throwable.class) - public static void monitorSpan( - @Advice.Enter RedisCommand command, - @Advice.Return(readOnly = false) Mono publisher) { + public static Mono monitorSpan( + @Advice.Return Mono originalPublisher, @Advice.Enter RedisCommand command) { + Mono publisher = originalPublisher; boolean finishSpanOnClose = !expectsResponse(command); LettuceMonoDualConsumer mdc = new LettuceMonoDualConsumer<>(command, finishSpanOnClose); @@ -73,6 +75,7 @@ public class LettuceReactiveCommandsInstrumentation implements TypeInstrumentati if (!finishSpanOnClose) { publisher = publisher.doOnSuccessOrError(mdc); } + return publisher; } } @@ -86,10 +89,11 @@ public class LettuceReactiveCommandsInstrumentation implements TypeInstrumentati } // if there is an exception thrown, then don't make spans + @AssignReturned.ToReturned @Advice.OnMethodExit(suppress = Throwable.class) - public static void monitorSpan( - @Advice.Enter RedisCommand command, - @Advice.Return(readOnly = false) Flux publisher) { + public static Flux monitorSpan( + @Advice.Return Flux originalPublisher, @Advice.Enter RedisCommand command) { + Flux publisher = originalPublisher; boolean expectsResponse = expectsResponse(command); LettuceFluxTerminationRunnable handler = @@ -102,6 +106,7 @@ public class LettuceReactiveCommandsInstrumentation implements TypeInstrumentati publisher = publisher.doOnEach(handler); publisher = publisher.doOnCancel(handler); } + return publisher; } } } diff --git a/instrumentation/lettuce/lettuce-5.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_1/LettuceAsyncCommandInstrumentation.java b/instrumentation/lettuce/lettuce-5.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_1/LettuceAsyncCommandInstrumentation.java index 069d077586..e7f8015870 100644 --- a/instrumentation/lettuce/lettuce-5.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_1/LettuceAsyncCommandInstrumentation.java +++ b/instrumentation/lettuce/lettuce-5.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_1/LettuceAsyncCommandInstrumentation.java @@ -5,6 +5,7 @@ package io.opentelemetry.javaagent.instrumentation.lettuce.v5_1; +import static io.opentelemetry.javaagent.instrumentation.lettuce.v5_1.LettuceSingletons.CONTEXT; import static net.bytebuddy.matcher.ElementMatchers.isConstructor; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; @@ -12,7 +13,6 @@ import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; import io.lettuce.core.protocol.AsyncCommand; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; -import io.opentelemetry.instrumentation.api.util.VirtualField; import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; @@ -42,7 +42,7 @@ public class LettuceAsyncCommandInstrumentation implements TypeInstrumentation { @Advice.OnMethodExit(suppress = Throwable.class) public static void saveContext(@Advice.This AsyncCommand asyncCommand) { Context context = Java8BytecodeBridge.currentContext(); - VirtualField.find(AsyncCommand.class, Context.class).set(asyncCommand, context); + CONTEXT.set(asyncCommand, context); } } @@ -50,14 +50,13 @@ public class LettuceAsyncCommandInstrumentation implements TypeInstrumentation { public static class RestoreContextAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.This AsyncCommand asyncCommand, @Advice.Local("otelScope") Scope scope) { - Context context = VirtualField.find(AsyncCommand.class, Context.class).get(asyncCommand); - scope = context.makeCurrent(); + public static Scope onEnter(@Advice.This AsyncCommand asyncCommand) { + Context context = CONTEXT.get(asyncCommand); + return context.makeCurrent(); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void onExit(@Advice.Local("otelScope") Scope scope) { + public static void onExit(@Advice.Enter Scope scope) { scope.close(); } } diff --git a/instrumentation/lettuce/lettuce-5.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_1/LettuceInstrumentationModule.java b/instrumentation/lettuce/lettuce-5.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_1/LettuceInstrumentationModule.java index fb909ced0a..c264c147c5 100644 --- a/instrumentation/lettuce/lettuce-5.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_1/LettuceInstrumentationModule.java +++ b/instrumentation/lettuce/lettuce-5.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_1/LettuceInstrumentationModule.java @@ -11,11 +11,13 @@ import static java.util.Arrays.asList; import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule; import java.util.List; import net.bytebuddy.matcher.ElementMatcher; @AutoService(InstrumentationModule.class) -public class LettuceInstrumentationModule extends InstrumentationModule { +public class LettuceInstrumentationModule extends InstrumentationModule + implements ExperimentalInstrumentationModule { public LettuceInstrumentationModule() { super("lettuce", "lettuce-5.1"); @@ -36,4 +38,9 @@ public class LettuceInstrumentationModule extends InstrumentationModule { return asList( new DefaultClientResourcesInstrumentation(), new LettuceAsyncCommandInstrumentation()); } + + @Override + public boolean isIndyReady() { + return true; + } } diff --git a/instrumentation/lettuce/lettuce-5.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_1/LettuceSingletons.java b/instrumentation/lettuce/lettuce-5.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_1/LettuceSingletons.java new file mode 100644 index 0000000000..31794ee28d --- /dev/null +++ b/instrumentation/lettuce/lettuce-5.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_1/LettuceSingletons.java @@ -0,0 +1,18 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.lettuce.v5_1; + +import io.lettuce.core.protocol.AsyncCommand; +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.api.util.VirtualField; + +public class LettuceSingletons { + + public static final VirtualField, Context> CONTEXT = + VirtualField.find(AsyncCommand.class, Context.class); + + private LettuceSingletons() {} +}