diff --git a/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/OnCompleteHandler.java b/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/OnCompleteHandler.java index a43c8e2301..8d261f3462 100644 --- a/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/OnCompleteHandler.java +++ b/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/OnCompleteHandler.java @@ -5,26 +5,29 @@ package io.opentelemetry.javaagent.instrumentation.rediscala; -import static io.opentelemetry.javaagent.instrumentation.rediscala.RediscalaClientTracer.tracer; +import static io.opentelemetry.javaagent.instrumentation.rediscala.RediscalaSingletons.instrumenter; import io.opentelemetry.context.Context; +import redis.RedisCommand; import scala.runtime.AbstractFunction1; import scala.util.Try; -public class OnCompleteHandler extends AbstractFunction1, Void> { +public final class OnCompleteHandler extends AbstractFunction1, Void> { private final Context context; + private final RedisCommand request; - public OnCompleteHandler(Context context) { + public OnCompleteHandler(Context context, RedisCommand request) { this.context = context; + this.request = request; } @Override public Void apply(Try result) { + Throwable error = null; if (result.isFailure()) { - tracer().endExceptionally(context, result.failed().get()); - } else { - tracer().end(context); + error = result.failed().get(); } + instrumenter().end(context, request, null, error); return null; } } diff --git a/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/RediscalaAttributesExtractor.java b/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/RediscalaAttributesExtractor.java new file mode 100644 index 0000000000..21a00ec674 --- /dev/null +++ b/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/RediscalaAttributesExtractor.java @@ -0,0 +1,45 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.rediscala; + +import io.opentelemetry.instrumentation.api.instrumenter.db.DbAttributesExtractor; +import io.opentelemetry.instrumentation.api.tracer.ClassNames; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; +import java.util.Locale; +import org.checkerframework.checker.nullness.qual.Nullable; +import redis.RedisCommand; + +final class RediscalaAttributesExtractor extends DbAttributesExtractor, Void> { + @Override + protected String system(RedisCommand redisCommand) { + return SemanticAttributes.DbSystemValues.REDIS; + } + + @Override + protected @Nullable String user(RedisCommand redisCommand) { + return null; + } + + @Override + protected @Nullable String name(RedisCommand redisCommand) { + return null; + } + + @Override + protected @Nullable String connectionString(RedisCommand redisCommand) { + return null; + } + + @Override + protected @Nullable String statement(RedisCommand redisCommand) { + return null; + } + + @Override + protected String operation(RedisCommand redisCommand) { + return ClassNames.simpleName(redisCommand.getClass()).toUpperCase(Locale.ROOT); + } +} diff --git a/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/RediscalaClientTracer.java b/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/RediscalaClientTracer.java deleted file mode 100644 index 055dabb41f..0000000000 --- a/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/RediscalaClientTracer.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.instrumentation.rediscala; - -import io.opentelemetry.instrumentation.api.tracer.ClassNames; -import io.opentelemetry.instrumentation.api.tracer.DatabaseClientTracer; -import io.opentelemetry.instrumentation.api.tracer.net.NetPeerAttributes; -import io.opentelemetry.semconv.trace.attributes.SemanticAttributes.DbSystemValues; -import java.net.InetSocketAddress; -import redis.RedisCommand; - -public class RediscalaClientTracer - extends DatabaseClientTracer, RedisCommand, String> { - - private static final RediscalaClientTracer TRACER = new RediscalaClientTracer(); - - private RediscalaClientTracer() { - super(NetPeerAttributes.INSTANCE); - } - - public static RediscalaClientTracer tracer() { - return TRACER; - } - - @Override - protected String sanitizeStatement(RedisCommand redisCommand) { - return ClassNames.simpleName(redisCommand.getClass()); - } - - @Override - protected String spanName( - RedisCommand connection, RedisCommand statement, String operation) { - return operation; - } - - @Override - protected String dbSystem(RedisCommand redisCommand) { - return DbSystemValues.REDIS; - } - - @Override - protected InetSocketAddress peerAddress(RedisCommand redisCommand) { - return null; - } - - @Override - protected String dbStatement( - RedisCommand connection, RedisCommand command, String operation) { - return operation; - } - - @Override - protected String getInstrumentationName() { - return "io.opentelemetry.rediscala-1.8"; - } -} diff --git a/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/RediscalaSingletons.java b/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/RediscalaSingletons.java new file mode 100644 index 0000000000..271a5463e3 --- /dev/null +++ b/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/RediscalaSingletons.java @@ -0,0 +1,38 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.rediscala; + +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.DbSpanNameExtractor; +import redis.RedisCommand; + +public final class RediscalaSingletons { + + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.rediscala-1.8"; + + private static final Instrumenter, Void> INSTRUMENTER; + + static { + RediscalaAttributesExtractor attributesExtractor = new RediscalaAttributesExtractor(); + SpanNameExtractor> spanNameExtractor = + DbSpanNameExtractor.create(attributesExtractor); + + INSTRUMENTER = + Instrumenter., Void>newBuilder( + GlobalOpenTelemetry.get(), INSTRUMENTATION_NAME, spanNameExtractor) + .addAttributesExtractor(attributesExtractor) + .newInstrumenter(SpanKindExtractor.alwaysClient()); + } + + public static Instrumenter, Void> instrumenter() { + return INSTRUMENTER; + } + + private RediscalaSingletons() {} +} diff --git a/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/RequestInstrumentation.java b/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/RequestInstrumentation.java index 3d9056730a..58ec0d9ffd 100644 --- a/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/RequestInstrumentation.java +++ b/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/RequestInstrumentation.java @@ -8,7 +8,7 @@ package io.opentelemetry.javaagent.instrumentation.rediscala; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasSuperType; import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; -import static io.opentelemetry.javaagent.instrumentation.rediscala.RediscalaClientTracer.tracer; +import static io.opentelemetry.javaagent.instrumentation.rediscala.RediscalaSingletons.instrumenter; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.named; @@ -62,23 +62,34 @@ public class RequestInstrumentation implements TypeInstrumentation { @Advice.Argument(0) RedisCommand cmd, @Advice.Local("otelContext") Context context, @Advice.Local("otelScope") Scope scope) { - context = tracer().startSpan(currentContext(), cmd, cmd); + + Context parentContext = currentContext(); + if (!instrumenter().shouldStart(parentContext, cmd)) { + return; + } + + context = instrumenter().start(parentContext, cmd); scope = context.makeCurrent(); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void stopSpan( + public static void onExit( + @Advice.Argument(0) RedisCommand cmd, @Advice.Local("otelContext") Context context, @Advice.Local("otelScope") Scope scope, @Advice.Thrown Throwable throwable, @Advice.FieldValue("executionContext") ExecutionContext ctx, @Advice.Return(readOnly = false) Future responseFuture) { + + if (scope == null) { + return; + } scope.close(); if (throwable != null) { - tracer().endExceptionally(context, throwable); + instrumenter().end(context, cmd, null, throwable); } else { - responseFuture.onComplete(new OnCompleteHandler(context), ctx); + responseFuture.onComplete(new OnCompleteHandler(context, cmd), ctx); } } } diff --git a/instrumentation/rediscala-1.8/javaagent/src/test/groovy/RediscalaClientTest.groovy b/instrumentation/rediscala-1.8/javaagent/src/test/groovy/RediscalaClientTest.groovy index 4c596b6065..bf11844f97 100644 --- a/instrumentation/rediscala-1.8/javaagent/src/test/groovy/RediscalaClientTest.groovy +++ b/instrumentation/rediscala-1.8/javaagent/src/test/groovy/RediscalaClientTest.groovy @@ -66,11 +66,11 @@ class RediscalaClientTest extends AgentInstrumentationSpecification { assertTraces(1) { trace(0, 1) { span(0) { - name "Set" + name "SET" kind CLIENT attributes { "${SemanticAttributes.DB_SYSTEM.key}" "redis" - "${SemanticAttributes.DB_STATEMENT.key}" "Set" + "${SemanticAttributes.DB_OPERATION.key}" "SET" } } } @@ -79,36 +79,42 @@ class RediscalaClientTest extends AgentInstrumentationSpecification { def "get command"() { when: - def write = redisClient.set("bar", - "baz", - Option.apply(null), - Option.apply(null), - false, - false, - new ByteStringSerializerLowPriority.String$()) - def value = redisClient.get("bar", new ByteStringDeserializerDefault.String$()) + def (write, value) = runWithSpan("parent") { + def w = redisClient.set("bar", + "baz", + Option.apply(null), + Option.apply(null), + false, + false, + new ByteStringSerializerLowPriority.String$()) + def v = redisClient.get("bar", new ByteStringDeserializerDefault.String$()) + return new Tuple(w, v) + } then: Await.result(write, Duration.apply("3 second")) == true Await.result(value, Duration.apply("3 second")) == Option.apply("baz") - assertTraces(2) { - trace(0, 1) { + assertTraces(1) { + trace(0, 3) { span(0) { - name "Set" + name "parent" + } + span(1) { + name "SET" kind CLIENT + childOf span(0) attributes { "${SemanticAttributes.DB_SYSTEM.key}" "redis" - "${SemanticAttributes.DB_STATEMENT.key}" "Set" + "${SemanticAttributes.DB_OPERATION.key}" "SET" } } - } - trace(1, 1) { - span(0) { - name "Get" + span(2) { + name "GET" kind CLIENT + childOf span(0) attributes { "${SemanticAttributes.DB_SYSTEM.key}" "redis" - "${SemanticAttributes.DB_STATEMENT.key}" "Get" + "${SemanticAttributes.DB_OPERATION.key}" "GET" } } }