Skip to content

Commit 7716367

Browse files
committed
add lettuce db client metrics
1 parent e42c213 commit 7716367

File tree

5 files changed

+83
-15
lines changed

5 files changed

+83
-15
lines changed

instrumentation/lettuce/lettuce-5.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_1/TracingHolder.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

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

8+
import static io.opentelemetry.instrumentation.api.internal.OperationMetricsUtil.NOOP_OPERATION_LISTENER;
9+
810
import io.lettuce.core.tracing.Tracing;
911
import io.opentelemetry.api.GlobalOpenTelemetry;
1012
import io.opentelemetry.instrumentation.lettuce.v5_1.LettuceTelemetry;
@@ -15,6 +17,9 @@ public final class TracingHolder {
1517
public static final Tracing TRACING =
1618
LettuceTelemetry.builder(GlobalOpenTelemetry.get())
1719
.setStatementSanitizationEnabled(AgentCommonConfig.get().isStatementSanitizationEnabled())
20+
.setMetrics(
21+
meter ->
22+
NOOP_OPERATION_LISTENER) // javaagent uses bytecode instrumentation for metrics
1823
.build()
1924
.newTracing();
2025

instrumentation/lettuce/lettuce-5.1/library/src/main/java/io/opentelemetry/instrumentation/lettuce/v5_1/LettuceTelemetry.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import io.opentelemetry.api.trace.Tracer;
1111
import io.opentelemetry.api.trace.TracerBuilder;
1212
import io.opentelemetry.instrumentation.api.incubator.semconv.db.RedisCommandSanitizer;
13+
import io.opentelemetry.instrumentation.api.instrumenter.OperationListener;
1314
import io.opentelemetry.instrumentation.api.internal.EmbeddedInstrumentationProperties;
1415

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

3233
private final Tracer tracer;
3334
private final RedisCommandSanitizer sanitizer;
35+
private final OperationListener metrics;
3436

35-
LettuceTelemetry(OpenTelemetry openTelemetry, boolean statementSanitizationEnabled) {
37+
LettuceTelemetry(
38+
OpenTelemetry openTelemetry,
39+
boolean statementSanitizationEnabled,
40+
OperationListener metrics) {
41+
this.metrics = metrics;
3642
TracerBuilder tracerBuilder = openTelemetry.tracerBuilder(INSTRUMENTATION_NAME);
3743
String version = EmbeddedInstrumentationProperties.findVersion(INSTRUMENTATION_NAME);
3844
if (version != null) {
@@ -47,6 +53,6 @@ public static LettuceTelemetryBuilder builder(OpenTelemetry openTelemetry) {
4753
* io.lettuce.core.resource.ClientResources.Builder#tracing(Tracing)}.
4854
*/
4955
public Tracing newTracing() {
50-
return new OpenTelemetryTracing(tracer, sanitizer);
56+
return new OpenTelemetryTracing(tracer, sanitizer, metrics);
5157
}
5258
}

instrumentation/lettuce/lettuce-5.1/library/src/main/java/io/opentelemetry/instrumentation/lettuce/v5_1/LettuceTelemetryBuilder.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,24 @@
55

66
package io.opentelemetry.instrumentation.lettuce.v5_1;
77

8+
import static io.opentelemetry.instrumentation.lettuce.v5_1.LettuceTelemetry.INSTRUMENTATION_NAME;
9+
810
import com.google.errorprone.annotations.CanIgnoreReturnValue;
911
import io.opentelemetry.api.OpenTelemetry;
12+
import io.opentelemetry.instrumentation.api.incubator.semconv.db.DbClientMetrics;
13+
import io.opentelemetry.instrumentation.api.instrumenter.OperationMetrics;
1014

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

1418
private final OpenTelemetry openTelemetry;
1519

1620
private boolean statementSanitizationEnabled = true;
21+
private OperationMetrics metrics;
1722

1823
LettuceTelemetryBuilder(OpenTelemetry openTelemetry) {
1924
this.openTelemetry = openTelemetry;
25+
metrics = DbClientMetrics.get();
2026
}
2127

2228
/**
@@ -31,11 +37,20 @@ public LettuceTelemetryBuilder setStatementSanitizationEnabled(
3137
return this;
3238
}
3339

40+
@CanIgnoreReturnValue
41+
public LettuceTelemetryBuilder setMetrics(OperationMetrics metrics) {
42+
this.metrics = metrics;
43+
return this;
44+
}
45+
3446
/**
3547
* Returns a new {@link LettuceTelemetry} with the settings of this {@link
3648
* LettuceTelemetryBuilder}.
3749
*/
3850
public LettuceTelemetry build() {
39-
return new LettuceTelemetry(openTelemetry, statementSanitizationEnabled);
51+
return new LettuceTelemetry(
52+
openTelemetry,
53+
statementSanitizationEnabled,
54+
metrics.create(openTelemetry.getMeterProvider().get(INSTRUMENTATION_NAME)));
4055
}
4156
}

instrumentation/lettuce/lettuce-5.1/library/src/main/java/io/opentelemetry/instrumentation/lettuce/v5_1/OpenTelemetryTracing.java

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import io.opentelemetry.context.Context;
2828
import io.opentelemetry.instrumentation.api.incubator.semconv.db.RedisCommandSanitizer;
2929
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
30+
import io.opentelemetry.instrumentation.api.instrumenter.OperationListener;
3031
import io.opentelemetry.instrumentation.api.internal.SemconvStability;
3132
import io.opentelemetry.instrumentation.api.semconv.network.NetworkAttributesExtractor;
3233
import io.opentelemetry.instrumentation.api.semconv.network.ServerAttributesExtractor;
@@ -54,8 +55,11 @@ final class OpenTelemetryTracing implements Tracing {
5455
NetworkAttributesExtractor.create(new LettuceServerAttributesGetter());
5556
private final TracerProvider tracerProvider;
5657

57-
OpenTelemetryTracing(io.opentelemetry.api.trace.Tracer tracer, RedisCommandSanitizer sanitizer) {
58-
this.tracerProvider = new OpenTelemetryTracerProvider(tracer, sanitizer);
58+
OpenTelemetryTracing(
59+
io.opentelemetry.api.trace.Tracer tracer,
60+
RedisCommandSanitizer sanitizer,
61+
OperationListener metrics) {
62+
this.tracerProvider = new OpenTelemetryTracerProvider(tracer, sanitizer, metrics);
5963
}
6064

6165
@Override
@@ -93,8 +97,10 @@ private static class OpenTelemetryTracerProvider implements TracerProvider {
9397
private final Tracer openTelemetryTracer;
9498

9599
OpenTelemetryTracerProvider(
96-
io.opentelemetry.api.trace.Tracer tracer, RedisCommandSanitizer sanitizer) {
97-
openTelemetryTracer = new OpenTelemetryTracer(tracer, sanitizer);
100+
io.opentelemetry.api.trace.Tracer tracer,
101+
RedisCommandSanitizer sanitizer,
102+
OperationListener metrics) {
103+
openTelemetryTracer = new OpenTelemetryTracer(tracer, sanitizer, metrics);
98104
}
99105

100106
@Override
@@ -135,10 +141,15 @@ private static class OpenTelemetryTracer extends Tracer {
135141

136142
private final io.opentelemetry.api.trace.Tracer tracer;
137143
private final RedisCommandSanitizer sanitizer;
144+
private final OperationListener metrics;
138145

139-
OpenTelemetryTracer(io.opentelemetry.api.trace.Tracer tracer, RedisCommandSanitizer sanitizer) {
146+
OpenTelemetryTracer(
147+
io.opentelemetry.api.trace.Tracer tracer,
148+
RedisCommandSanitizer sanitizer,
149+
OperationListener metrics) {
140150
this.tracer = tracer;
141151
this.sanitizer = sanitizer;
152+
this.metrics = metrics;
142153
}
143154

144155
@Override
@@ -165,7 +176,7 @@ private OpenTelemetrySpan nextSpan(Context context) {
165176
.setSpanKind(SpanKind.CLIENT)
166177
.setParent(context)
167178
.setAttribute(DB_SYSTEM, REDIS);
168-
return new OpenTelemetrySpan(context, spanBuilder, sanitizer);
179+
return new OpenTelemetrySpan(context, spanBuilder, sanitizer, metrics);
169180
}
170181
}
171182

@@ -178,18 +189,26 @@ private static class OpenTelemetrySpan extends Tracer.Span {
178189
private final Context context;
179190
private final SpanBuilder spanBuilder;
180191
private final RedisCommandSanitizer sanitizer;
192+
private final OperationListener metrics;
181193

182194
@Nullable private String name;
183195
@Nullable private List<Object> events;
184196
@Nullable private Throwable error;
185197
@Nullable private Span span;
198+
private long spanStartTime;
199+
private final AttributesBuilder attributesBuilder = Attributes.builder();
186200
@Nullable private List<String> argsList;
187201
@Nullable private String argsString;
188202

189-
OpenTelemetrySpan(Context context, SpanBuilder spanBuilder, RedisCommandSanitizer sanitizer) {
203+
OpenTelemetrySpan(
204+
Context context,
205+
SpanBuilder spanBuilder,
206+
RedisCommandSanitizer sanitizer,
207+
OperationListener metrics) {
190208
this.context = context;
191209
this.spanBuilder = spanBuilder;
192210
this.sanitizer = sanitizer;
211+
this.metrics = metrics;
193212
}
194213

195214
@Override
@@ -218,11 +237,13 @@ private void fillEndpoint(OpenTelemetryEndpoint endpoint) {
218237
Context currentContext = span == null ? context : context.with(span);
219238
serverAttributesExtractor.onStart(attributesBuilder, currentContext, endpoint);
220239
networkAttributesExtractor.onEnd(attributesBuilder, currentContext, endpoint, null, null);
240+
Attributes attributes = attributesBuilder.build();
221241
if (span != null) {
222-
span.setAllAttributes(attributesBuilder.build());
242+
span.setAllAttributes(attributes);
223243
} else {
224-
spanBuilder.setAllAttributes(attributesBuilder.build());
244+
spanBuilder.setAllAttributes(attributes);
225245
}
246+
attributesBuilder.putAll(attributes);
226247
}
227248

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

235257
Span span = this.span;
236258
if (span == null) {
@@ -258,7 +280,7 @@ public synchronized Tracer.Span start(RedisCommand<?, ?, ?> command) {
258280
}
259281
}
260282

261-
finish(span);
283+
finish(span, startTime);
262284
});
263285
}
264286

@@ -270,6 +292,7 @@ public synchronized Tracer.Span start(RedisCommand<?, ?, ?> command) {
270292
@CanIgnoreReturnValue
271293
public synchronized Tracer.Span start() {
272294
span = spanBuilder.startSpan();
295+
spanStartTime = System.nanoTime();
273296
if (name != null) {
274297
span.updateName(name);
275298
}
@@ -330,6 +353,7 @@ public synchronized Tracer.Span tag(String key, String value) {
330353
} else {
331354
spanBuilder.setAttribute(key, value);
332355
}
356+
attributesBuilder.put(key, value);
333357
return this;
334358
}
335359

@@ -347,16 +371,18 @@ public synchronized Tracer.Span error(Throwable throwable) {
347371
@Override
348372
public synchronized void finish() {
349373
if (span != null) {
350-
finish(span);
374+
finish(span, spanStartTime);
351375
}
352376
}
353377

354-
private void finish(Span span) {
378+
private void finish(Span span, long startTime) {
355379
if (name != null) {
356380
String statement =
357381
sanitizer.sanitize(name, argsList != null ? argsList : splitArgs(argsString));
358382
if (SemconvStability.emitStableDatabaseSemconv()) {
359383
span.setAttribute(DB_QUERY_TEXT, statement);
384+
Context c = metrics.onStart(Context.current(), Attributes.empty(), startTime);
385+
metrics.onEnd(c, attributesBuilder.build(), System.nanoTime());
360386
}
361387
if (SemconvStability.emitOldDatabaseSemconv()) {
362388
span.setAttribute(DB_STATEMENT, statement);

instrumentation/lettuce/lettuce-5.1/testing/src/main/java/io/opentelemetry/instrumentation/lettuce/v5_1/AbstractLettuceSyncClientTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
package io.opentelemetry.instrumentation.lettuce.v5_1;
77

8+
import static io.opentelemetry.instrumentation.testing.junit.db.DbClientMetricsTestUtil.assertDurationMetric;
89
import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStable;
910
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
1011
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies;
@@ -13,6 +14,9 @@
1314
import static io.opentelemetry.semconv.NetworkAttributes.NETWORK_TYPE;
1415
import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS;
1516
import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT;
17+
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_COLLECTION_NAME;
18+
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_NAMESPACE;
19+
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_OPERATION_NAME;
1620
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_STATEMENT;
1721
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SYSTEM;
1822
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -135,6 +139,18 @@ void testSetCommand() {
135139
.hasEventsSatisfyingExactly(
136140
event -> event.hasName("redis.encode.start"),
137141
event -> event.hasName("redis.encode.end"))));
142+
143+
assertDurationMetric(
144+
testing(),
145+
"io.opentelemetry.lettuce-5.1",
146+
DB_SYSTEM,
147+
DB_COLLECTION_NAME,
148+
DB_NAMESPACE,
149+
DB_OPERATION_NAME);
150+
//
151+
// testing().waitAndAssertMetrics(metric ->
152+
// OpenTelemetryAssertions.assertThat(metric)
153+
// .hasName("db.client.operation.duration"));
138154
}
139155

140156
@Test

0 commit comments

Comments
 (0)