Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

package io.opentelemetry.javaagent.instrumentation.lettuce.v5_1;

import static io.opentelemetry.instrumentation.api.internal.OperationMetricsUtil.NOOP_OPERATION_LISTENER;

import io.lettuce.core.tracing.Tracing;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.lettuce.v5_1.LettuceTelemetry;
Expand All @@ -15,6 +17,9 @@ public final class TracingHolder {
public static final Tracing TRACING =
LettuceTelemetry.builder(GlobalOpenTelemetry.get())
.setStatementSanitizationEnabled(AgentCommonConfig.get().isStatementSanitizationEnabled())
.setMetrics(
meter ->
NOOP_OPERATION_LISTENER) // javaagent uses bytecode instrumentation for metrics
.build()
.newTracing();

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,18 +5,24 @@

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;
import io.opentelemetry.instrumentation.api.instrumenter.OperationMetrics;

/** A builder of {@link LettuceTelemetry}. */
public final class LettuceTelemetryBuilder {

private final OpenTelemetry openTelemetry;

private boolean statementSanitizationEnabled = true;
private OperationMetrics metrics;

LettuceTelemetryBuilder(OpenTelemetry openTelemetry) {
this.openTelemetry = openTelemetry;
metrics = DbClientMetrics.get();
}

/**
Expand All @@ -31,11 +37,20 @@ public LettuceTelemetryBuilder setStatementSanitizationEnabled(
return this;
}

@CanIgnoreReturnValue
public LettuceTelemetryBuilder setMetrics(OperationMetrics metrics) {
this.metrics = metrics;
return this;
}

/**
* Returns a new {@link LettuceTelemetry} with the settings of this {@link
* LettuceTelemetryBuilder}.
*/
public LettuceTelemetry build() {
return new LettuceTelemetry(openTelemetry, statementSanitizationEnabled);
return new LettuceTelemetry(
openTelemetry,
statementSanitizationEnabled,
metrics.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 spanStartTime;
private final AttributesBuilder attributesBuilder = Attributes.builder();
@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);
}
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 startTime = 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, startTime);
});
}

Expand All @@ -270,6 +292,7 @@ public synchronized Tracer.Span start(RedisCommand<?, ?, ?> command) {
@CanIgnoreReturnValue
public synchronized Tracer.Span start() {
span = spanBuilder.startSpan();
spanStartTime = 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,18 @@ public synchronized Tracer.Span error(Throwable throwable) {
@Override
public synchronized void finish() {
if (span != null) {
finish(span);
finish(span, spanStartTime);
}
}

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);
Context c = metrics.onStart(Context.current(), Attributes.empty(), startTime);
metrics.onEnd(c, 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,6 +14,9 @@
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_COLLECTION_NAME;
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_NAMESPACE;
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_OPERATION_NAME;
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;
Expand Down Expand Up @@ -135,6 +139,14 @@ void testSetCommand() {
.hasEventsSatisfyingExactly(
event -> event.hasName("redis.encode.start"),
event -> event.hasName("redis.encode.end"))));

assertDurationMetric(
testing(),
"io.opentelemetry.lettuce-5.1",
DB_SYSTEM,
DB_COLLECTION_NAME,
DB_NAMESPACE,
DB_OPERATION_NAME);
}

@Test
Expand Down
Loading