Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
Expand Down Expand Up @@ -980,7 +979,7 @@ void testGetConnection(
trace -> {
List<Consumer<SpanDataAssert>> assertions =
new ArrayList<>(
Arrays.asList(
asList(
span1 -> span1.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
span1 ->
span1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.api.trace.TracerBuilder;
import io.opentelemetry.instrumentation.api.incubator.semconv.db.RedisCommandSanitizer;
import io.opentelemetry.instrumentation.api.instrumenter.OperationListener;
import io.opentelemetry.instrumentation.api.internal.EmbeddedInstrumentationProperties;

/** Entrypoint for instrumenting Lettuce or clients. */
Expand All @@ -31,8 +32,13 @@ public static LettuceTelemetryBuilder builder(OpenTelemetry openTelemetry) {

private final Tracer tracer;
private final RedisCommandSanitizer sanitizer;
private final OperationListener metrics;

LettuceTelemetry(OpenTelemetry openTelemetry, boolean statementSanitizationEnabled) {
LettuceTelemetry(
OpenTelemetry openTelemetry,
boolean statementSanitizationEnabled,
OperationListener metrics) {
this.metrics = metrics;
TracerBuilder tracerBuilder = openTelemetry.tracerBuilder(INSTRUMENTATION_NAME);
String version = EmbeddedInstrumentationProperties.findVersion(INSTRUMENTATION_NAME);
if (version != null) {
Expand All @@ -47,6 +53,6 @@ public static LettuceTelemetryBuilder builder(OpenTelemetry openTelemetry) {
* io.lettuce.core.resource.ClientResources.Builder#tracing(Tracing)}.
*/
public Tracing newTracing() {
return new OpenTelemetryTracing(tracer, sanitizer);
return new OpenTelemetryTracing(tracer, sanitizer, metrics);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@

package io.opentelemetry.instrumentation.lettuce.v5_1;

import static io.opentelemetry.instrumentation.lettuce.v5_1.LettuceTelemetry.INSTRUMENTATION_NAME;

import com.google.errorprone.annotations.CanIgnoreReturnValue;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.instrumentation.api.incubator.semconv.db.DbClientMetrics;

/** A builder of {@link LettuceTelemetry}. */
public final class LettuceTelemetryBuilder {
Expand Down Expand Up @@ -36,6 +39,9 @@ public LettuceTelemetryBuilder setStatementSanitizationEnabled(
* LettuceTelemetryBuilder}.
*/
public LettuceTelemetry build() {
return new LettuceTelemetry(openTelemetry, statementSanitizationEnabled);
return new LettuceTelemetry(
openTelemetry,
statementSanitizationEnabled,
DbClientMetrics.get().create(openTelemetry.getMeterProvider().get(INSTRUMENTATION_NAME)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import io.opentelemetry.context.Context;
import io.opentelemetry.instrumentation.api.incubator.semconv.db.RedisCommandSanitizer;
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.OperationListener;
import io.opentelemetry.instrumentation.api.internal.SemconvStability;
import io.opentelemetry.instrumentation.api.semconv.network.NetworkAttributesExtractor;
import io.opentelemetry.instrumentation.api.semconv.network.ServerAttributesExtractor;
Expand Down Expand Up @@ -54,8 +55,11 @@ final class OpenTelemetryTracing implements Tracing {
NetworkAttributesExtractor.create(new LettuceServerAttributesGetter());
private final TracerProvider tracerProvider;

OpenTelemetryTracing(io.opentelemetry.api.trace.Tracer tracer, RedisCommandSanitizer sanitizer) {
this.tracerProvider = new OpenTelemetryTracerProvider(tracer, sanitizer);
OpenTelemetryTracing(
io.opentelemetry.api.trace.Tracer tracer,
RedisCommandSanitizer sanitizer,
OperationListener metrics) {
this.tracerProvider = new OpenTelemetryTracerProvider(tracer, sanitizer, metrics);
}

@Override
Expand Down Expand Up @@ -93,8 +97,10 @@ private static class OpenTelemetryTracerProvider implements TracerProvider {
private final Tracer openTelemetryTracer;

OpenTelemetryTracerProvider(
io.opentelemetry.api.trace.Tracer tracer, RedisCommandSanitizer sanitizer) {
openTelemetryTracer = new OpenTelemetryTracer(tracer, sanitizer);
io.opentelemetry.api.trace.Tracer tracer,
RedisCommandSanitizer sanitizer,
OperationListener metrics) {
openTelemetryTracer = new OpenTelemetryTracer(tracer, sanitizer, metrics);
}

@Override
Expand Down Expand Up @@ -135,10 +141,15 @@ private static class OpenTelemetryTracer extends Tracer {

private final io.opentelemetry.api.trace.Tracer tracer;
private final RedisCommandSanitizer sanitizer;
private final OperationListener metrics;

OpenTelemetryTracer(io.opentelemetry.api.trace.Tracer tracer, RedisCommandSanitizer sanitizer) {
OpenTelemetryTracer(
io.opentelemetry.api.trace.Tracer tracer,
RedisCommandSanitizer sanitizer,
OperationListener metrics) {
this.tracer = tracer;
this.sanitizer = sanitizer;
this.metrics = metrics;
}

@Override
Expand All @@ -165,7 +176,7 @@ private OpenTelemetrySpan nextSpan(Context context) {
.setSpanKind(SpanKind.CLIENT)
.setParent(context)
.setAttribute(DB_SYSTEM, REDIS);
return new OpenTelemetrySpan(context, spanBuilder, sanitizer);
return new OpenTelemetrySpan(context, spanBuilder, sanitizer, metrics);
}
}

Expand All @@ -178,18 +189,26 @@ private static class OpenTelemetrySpan extends Tracer.Span {
private final Context context;
private final SpanBuilder spanBuilder;
private final RedisCommandSanitizer sanitizer;
private final OperationListener metrics;

@Nullable private String name;
@Nullable private List<Object> events;
@Nullable private Throwable error;
@Nullable private Span span;
private long spanStartNanos;
private final AttributesBuilder attributesBuilder = Attributes.builder().put(DB_SYSTEM, REDIS);
@Nullable private List<String> argsList;
@Nullable private String argsString;

OpenTelemetrySpan(Context context, SpanBuilder spanBuilder, RedisCommandSanitizer sanitizer) {
OpenTelemetrySpan(
Context context,
SpanBuilder spanBuilder,
RedisCommandSanitizer sanitizer,
OperationListener metrics) {
this.context = context;
this.spanBuilder = spanBuilder;
this.sanitizer = sanitizer;
this.metrics = metrics;
}

@Override
Expand Down Expand Up @@ -218,11 +237,13 @@ private void fillEndpoint(OpenTelemetryEndpoint endpoint) {
Context currentContext = span == null ? context : context.with(span);
serverAttributesExtractor.onStart(attributesBuilder, currentContext, endpoint);
networkAttributesExtractor.onEnd(attributesBuilder, currentContext, endpoint, null, null);
Attributes attributes = attributesBuilder.build();
if (span != null) {
span.setAllAttributes(attributesBuilder.build());
span.setAllAttributes(attributes);
} else {
spanBuilder.setAllAttributes(attributesBuilder.build());
spanBuilder.setAllAttributes(attributes);
}
this.attributesBuilder.putAll(attributes);
}

// Added and called in 6.0+
Expand All @@ -231,6 +252,7 @@ private void fillEndpoint(OpenTelemetryEndpoint endpoint) {
@SuppressWarnings("UnusedMethod")
public synchronized Tracer.Span start(RedisCommand<?, ?, ?> command) {
start();
long startNanos = System.nanoTime();

Span span = this.span;
if (span == null) {
Expand Down Expand Up @@ -258,7 +280,7 @@ public synchronized Tracer.Span start(RedisCommand<?, ?, ?> command) {
}
}

finish(span);
finish(span, startNanos);
});
}

Expand All @@ -270,6 +292,7 @@ public synchronized Tracer.Span start(RedisCommand<?, ?, ?> command) {
@CanIgnoreReturnValue
public synchronized Tracer.Span start() {
span = spanBuilder.startSpan();
spanStartNanos = System.nanoTime();
if (name != null) {
span.updateName(name);
}
Expand Down Expand Up @@ -330,6 +353,7 @@ public synchronized Tracer.Span tag(String key, String value) {
} else {
spanBuilder.setAttribute(key, value);
}
attributesBuilder.put(key, value);
return this;
}

Expand All @@ -347,16 +371,20 @@ public synchronized Tracer.Span error(Throwable throwable) {
@Override
public synchronized void finish() {
if (span != null) {
finish(span);
finish(span, spanStartNanos);
}
}

private void finish(Span span) {
private void finish(Span span, long startTime) {
if (name != null) {
String statement =
sanitizer.sanitize(name, argsList != null ? argsList : splitArgs(argsString));
if (SemconvStability.emitStableDatabaseSemconv()) {
span.setAttribute(DB_QUERY_TEXT, statement);
metrics.onEnd(
metrics.onStart(Context.current(), Attributes.empty(), startTime),
attributesBuilder.build(),
System.nanoTime());
}
if (SemconvStability.emitOldDatabaseSemconv()) {
span.setAttribute(DB_STATEMENT, statement);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package io.opentelemetry.instrumentation.lettuce.v5_1;

import static io.opentelemetry.instrumentation.testing.junit.db.DbClientMetricsTestUtil.assertDurationMetric;
import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStable;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies;
Expand All @@ -13,9 +14,11 @@
import static io.opentelemetry.semconv.NetworkAttributes.NETWORK_TYPE;
import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS;
import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT;
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_NAMESPACE;
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_STATEMENT;
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SYSTEM;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;

Expand All @@ -31,7 +34,9 @@
import io.opentelemetry.instrumentation.test.utils.PortUtils;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
Expand Down Expand Up @@ -135,6 +140,20 @@ void testSetCommand() {
.hasEventsSatisfyingExactly(
event -> event.hasName("redis.encode.start"),
event -> event.hasName("redis.encode.end"))));

List<AttributeKey<?>> expected =
new ArrayList<>(
asList(
DB_SYSTEM, SERVER_ADDRESS, SERVER_PORT, NETWORK_PEER_ADDRESS, NETWORK_PEER_PORT));
if (Boolean.getBoolean("testLatestDeps")) {
expected.add(DB_NAMESPACE);
}
assertDurationMetric(testing(), "io.opentelemetry.lettuce-5.1", toArray(expected));
}

@SuppressWarnings("rawtypes")
private static AttributeKey[] toArray(List<AttributeKey<?>> expected) {
return expected.toArray(new AttributeKey[0]);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitStableDatabaseSemconv;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SYSTEM;

import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
Expand All @@ -19,6 +20,9 @@ public static void assertDurationMetric(
InstrumentationExtension testing,
String instrumentationName,
AttributeKey<?>... expectedKeys) {
// db.system is required - see
// https://opentelemetry.io/docs/specs/semconv/database/database-metrics/#metric-dbclientoperationduration
assertThat(expectedKeys).extracting(AttributeKey::getKey).contains(DB_SYSTEM.getKey());
Comment on lines +23 to +25
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

if (!emitStableDatabaseSemconv()) {
return;
}
Expand Down
Loading