Skip to content

Commit d78c242

Browse files
SylvainJugelaurit
andauthored
add experimental option to avoid lettuce noisy span events (#14750)
Co-authored-by: Lauri Tulmin <[email protected]>
1 parent 9422142 commit d78c242

File tree

13 files changed

+132
-140
lines changed

13 files changed

+132
-140
lines changed

instrumentation/lettuce/README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Settings for the Lettuce instrumentation
22

3-
| System property | Type | Default | Description |
4-
|-------------------------------------------------------------|---------|---------|-----------------------------------------------------|
5-
| `otel.instrumentation.lettuce.experimental-span-attributes` | Boolean | `false` | Enable the capture of experimental span attributes. |
6-
| `otel.instrumentation.lettuce.connection-telemetry.enabled` | Boolean | `false` | Enable the creation of Connect spans. |
3+
| System property | Type | Default | Description |
4+
|-----------------------------------------------------------------------------|---------|---------|--------------------------------------------------------------------------------|
5+
| `otel.instrumentation.lettuce.experimental-span-attributes` | Boolean | `false` | Enable the capture of experimental span attributes. |
6+
| `otel.instrumentation.lettuce.connection-telemetry.enabled` | Boolean | `false` | Enable the creation of Connect spans. |
7+
| `otel.instrumentation.lettuce.experimental.command-encoding-events.enabled` | Boolean | `false` | Enable the capture of `redis.encode.start` and `redis.encode.end` span events. |

instrumentation/lettuce/lettuce-4.0/javaagent/build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ dependencies {
1919

2020
tasks {
2121
withType<Test>().configureEach {
22-
// TODO run tests both with and without experimental span attributes
22+
// TODO run tests both with and without experimental span attributes and span events
2323
jvmArgs("-Dotel.instrumentation.lettuce.experimental-span-attributes=true")
2424
jvmArgs("-Dotel.instrumentation.lettuce.connection-telemetry.enabled=true")
25+
jvmArgs("-Dotel.instrumentation.lettuce.experimental.command-encoding-events.enabled=true")
2526
usesService(gradle.sharedServices.registrations["testcontainersBuildService"].service)
2627
}
2728

instrumentation/lettuce/lettuce-5.0/javaagent/build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ dependencies {
2626

2727
tasks {
2828
withType<Test>().configureEach {
29-
// TODO run tests both with and without experimental span attributes
29+
// TODO run tests both with and without experimental span attributes and span events
3030
jvmArgs("-Dotel.instrumentation.lettuce.experimental-span-attributes=true")
3131
jvmArgs("-Dotel.instrumentation.lettuce.connection-telemetry.enabled=true")
32+
jvmArgs("-Dotel.instrumentation.lettuce.experimental.command-encoding-events.enabled=true")
3233
usesService(gradle.sharedServices.registrations["testcontainersBuildService"].service)
3334
}
3435

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,19 @@
99
import io.opentelemetry.api.GlobalOpenTelemetry;
1010
import io.opentelemetry.instrumentation.lettuce.v5_1.LettuceTelemetry;
1111
import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig;
12+
import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig;
1213

1314
public final class TracingHolder {
1415

16+
private static final boolean CAPTURE_COMMAND_ENCODING_EVENTS =
17+
AgentInstrumentationConfig.get()
18+
.getBoolean(
19+
"otel.instrumentation.lettuce.experimental.command-encoding-events.enabled", false);
20+
1521
public static final Tracing TRACING =
1622
LettuceTelemetry.builder(GlobalOpenTelemetry.get())
1723
.setStatementSanitizationEnabled(AgentCommonConfig.get().isStatementSanitizationEnabled())
24+
.setEncodingSpanEventsEnabled(CAPTURE_COMMAND_ENCODING_EVENTS)
1825
.build()
1926
.newTracing();
2027

instrumentation/lettuce/lettuce-5.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_1/LettuceReactiveClientTest.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import io.lettuce.core.RedisClient;
1919
import io.opentelemetry.api.common.Attributes;
2020
import io.opentelemetry.api.trace.SpanKind;
21+
import io.opentelemetry.instrumentation.lettuce.v5_1.AbstractLettuceClientTest;
2122
import io.opentelemetry.instrumentation.lettuce.v5_1.AbstractLettuceReactiveClientTest;
2223
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
2324
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
@@ -66,9 +67,7 @@ void testAsyncSubscriberWithSpecificThreadPool() {
6667
equalTo(SERVER_PORT, port),
6768
equalTo(maybeStable(DB_SYSTEM), "redis"),
6869
equalTo(maybeStable(DB_STATEMENT), "SET a ?")))
69-
.hasEventsSatisfyingExactly(
70-
event -> event.hasName("redis.encode.start"),
71-
event -> event.hasName("redis.encode.end")),
70+
.satisfies(AbstractLettuceClientTest::assertCommandEncodeEvents),
7271
span ->
7372
span.hasName("GET")
7473
.hasKind(SpanKind.CLIENT)
@@ -82,8 +81,6 @@ void testAsyncSubscriberWithSpecificThreadPool() {
8281
equalTo(SERVER_PORT, port),
8382
equalTo(maybeStable(DB_SYSTEM), "redis"),
8483
equalTo(maybeStable(DB_STATEMENT), "GET a")))
85-
.hasEventsSatisfyingExactly(
86-
event -> event.hasName("redis.encode.start"),
87-
event -> event.hasName("redis.encode.end"))));
84+
.satisfies(AbstractLettuceClientTest::assertCommandEncodeEvents)));
8885
}
8986
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ public static LettuceTelemetryBuilder builder(OpenTelemetry openTelemetry) {
3333
private final Tracer tracer;
3434
private final RedisCommandSanitizer sanitizer;
3535
private final OperationListener metrics;
36+
private final boolean encodingEventsEnabled;
3637

3738
LettuceTelemetry(
3839
OpenTelemetry openTelemetry,
3940
boolean statementSanitizationEnabled,
41+
boolean encodingEventsEnabled,
4042
OperationListener metrics) {
4143
this.metrics = metrics;
4244
TracerBuilder tracerBuilder = openTelemetry.tracerBuilder(INSTRUMENTATION_NAME);
@@ -46,13 +48,14 @@ public static LettuceTelemetryBuilder builder(OpenTelemetry openTelemetry) {
4648
}
4749
tracer = tracerBuilder.build();
4850
sanitizer = RedisCommandSanitizer.create(statementSanitizationEnabled);
51+
this.encodingEventsEnabled = encodingEventsEnabled;
4952
}
5053

5154
/**
5255
* Returns a new {@link Tracing} which can be used with methods like {@link
5356
* io.lettuce.core.resource.ClientResources.Builder#tracing(Tracing)}.
5457
*/
5558
public Tracing newTracing() {
56-
return new OpenTelemetryTracing(tracer, sanitizer, metrics);
59+
return new OpenTelemetryTracing(tracer, sanitizer, metrics, encodingEventsEnabled);
5760
}
5861
}

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public final class LettuceTelemetryBuilder {
1717
private final OpenTelemetry openTelemetry;
1818

1919
private boolean statementSanitizationEnabled = true;
20+
private boolean encodingEventsEnabled = false;
2021

2122
LettuceTelemetryBuilder(OpenTelemetry openTelemetry) {
2223
this.openTelemetry = openTelemetry;
@@ -34,6 +35,16 @@ public LettuceTelemetryBuilder setStatementSanitizationEnabled(
3435
return this;
3536
}
3637

38+
/**
39+
* Sets whether the {@code redis.encode.start} and {@code redis.encode.end} span events should be
40+
* emitted by the constructed {@link LettuceTelemetry}. Disabled by default.
41+
*/
42+
@CanIgnoreReturnValue
43+
public LettuceTelemetryBuilder setEncodingSpanEventsEnabled(boolean encodingEventsEnabled) {
44+
this.encodingEventsEnabled = encodingEventsEnabled;
45+
return this;
46+
}
47+
3748
/**
3849
* Returns a new {@link LettuceTelemetry} with the settings of this {@link
3950
* LettuceTelemetryBuilder}.
@@ -42,6 +53,7 @@ public LettuceTelemetry build() {
4253
return new LettuceTelemetry(
4354
openTelemetry,
4455
statementSanitizationEnabled,
56+
encodingEventsEnabled,
4557
DbClientMetrics.get().create(openTelemetry.getMeterProvider().get(INSTRUMENTATION_NAME)));
4658
}
4759
}

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

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@ final class OpenTelemetryTracing implements Tracing {
5959
OpenTelemetryTracing(
6060
io.opentelemetry.api.trace.Tracer tracer,
6161
RedisCommandSanitizer sanitizer,
62-
OperationListener metrics) {
63-
this.tracerProvider = new OpenTelemetryTracerProvider(tracer, sanitizer, metrics);
62+
OperationListener metrics,
63+
boolean encodingEventsEnabled) {
64+
this.tracerProvider =
65+
new OpenTelemetryTracerProvider(tracer, sanitizer, metrics, encodingEventsEnabled);
6466
}
6567

6668
@Override
@@ -100,8 +102,10 @@ private static class OpenTelemetryTracerProvider implements TracerProvider {
100102
OpenTelemetryTracerProvider(
101103
io.opentelemetry.api.trace.Tracer tracer,
102104
RedisCommandSanitizer sanitizer,
103-
OperationListener metrics) {
104-
openTelemetryTracer = new OpenTelemetryTracer(tracer, sanitizer, metrics);
105+
OperationListener metrics,
106+
boolean encodingEventsEnabled) {
107+
openTelemetryTracer =
108+
new OpenTelemetryTracer(tracer, sanitizer, metrics, encodingEventsEnabled);
105109
}
106110

107111
@Override
@@ -143,14 +147,17 @@ private static class OpenTelemetryTracer extends Tracer {
143147
private final io.opentelemetry.api.trace.Tracer tracer;
144148
private final RedisCommandSanitizer sanitizer;
145149
private final OperationListener metrics;
150+
private final boolean encodingEventsEnabled;
146151

147152
OpenTelemetryTracer(
148153
io.opentelemetry.api.trace.Tracer tracer,
149154
RedisCommandSanitizer sanitizer,
150-
OperationListener metrics) {
155+
OperationListener metrics,
156+
boolean encodingEventsEnabled) {
151157
this.tracer = tracer;
152158
this.sanitizer = sanitizer;
153159
this.metrics = metrics;
160+
this.encodingEventsEnabled = encodingEventsEnabled;
154161
}
155162

156163
@Override
@@ -179,7 +186,7 @@ private OpenTelemetrySpan nextSpan(Context context) {
179186
if (SemconvStability.emitOldDatabaseSemconv()) {
180187
spanBuilder.setAttribute(DB_SYSTEM, REDIS);
181188
}
182-
return new OpenTelemetrySpan(context, spanBuilder, sanitizer, metrics);
189+
return new OpenTelemetrySpan(context, spanBuilder, sanitizer, metrics, encodingEventsEnabled);
183190
}
184191
}
185192

@@ -193,6 +200,7 @@ private static class OpenTelemetrySpan extends Tracer.Span {
193200
private final SpanBuilder spanBuilder;
194201
private final RedisCommandSanitizer sanitizer;
195202
private final OperationListener metrics;
203+
private final boolean encodingEventsEnabled;
196204

197205
@Nullable private String name;
198206
@Nullable private List<Object> events;
@@ -207,12 +215,14 @@ private static class OpenTelemetrySpan extends Tracer.Span {
207215
Context context,
208216
SpanBuilder spanBuilder,
209217
RedisCommandSanitizer sanitizer,
210-
OperationListener metrics) {
218+
OperationListener metrics,
219+
boolean encodingEventsEnabled) {
211220
this.context = context;
212221
this.spanBuilder = spanBuilder;
213222
this.sanitizer = sanitizer;
214223
this.metrics = metrics;
215224
this.attributesBuilder = Attributes.builder();
225+
this.encodingEventsEnabled = encodingEventsEnabled;
216226
if (SemconvStability.emitStableDatabaseSemconv()) {
217227
attributesBuilder.put(DB_SYSTEM_NAME, REDIS);
218228
}
@@ -326,6 +336,11 @@ public synchronized Tracer.Span start() {
326336
@Override
327337
@CanIgnoreReturnValue
328338
public synchronized Tracer.Span annotate(String value) {
339+
if (!encodingEventsEnabled && value.startsWith("redis.encode.")) {
340+
// skip noisy encode events produced by io.lettuce.core.protocol.TracedCommand
341+
return this;
342+
}
343+
329344
if (span != null) {
330345
span.addEvent(value);
331346
} else {

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

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,7 @@ void testSetCommandUsingFutureGetWithTimeout() throws Exception {
168168
equalTo(SERVER_PORT, port),
169169
equalTo(maybeStable(DB_SYSTEM), "redis"),
170170
equalTo(maybeStable(DB_STATEMENT), "SET TESTSETKEY ?")))
171-
.hasEventsSatisfyingExactly(
172-
event -> event.hasName("redis.encode.start"),
173-
event -> event.hasName("redis.encode.end"))));
171+
.satisfies(AbstractLettuceClientTest::assertCommandEncodeEvents)));
174172
}
175173

176174
@Test
@@ -214,9 +212,8 @@ void testGetCommandChainedWithThenAccept() throws Exception {
214212
equalTo(SERVER_PORT, port),
215213
equalTo(maybeStable(DB_SYSTEM), "redis"),
216214
equalTo(maybeStable(DB_STATEMENT), "GET TESTKEY")))
217-
.hasEventsSatisfyingExactly(
218-
event -> event.hasName("redis.encode.start"),
219-
event -> event.hasName("redis.encode.end"))));
215+
.satisfies(
216+
AbstractLettuceClientTest::assertCommandEncodeEvents)));
220217

221218
if (testCallback()) {
222219
spanAsserts.add(
@@ -294,9 +291,8 @@ void testGetNonExistentKeyCommandWithHandleAsyncAndChainedWithThenApply() throws
294291
equalTo(maybeStable(DB_SYSTEM), "redis"),
295292
equalTo(
296293
maybeStable(DB_STATEMENT), "GET NON_EXISTENT_KEY")))
297-
.hasEventsSatisfyingExactly(
298-
event -> event.hasName("redis.encode.start"),
299-
event -> event.hasName("redis.encode.end"))));
294+
.satisfies(
295+
AbstractLettuceClientTest::assertCommandEncodeEvents)));
300296

301297
if (testCallback()) {
302298
spanAsserts.addAll(
@@ -360,9 +356,8 @@ void testCommandWithNoArgumentsUsingBiconsumer() throws Exception {
360356
equalTo(SERVER_PORT, port),
361357
equalTo(maybeStable(DB_SYSTEM), "redis"),
362358
equalTo(maybeStable(DB_STATEMENT), "RANDOMKEY")))
363-
.hasEventsSatisfyingExactly(
364-
event -> event.hasName("redis.encode.start"),
365-
event -> event.hasName("redis.encode.end"))));
359+
.satisfies(
360+
AbstractLettuceClientTest::assertCommandEncodeEvents)));
366361

367362
if (testCallback()) {
368363
spanAsserts.add(
@@ -422,9 +417,7 @@ void testHashSetAndThenNestApplyToHashGetall() throws Exception {
422417
equalTo(
423418
maybeStable(DB_STATEMENT),
424419
"HMSET TESTHM firstname ? lastname ? age ?")))
425-
.hasEventsSatisfyingExactly(
426-
event -> event.hasName("redis.encode.start"),
427-
event -> event.hasName("redis.encode.end"))),
420+
.satisfies(AbstractLettuceClientTest::assertCommandEncodeEvents)),
428421
trace ->
429422
trace.hasSpansSatisfyingExactly(
430423
span ->
@@ -439,8 +432,6 @@ void testHashSetAndThenNestApplyToHashGetall() throws Exception {
439432
equalTo(SERVER_PORT, port),
440433
equalTo(maybeStable(DB_SYSTEM), "redis"),
441434
equalTo(maybeStable(DB_STATEMENT), "HGETALL TESTHM")))
442-
.hasEventsSatisfyingExactly(
443-
event -> event.hasName("redis.encode.start"),
444-
event -> event.hasName("redis.encode.end"))));
435+
.satisfies(AbstractLettuceClientTest::assertCommandEncodeEvents)));
445436
}
446437
}

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

Lines changed: 21 additions & 1 deletion
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.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
89
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
910
import static io.opentelemetry.semconv.DbAttributes.DB_NAMESPACE;
1011
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_REDIS_DATABASE_INDEX;
@@ -15,6 +16,7 @@
1516
import io.opentelemetry.instrumentation.testing.internal.AutoCleanupExtension;
1617
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
1718
import io.opentelemetry.sdk.testing.assertj.AttributeAssertion;
19+
import io.opentelemetry.sdk.trace.data.SpanData;
1820
import java.util.ArrayList;
1921
import java.util.Arrays;
2022
import java.util.List;
@@ -27,9 +29,13 @@
2729
import org.testcontainers.containers.wait.strategy.Wait;
2830

2931
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
30-
abstract class AbstractLettuceClientTest {
32+
public abstract class AbstractLettuceClientTest {
3133
protected static final Logger logger = LoggerFactory.getLogger(AbstractLettuceClientTest.class);
3234

35+
private static final boolean COMMAND_ENCODING_EVENTS_ENABLED =
36+
Boolean.getBoolean(
37+
"otel.instrumentation.lettuce.experimental.command-encoding-events.enabled");
38+
3339
@RegisterExtension static final AutoCleanupExtension cleanup = AutoCleanupExtension.create();
3440

3541
protected static final int DB_INDEX = 0;
@@ -94,4 +100,18 @@ protected static List<AttributeAssertion> addExtraAttributes(AttributeAssertion.
94100
}
95101
return result;
96102
}
103+
104+
protected static void assertCommandEncodeEvents(SpanData span) {
105+
if (COMMAND_ENCODING_EVENTS_ENABLED) {
106+
assertThat(span)
107+
.hasEventsSatisfyingExactly(
108+
event -> event.hasName("redis.encode.start"),
109+
event -> event.hasName("redis.encode.end"));
110+
} else {
111+
assertThat(span.getEvents())
112+
.noneSatisfy(event -> assertThat(event).hasName("redis.encode.start"));
113+
assertThat(span.getEvents())
114+
.noneSatisfy(event -> assertThat(event).hasName("redis.encode.end"));
115+
}
116+
}
97117
}

0 commit comments

Comments
 (0)