Update jedis-3.0 to Instrumenter API
MODIFY
instrumentation/jedis/jedis-3.0/javaagent/jedis-3.0-javaagent.gradle
instrumentation/jedis/jedis-3.0/javaagent/jedis-3.0-javaagent.gradle
@@ -17,6 +17,9 @@ muzzle {
dependencies {
library "redis.clients:jedis:3.0.0"
+ compileOnly "com.google.auto.value:auto-value-annotations"
+ annotationProcessor "com.google.auto.value:auto-value"
+
// ensures jedis-1.4 instrumentation does not load with jedis 3.0+ by failing
// the tests in the event it does. The tests will end up with double spans
testInstrumentation project(':instrumentation:jedis:jedis-1.4:javaagent')

DELETE
instrumentation/jedis/jedis-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jedis/v3_0/JedisClientTracer.java
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.javaagent.instrumentation.jedis.v3_0;
-
-import io.opentelemetry.instrumentation.api.db.RedisCommandSanitizer;
-import io.opentelemetry.instrumentation.api.tracer.DatabaseClientTracer;
-import io.opentelemetry.instrumentation.api.tracer.net.NetPeerAttributes;
-import io.opentelemetry.javaagent.instrumentation.jedis.v3_0.JedisClientTracer.CommandWithArgs;
-import io.opentelemetry.semconv.trace.attributes.SemanticAttributes.DbSystemValues;
-import java.net.InetSocketAddress;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.List;
-import redis.clients.jedis.Connection;
-import redis.clients.jedis.Protocol;
-import redis.clients.jedis.commands.ProtocolCommand;
-
-public class JedisClientTracer extends DatabaseClientTracer<Connection, CommandWithArgs, String> {
- private static final JedisClientTracer TRACER = new JedisClientTracer();
-
- private JedisClientTracer() {
- super(NetPeerAttributes.INSTANCE);
- }
-
- public static JedisClientTracer tracer() {
- return TRACER;
- }
-
- @Override
- protected String sanitizeStatement(CommandWithArgs command) {
- return RedisCommandSanitizer.sanitize(command.getStringCommand(), command.getArgs());
- }
-
- @Override
- protected String spanName(
- Connection connection, CommandWithArgs command, String sanitizedStatement) {
- return command.getStringCommand();
- }
-
- @Override
- protected String dbSystem(Connection connection) {
- return DbSystemValues.REDIS;
- }
-
- @Override
- protected String dbConnectionString(Connection connection) {
- return null;
- }
-
- @Override
- protected InetSocketAddress peerAddress(Connection connection) {
- return new InetSocketAddress(connection.getHost(), connection.getPort());
- }
-
- @Override
- protected String dbStatement(
- Connection connection, CommandWithArgs command, String sanitizedStatement) {
- return sanitizedStatement;
- }
-
- @Override
- protected String getInstrumentationName() {
- return "io.opentelemetry.javaagent.jedis-3.0";
- }
-
- public static final class CommandWithArgs {
- private final ProtocolCommand command;
- private final byte[][] args;
-
- public CommandWithArgs(ProtocolCommand command, byte[][] args) {
- this.command = command;
- this.args = args;
- }
-
- private String getStringCommand() {
- if (command instanceof Protocol.Command) {
- return ((Protocol.Command) command).name();
- } else {
- // Protocol.Command is the only implementation in the Jedis lib as of 3.1 but this will save
- // us if that changes
- return new String(command.getRaw(), StandardCharsets.UTF_8);
- }
- }
-
- private List<?> getArgs() {
- return Arrays.asList(args);
- }
- }
-}

MODIFY
instrumentation/jedis/jedis-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jedis/v3_0/JedisConnectionInstrumentation.java
instrumentation/jedis/jedis-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jedis/v3_0/JedisConnectionInstrumentation.java
package io.opentelemetry.javaagent.instrumentation.jedis.v3_0;
import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
-import static io.opentelemetry.javaagent.instrumentation.jedis.v3_0.JedisClientTracer.tracer;
+import static io.opentelemetry.javaagent.instrumentation.jedis.v3_0.JedisInstrumenters.instrumenter;
+import static java.util.Arrays.asList;
import static net.bytebuddy.matcher.ElementMatchers.is;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.named;
@@ -38,8 +39,7 @@ public class JedisConnectionInstrumentation implements TypeInstrumentation {
.and(takesArgument(0, named("redis.clients.jedis.commands.ProtocolCommand")))
.and(takesArgument(1, is(byte[][].class))),
this.getClass().getName() + "$SendCommandAdvice");
- // FIXME: This instrumentation only incorporates sending the command, not processing the
- // result.
+ // FIXME: This instrumentation only incorporates sending the command, not processing the result.
}
public static class SendCommandAdvice {
@@ -49,32 +49,31 @@ public class JedisConnectionInstrumentation implements TypeInstrumentation {
@Advice.This Connection connection,
@Advice.Argument(0) ProtocolCommand command,
@Advice.Argument(1) byte[][] args,
+ @Advice.Local("otelJedisRequest") JedisRequest request,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
- context =
- tracer()
- .startSpan(
- currentContext(),
- connection,
- new JedisClientTracer.CommandWithArgs(command, args));
+ Context parentContext = currentContext();
+ request = JedisRequest.create(connection, command, asList(args));
+ if (!instrumenter().shouldStart(parentContext, request)) {
+ return;
+ }
+
+ context = instrumenter().start(parentContext, request);
scope = context.makeCurrent();
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void stopSpan(
@Advice.Thrown Throwable throwable,
+ @Advice.Local("otelJedisRequest") JedisRequest request,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
if (scope == null) {
return;
}
- scope.close();
- if (throwable != null) {
- tracer().endExceptionally(context, throwable);
- } else {
- tracer().end(context);
- }
+ scope.close();
+ instrumenter().end(context, request, null, throwable);
}
}
}

ADD
instrumentation/jedis/jedis-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jedis/v3_0/JedisDbAttributesExtractor.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.jedis.v3_0;
+
+import io.opentelemetry.instrumentation.api.instrumenter.db.DbAttributesExtractor;
+import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+final class JedisDbAttributesExtractor extends DbAttributesExtractor<JedisRequest, Void> {
+ @Override
+ protected String system(JedisRequest request) {
+ return SemanticAttributes.DbSystemValues.REDIS;
+ }
+
+ @Override
+ @Nullable
+ protected String user(JedisRequest request) {
+ return null;
+ }
+
+ @Override
+ protected String name(JedisRequest request) {
+ return null;
+ }
+
+ @Override
+ protected String connectionString(JedisRequest request) {
+ return null;
+ }
+
+ @Override
+ protected String statement(JedisRequest request) {
+ return request.getStatement();
+ }
+
+ @Override
+ protected String operation(JedisRequest request) {
+ return request.getOperation();
+ }
+}

ADD
instrumentation/jedis/jedis-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jedis/v3_0/JedisInstrumenters.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.jedis.v3_0;
+
+import io.opentelemetry.api.GlobalOpenTelemetry;
+import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
+import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
+import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
+import io.opentelemetry.instrumentation.api.instrumenter.db.DbAttributesExtractor;
+import io.opentelemetry.instrumentation.api.instrumenter.db.DbSpanNameExtractor;
+import io.opentelemetry.javaagent.instrumentation.api.instrumenter.PeerServiceAttributesExtractor;
+
+public final class JedisInstrumenters {
+ private static final String INSTRUMENTATION_NAME = "io.opentelemetry.javaagent.jedis-3.0";
+
+ private static final Instrumenter<JedisRequest, Void> INSTRUMENTER;
+
+ static {
+ DbAttributesExtractor<JedisRequest, Void> attributesExtractor =
+ new JedisDbAttributesExtractor();
+ SpanNameExtractor<JedisRequest> spanName = DbSpanNameExtractor.create(attributesExtractor);
+ JedisNetAttributesExtractor netAttributesExtractor = new JedisNetAttributesExtractor();
+
+ INSTRUMENTER =
+ Instrumenter.<JedisRequest, Void>newBuilder(
+ GlobalOpenTelemetry.get(), INSTRUMENTATION_NAME, spanName)
+ .addAttributesExtractor(attributesExtractor)
+ .addAttributesExtractor(netAttributesExtractor)
+ .addAttributesExtractor(PeerServiceAttributesExtractor.create(netAttributesExtractor))
+ .newInstrumenter(SpanKindExtractor.alwaysClient());
+ }
+
+ public static Instrumenter<JedisRequest, Void> instrumenter() {
+ return INSTRUMENTER;
+ }
+
+ private JedisInstrumenters() {}
+}

ADD
instrumentation/jedis/jedis-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jedis/v3_0/JedisNetAttributesExtractor.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.jedis.v3_0;
+
+import io.opentelemetry.instrumentation.api.instrumenter.net.NetAttributesExtractor;
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+final class JedisNetAttributesExtractor extends NetAttributesExtractor<JedisRequest, Void> {
+
+ @Override
+ @Nullable
+ public String transport(JedisRequest request) {
+ return null;
+ }
+
+ @Override
+ public String peerName(JedisRequest request, @Nullable Void response) {
+ return request.getConnection().getHost();
+ }
+
+ @Override
+ public Integer peerPort(JedisRequest request, @Nullable Void response) {
+ return request.getConnection().getPort();
+ }
+
+ @Override
+ @Nullable
+ public String peerIp(JedisRequest request, @Nullable Void response) {
+ return null;
+ }
+}

ADD
instrumentation/jedis/jedis-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jedis/v3_0/JedisRequest.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.jedis.v3_0;
+
+import com.google.auto.value.AutoValue;
+import io.opentelemetry.instrumentation.api.db.RedisCommandSanitizer;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import redis.clients.jedis.Connection;
+import redis.clients.jedis.Protocol;
+import redis.clients.jedis.commands.ProtocolCommand;
+
+@AutoValue
+public abstract class JedisRequest {
+
+ public abstract Connection getConnection();
+
+ public abstract ProtocolCommand getCommand();
+
+ public abstract List<byte[]> getArgs();
+
+ public String getOperation() {
+ ProtocolCommand command = getCommand();
+ if (command instanceof Protocol.Command) {
+ return ((Protocol.Command) command).name();
+ } else {
+ // Protocol.Command is the only implementation in the Jedis lib as of 3.1 but this will save
+ // us if that changes
+ return new String(command.getRaw(), StandardCharsets.UTF_8);
+ }
+ }
+
+ public String getStatement() {
+ return RedisCommandSanitizer.sanitize(getOperation(), getArgs());
+ }
+
+ public static JedisRequest create(
+ Connection connection, ProtocolCommand command, List<byte[]> args) {
+ return new AutoValue_JedisRequest(connection, command, args);
+ }
+}

MODIFY
instrumentation/jedis/jedis-3.0/javaagent/src/test/groovy/Jedis30ClientTest.groovy
instrumentation/jedis/jedis-3.0/javaagent/src/test/groovy/Jedis30ClientTest.groovy
@@ -50,7 +50,7 @@ class Jedis30ClientTest extends AgentInstrumentationSpecification {
attributes {
"$SemanticAttributes.DB_SYSTEM.key" "redis"
"$SemanticAttributes.DB_STATEMENT.key" "SET foo ?"
- "$SemanticAttributes.NET_PEER_IP.key" "127.0.0.1"
+ "$SemanticAttributes.DB_OPERATION.key" "SET"
"$SemanticAttributes.NET_PEER_NAME.key" "localhost"
"$SemanticAttributes.NET_PEER_PORT.key" port
}
@@ -75,7 +75,7 @@ class Jedis30ClientTest extends AgentInstrumentationSpecification {
attributes {
"$SemanticAttributes.DB_SYSTEM.key" "redis"
"$SemanticAttributes.DB_STATEMENT.key" "SET foo ?"
- "$SemanticAttributes.NET_PEER_IP.key" "127.0.0.1"
+ "$SemanticAttributes.DB_OPERATION.key" "SET"
"$SemanticAttributes.NET_PEER_NAME.key" "localhost"
"$SemanticAttributes.NET_PEER_PORT.key" port
}
@@ -88,7 +88,7 @@ class Jedis30ClientTest extends AgentInstrumentationSpecification {
attributes {
"$SemanticAttributes.DB_SYSTEM.key" "redis"
"$SemanticAttributes.DB_STATEMENT.key" "GET foo"
- "$SemanticAttributes.NET_PEER_IP.key" "127.0.0.1"
+ "$SemanticAttributes.DB_OPERATION.key" "GET"
"$SemanticAttributes.NET_PEER_NAME.key" "localhost"
"$SemanticAttributes.NET_PEER_PORT.key" port
}
@@ -113,7 +113,7 @@ class Jedis30ClientTest extends AgentInstrumentationSpecification {
attributes {
"$SemanticAttributes.DB_SYSTEM.key" "redis"
"$SemanticAttributes.DB_STATEMENT.key" "SET foo ?"
- "$SemanticAttributes.NET_PEER_IP.key" "127.0.0.1"
+ "$SemanticAttributes.DB_OPERATION.key" "SET"
"$SemanticAttributes.NET_PEER_NAME.key" "localhost"
"$SemanticAttributes.NET_PEER_PORT.key" port
}
@@ -126,7 +126,7 @@ class Jedis30ClientTest extends AgentInstrumentationSpecification {
attributes {
"$SemanticAttributes.DB_SYSTEM.key" "redis"
"$SemanticAttributes.DB_STATEMENT.key" "RANDOMKEY"
- "$SemanticAttributes.NET_PEER_IP.key" "127.0.0.1"
+ "$SemanticAttributes.DB_OPERATION.key" "RANDOMKEY"
"$SemanticAttributes.NET_PEER_NAME.key" "localhost"
"$SemanticAttributes.NET_PEER_PORT.key" port
}

Update jedis-3.0 to Instrumenter API (#3124)