make lettuce indy-ready (#14663)

This commit is contained in:
SylvainJuge 2025-09-15 18:30:53 +02:00 committed by GitHub
parent ecdaa63cde
commit d1a74373c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 194 additions and 88 deletions

View File

@ -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();
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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<Context> COMMAND_CONTEXT_KEY =
ContextKey.named("opentelemetry-lettuce-v4_0-context-key");
public static final VirtualField<AsyncCommand<?, ?, ?>, Context> CONTEXT =
VirtualField.find(AsyncCommand.class, Context.class);
static {
LettuceDbAttributesGetter dbAttributesGetter = new LettuceDbAttributesGetter();

View File

@ -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();
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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<Context> COMMAND_CONTEXT_KEY =
ContextKey.named("opentelemetry-lettuce-v5_0-context-key");
public static final VirtualField<AsyncCommand<?, ?, ?>, Context> CONTEXT =
VirtualField.find(AsyncCommand.class, Context.class);
static {
LettuceDbAttributesGetter dbAttributesGetter = new LettuceDbAttributesGetter();

View File

@ -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 <K, V, T> void monitorSpan(
@Advice.Enter RedisCommand<K, V, T> command,
@Advice.Return(readOnly = false) Mono<T> publisher) {
public static <K, V, T> Mono<T> monitorSpan(
@Advice.Return Mono<T> originalPublisher, @Advice.Enter RedisCommand<K, V, T> command) {
Mono<T> publisher = originalPublisher;
boolean finishSpanOnClose = !expectsResponse(command);
LettuceMonoDualConsumer<? super Subscription, T> 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 <K, V, T> void monitorSpan(
@Advice.Enter RedisCommand<K, V, T> command,
@Advice.Return(readOnly = false) Flux<T> publisher) {
public static <K, V, T> Flux<T> monitorSpan(
@Advice.Return Flux<T> originalPublisher, @Advice.Enter RedisCommand<K, V, T> command) {
Flux<T> 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;
}
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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<AsyncCommand<?, ?, ?>, Context> CONTEXT =
VirtualField.find(AsyncCommand.class, Context.class);
private LettuceSingletons() {}
}