-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add instrumentation for vert.x redis client (open-telemetry#9838)
- Loading branch information
Showing
17 changed files
with
849 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
27 changes: 27 additions & 0 deletions
27
instrumentation/vertx/vertx-redis-client-4.0/javaagent/build.gradle.kts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
plugins { | ||
id("otel.javaagent-instrumentation") | ||
} | ||
|
||
muzzle { | ||
pass { | ||
group.set("io.vertx") | ||
module.set("vertx-redis-client") | ||
versions.set("[4.0.0,)") | ||
assertInverse.set(true) | ||
} | ||
} | ||
|
||
dependencies { | ||
library("io.vertx:vertx-redis-client:4.0.0") | ||
compileOnly("io.vertx:vertx-codegen:4.0.0") | ||
|
||
testInstrumentation(project(":instrumentation:netty:netty-4.1:javaagent")) | ||
|
||
testLibrary("io.vertx:vertx-codegen:4.0.0") | ||
} | ||
|
||
tasks { | ||
withType<Test>().configureEach { | ||
usesService(gradle.sharedServices.registrations["testcontainersBuildService"].service) | ||
} | ||
} |
38 changes: 38 additions & 0 deletions
38
.../opentelemetry/javaagent/instrumentation/vertx/v4_0/redis/CommandImplInstrumentation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.redis; | ||
|
||
import static net.bytebuddy.matcher.ElementMatchers.isConstructor; | ||
import static net.bytebuddy.matcher.ElementMatchers.named; | ||
|
||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; | ||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; | ||
import io.vertx.redis.client.impl.CommandImpl; | ||
import net.bytebuddy.asm.Advice; | ||
import net.bytebuddy.description.type.TypeDescription; | ||
import net.bytebuddy.matcher.ElementMatcher; | ||
|
||
public class CommandImplInstrumentation implements TypeInstrumentation { | ||
@Override | ||
public ElementMatcher<TypeDescription> typeMatcher() { | ||
return named("io.vertx.redis.client.impl.CommandImpl"); | ||
} | ||
|
||
@Override | ||
public void transform(TypeTransformer transformer) { | ||
transformer.applyAdviceToMethod( | ||
isConstructor(), this.getClass().getName() + "$ConstructorAdvice"); | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public static class ConstructorAdvice { | ||
@Advice.OnMethodExit(suppress = Throwable.class) | ||
public static void onExit( | ||
@Advice.This CommandImpl command, @Advice.Argument(0) String commandName) { | ||
VertxRedisClientSingletons.setCommandName(command, commandName); | ||
} | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
...ry/javaagent/instrumentation/vertx/v4_0/redis/RedisConnectionProviderInstrumentation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.redis; | ||
|
||
import static net.bytebuddy.matcher.ElementMatchers.named; | ||
import static net.bytebuddy.matcher.ElementMatchers.not; | ||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument; | ||
|
||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; | ||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; | ||
import io.vertx.redis.client.RedisConnection; | ||
import io.vertx.redis.client.impl.RedisStandaloneConnection; | ||
import io.vertx.redis.client.impl.RedisURI; | ||
import net.bytebuddy.asm.Advice; | ||
import net.bytebuddy.description.type.TypeDescription; | ||
import net.bytebuddy.matcher.ElementMatcher; | ||
|
||
public class RedisConnectionProviderInstrumentation implements TypeInstrumentation { | ||
@Override | ||
public ElementMatcher<TypeDescription> typeMatcher() { | ||
return named("io.vertx.redis.client.impl.RedisConnectionManager$RedisConnectionProvider"); | ||
} | ||
|
||
@Override | ||
public void transform(TypeTransformer transformer) { | ||
// 4.1.0 | ||
transformer.applyAdviceToMethod( | ||
named("init").and(not(takesArgument(0, named("io.vertx.redis.client.RedisConnection")))), | ||
this.getClass().getName() + "$InitAdvice"); | ||
// 4.0.0 | ||
transformer.applyAdviceToMethod( | ||
named("init").and(takesArgument(0, named("io.vertx.redis.client.RedisConnection"))), | ||
this.getClass().getName() + "$InitWithConnectionAdvice"); | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public static class InitAdvice { | ||
@Advice.OnMethodEnter(suppress = Throwable.class) | ||
public static void onEnter(@Advice.FieldValue("redisURI") RedisURI redisUri) { | ||
// for 4.1.0 and later we set RedisURI in a ThreadLocal that is used in advice added in | ||
// RedisStandaloneConnectionInstrumentation that attaches RedisURI to | ||
// RedisStandaloneConnection | ||
VertxRedisClientSingletons.setRedisUriThreadLocal(redisUri); | ||
} | ||
|
||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) | ||
public static void onExit() { | ||
VertxRedisClientSingletons.setRedisUriThreadLocal(null); | ||
} | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public static class InitWithConnectionAdvice { | ||
@Advice.OnMethodEnter(suppress = Throwable.class) | ||
public static void onEnter( | ||
@Advice.Argument(0) RedisConnection connection, | ||
@Advice.FieldValue("redisURI") RedisURI redisUri) { | ||
// for 4.0.x we don't need to use ThreadLocal like in 4.1.0 because in this method we have | ||
// access to both the RedisURI and RedisConnection | ||
if (connection instanceof RedisStandaloneConnection) { | ||
VertxRedisClientSingletons.setRedisUri((RedisStandaloneConnection) connection, redisUri); | ||
} | ||
} | ||
} | ||
} |
103 changes: 103 additions & 0 deletions
103
.../javaagent/instrumentation/vertx/v4_0/redis/RedisStandaloneConnectionInstrumentation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.redis; | ||
|
||
import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext; | ||
import static io.opentelemetry.javaagent.instrumentation.vertx.v4_0.redis.VertxRedisClientSingletons.instrumenter; | ||
import static net.bytebuddy.matcher.ElementMatchers.isConstructor; | ||
import static net.bytebuddy.matcher.ElementMatchers.named; | ||
|
||
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 io.vertx.core.Future; | ||
import io.vertx.core.net.NetSocket; | ||
import io.vertx.redis.client.Request; | ||
import io.vertx.redis.client.Response; | ||
import io.vertx.redis.client.impl.RedisStandaloneConnection; | ||
import io.vertx.redis.client.impl.RedisURI; | ||
import io.vertx.redis.client.impl.RequestUtil; | ||
import net.bytebuddy.asm.Advice; | ||
import net.bytebuddy.description.type.TypeDescription; | ||
import net.bytebuddy.matcher.ElementMatcher; | ||
|
||
public class RedisStandaloneConnectionInstrumentation implements TypeInstrumentation { | ||
@Override | ||
public ElementMatcher<TypeDescription> typeMatcher() { | ||
return named("io.vertx.redis.client.impl.RedisStandaloneConnection"); | ||
} | ||
|
||
@Override | ||
public void transform(TypeTransformer transformer) { | ||
transformer.applyAdviceToMethod(named("send"), this.getClass().getName() + "$SendAdvice"); | ||
transformer.applyAdviceToMethod( | ||
isConstructor(), this.getClass().getName() + "$ConstructorAdvice"); | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public static class SendAdvice { | ||
@Advice.OnMethodEnter(suppress = Throwable.class) | ||
public static void onEnter( | ||
@Advice.This RedisStandaloneConnection connection, | ||
@Advice.Argument(0) Request request, | ||
@Advice.FieldValue("netSocket") NetSocket netSocket, | ||
@Advice.Local("otelRequest") VertxRedisClientRequest otelRequest, | ||
@Advice.Local("otelContext") Context context, | ||
@Advice.Local("otelScope") Scope scope) { | ||
if (request == null) { | ||
return; | ||
} | ||
|
||
String commandName = VertxRedisClientSingletons.getCommandName(request.command()); | ||
RedisURI redisUri = VertxRedisClientSingletons.getRedisUri(connection); | ||
if (commandName == null || redisUri == null) { | ||
return; | ||
} | ||
|
||
otelRequest = | ||
new VertxRedisClientRequest( | ||
commandName, RequestUtil.getArgs(request), redisUri, netSocket); | ||
Context parentContext = currentContext(); | ||
if (!instrumenter().shouldStart(parentContext, otelRequest)) { | ||
return; | ||
} | ||
|
||
context = instrumenter().start(parentContext, otelRequest); | ||
scope = context.makeCurrent(); | ||
} | ||
|
||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) | ||
public static void onExit( | ||
@Advice.Thrown Throwable throwable, | ||
@Advice.Return(readOnly = false) Future<Response> responseFuture, | ||
@Advice.Local("otelRequest") VertxRedisClientRequest otelRequest, | ||
@Advice.Local("otelContext") Context context, | ||
@Advice.Local("otelScope") Scope scope) { | ||
if (scope == null) { | ||
return; | ||
} | ||
|
||
scope.close(); | ||
if (throwable != null) { | ||
instrumenter().end(context, otelRequest, null, throwable); | ||
} else { | ||
responseFuture = | ||
VertxRedisClientSingletons.wrapEndSpan(responseFuture, context, otelRequest); | ||
} | ||
} | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public static class ConstructorAdvice { | ||
@Advice.OnMethodExit(suppress = Throwable.class) | ||
public static void onExit(@Advice.This RedisStandaloneConnection connection) { | ||
// used in 4.1.0, for 4.0.0 it is set in RedisConnectionProviderInstrumentation | ||
VertxRedisClientSingletons.setRedisUri( | ||
connection, VertxRedisClientSingletons.getRedisUriThreadLocal()); | ||
} | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
...metry/javaagent/instrumentation/vertx/v4_0/redis/VertxRedisClientAttributesExtractor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.redis; | ||
|
||
import static io.opentelemetry.instrumentation.api.internal.AttributesExtractorUtil.internalSet; | ||
|
||
import io.opentelemetry.api.common.AttributesBuilder; | ||
import io.opentelemetry.context.Context; | ||
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; | ||
import io.opentelemetry.semconv.SemanticAttributes; | ||
import javax.annotation.Nullable; | ||
|
||
enum VertxRedisClientAttributesExtractor | ||
implements AttributesExtractor<VertxRedisClientRequest, Void> { | ||
INSTANCE; | ||
|
||
@Override | ||
public void onStart( | ||
AttributesBuilder attributes, Context parentContext, VertxRedisClientRequest request) { | ||
internalSet(attributes, SemanticAttributes.DB_REDIS_DATABASE_INDEX, request.getDatabaseIndex()); | ||
} | ||
|
||
@Override | ||
public void onEnd( | ||
AttributesBuilder attributes, | ||
Context context, | ||
VertxRedisClientRequest request, | ||
@Nullable Void unused, | ||
@Nullable Throwable error) {} | ||
} |
54 changes: 54 additions & 0 deletions
54
...elemetry/javaagent/instrumentation/vertx/v4_0/redis/VertxRedisClientAttributesGetter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.redis; | ||
|
||
import io.opentelemetry.instrumentation.api.incubator.semconv.db.DbClientAttributesGetter; | ||
import io.opentelemetry.instrumentation.api.incubator.semconv.db.RedisCommandSanitizer; | ||
import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig; | ||
import io.opentelemetry.semconv.SemanticAttributes; | ||
import javax.annotation.Nullable; | ||
|
||
public enum VertxRedisClientAttributesGetter | ||
implements DbClientAttributesGetter<VertxRedisClientRequest> { | ||
INSTANCE; | ||
|
||
private static final RedisCommandSanitizer sanitizer = | ||
RedisCommandSanitizer.create(CommonConfig.get().isStatementSanitizationEnabled()); | ||
|
||
@Override | ||
public String getSystem(VertxRedisClientRequest request) { | ||
return SemanticAttributes.DbSystemValues.REDIS; | ||
} | ||
|
||
@Override | ||
@Nullable | ||
public String getUser(VertxRedisClientRequest request) { | ||
return request.getUser(); | ||
} | ||
|
||
@Override | ||
@Nullable | ||
public String getName(VertxRedisClientRequest request) { | ||
return null; | ||
} | ||
|
||
@Override | ||
@Nullable | ||
public String getConnectionString(VertxRedisClientRequest request) { | ||
return request.getConnectionString(); | ||
} | ||
|
||
@Override | ||
public String getStatement(VertxRedisClientRequest request) { | ||
return sanitizer.sanitize(request.getCommand(), request.getArgs()); | ||
} | ||
|
||
@Nullable | ||
@Override | ||
public String getOperation(VertxRedisClientRequest request) { | ||
return request.getCommand(); | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
...try/javaagent/instrumentation/vertx/v4_0/redis/VertxRedisClientInstrumentationModule.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.redis; | ||
|
||
import static java.util.Arrays.asList; | ||
import static java.util.Collections.singletonList; | ||
|
||
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 VertxRedisClientInstrumentationModule extends InstrumentationModule | ||
implements ExperimentalInstrumentationModule { | ||
|
||
public VertxRedisClientInstrumentationModule() { | ||
super("vertx-redis-client", "vertx-redis-client-4.0", "vertx"); | ||
} | ||
|
||
@Override | ||
public boolean isHelperClass(String className) { | ||
return "io.vertx.redis.client.impl.RequestUtil".equals(className); | ||
} | ||
|
||
@Override | ||
public List<String> injectedClassNames() { | ||
return singletonList("io.vertx.redis.client.impl.RequestUtil"); | ||
} | ||
|
||
@Override | ||
public List<TypeInstrumentation> typeInstrumentations() { | ||
return asList( | ||
new RedisStandaloneConnectionInstrumentation(), | ||
new RedisConnectionProviderInstrumentation(), | ||
new CommandImplInstrumentation()); | ||
} | ||
} |
Oops, something went wrong.