Skip to content

Commit 7ed3338

Browse files
authored
Merge pull request #2946 from DataDog/tvaleev/feature/RUM-12103
RUM-12103: Handle OTEL reserved attributes when using AttributeKeys (Fixes #2935)
2 parents 05df7a3 + 1327d97 commit 7ed3338

File tree

2 files changed

+129
-8
lines changed

2 files changed

+129
-8
lines changed

features/dd-sdk-android-trace-otel/src/main/java/com/datadog/opentelemetry/trace/OtelSpanBuilder.java

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,8 @@ public SpanBuilder addLink(SpanContext spanContext, Attributes attributes) {
101101

102102
@Override
103103
public SpanBuilder setAttribute(@NonNull String key, @Nullable String value) {
104-
// Check reserved attributes
105-
if (OPERATION_NAME_SPECIFIC_ATTRIBUTE.equals(key) && value != null) {
106-
this.overriddenOperationName = value.toLowerCase(ROOT);
107-
return this;
108-
} else if (ANALYTICS_EVENT_SPECIFIC_ATTRIBUTES.equals(key) && value != null) {
109-
this.overriddenAnalyticsSampleRate = parseBoolean(value) ? 1 : 0;
110-
return this;
111-
}
104+
if (handleReservedAttribute(key, value)) return this;
105+
112106
// Store as object to prevent delegate to remove tag when value is empty
113107
this.delegate.withTag(key, value);
114108
return this;
@@ -156,6 +150,8 @@ public <T> SpanBuilder setAttribute(AttributeKey<T> key, @Nullable T value) {
156150
}
157151
}
158152
break;
153+
case STRING:
154+
return setAttribute(key.getKey(), (String) value);
159155
default:
160156
this.delegate.withTag(key.getKey(), value);
161157
break;
@@ -194,4 +190,16 @@ public Span startSpan() {
194190
}
195191
return new OtelSpan(delegate, agentTracer);
196192
}
193+
194+
private boolean handleReservedAttribute(String key, String value) {
195+
if (OPERATION_NAME_SPECIFIC_ATTRIBUTE.equals(key) && value != null) {
196+
this.overriddenOperationName = value.toLowerCase(ROOT);
197+
return true;
198+
} else if (ANALYTICS_EVENT_SPECIFIC_ATTRIBUTES.equals(key) && value != null) {
199+
this.overriddenAnalyticsSampleRate = parseBoolean(value) ? 1 : 0;
200+
return true;
201+
}
202+
203+
return false;
204+
}
197205
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
4+
* Copyright 2016-Present Datadog, Inc.
5+
*/
6+
7+
package com.datadog.opentelemetry.trace
8+
9+
import com.datadog.android.api.InternalLogger
10+
import com.datadog.android.trace.api.DatadogTracingConstants
11+
import com.datadog.android.trace.api.span.DatadogSpan
12+
import com.datadog.android.trace.api.span.DatadogSpanBuilder
13+
import com.datadog.android.trace.api.tracer.DatadogTracer
14+
import com.datadog.android.trace.opentelemetry.utils.forge.Configurator
15+
import fr.xgouchet.elmyr.junit5.ForgeConfiguration
16+
import fr.xgouchet.elmyr.junit5.ForgeExtension
17+
import io.opentelemetry.api.common.AttributeKey
18+
import org.junit.jupiter.api.BeforeEach
19+
import org.junit.jupiter.api.Test
20+
import org.junit.jupiter.api.extension.ExtendWith
21+
import org.junit.jupiter.api.extension.Extensions
22+
import org.mockito.Mock
23+
import org.mockito.junit.jupiter.MockitoExtension
24+
import org.mockito.junit.jupiter.MockitoSettings
25+
import org.mockito.kotlin.verify
26+
import org.mockito.kotlin.verifyNoInteractions
27+
import org.mockito.kotlin.whenever
28+
import org.mockito.quality.Strictness
29+
30+
@Extensions(
31+
ExtendWith(MockitoExtension::class),
32+
ExtendWith(ForgeExtension::class)
33+
)
34+
@MockitoSettings(strictness = Strictness.LENIENT)
35+
@ForgeConfiguration(Configurator::class)
36+
internal class OtelSpanBuilderTest {
37+
38+
private lateinit var testedBuilder: OtelSpanBuilder
39+
40+
@Mock
41+
lateinit var mockDelegateBuilder: DatadogSpanBuilder
42+
43+
@Mock
44+
lateinit var mockAgentTracer: DatadogTracer
45+
46+
@Mock
47+
lateinit var mockLogger: InternalLogger
48+
49+
@Mock
50+
lateinit var mockAgentSpan: DatadogSpan
51+
52+
// region Init
53+
@BeforeEach
54+
fun `set up`() {
55+
whenever(mockDelegateBuilder.start()).thenReturn(mockAgentSpan)
56+
testedBuilder = OtelSpanBuilder(mockDelegateBuilder, mockAgentTracer, mockLogger)
57+
}
58+
59+
// endregion
60+
61+
// region setAttribute
62+
63+
@Test
64+
fun `M add attribute W setAttribute`() {
65+
// When
66+
testedBuilder.setAttribute("string", "b")
67+
testedBuilder.setAttribute("empty_string", "")
68+
testedBuilder.setAttribute("number", 2L)
69+
testedBuilder.setAttribute("boolean", false)
70+
71+
// Then
72+
verify(mockDelegateBuilder).withTag("string", "b")
73+
verify(mockDelegateBuilder).withTag("empty_string", "")
74+
verify(mockDelegateBuilder).withTag("number", 2L)
75+
verify(mockDelegateBuilder).withTag("boolean", false)
76+
}
77+
78+
@Test
79+
fun `M add attribute W setAttribute with reserved string key`() {
80+
// When
81+
testedBuilder.setAttribute(OtelConventions.OPERATION_NAME_SPECIFIC_ATTRIBUTE, "op_name")
82+
testedBuilder.setAttribute(OtelConventions.ANALYTICS_EVENT_SPECIFIC_ATTRIBUTES, "true")
83+
84+
// Then
85+
verifyNoInteractions(mockDelegateBuilder)
86+
testedBuilder.startSpan()
87+
88+
verify(mockAgentSpan).operationName = "op_name"
89+
verify(mockAgentSpan).setMetric(DatadogTracingConstants.Tags.KEY_ANALYTICS_SAMPLE_RATE, 1)
90+
}
91+
92+
@Test
93+
fun `M add attribute W setAttribute with reserved attribute key`() {
94+
// When
95+
testedBuilder.setAttribute(
96+
AttributeKey.stringKey(OtelConventions.OPERATION_NAME_SPECIFIC_ATTRIBUTE),
97+
"op_name"
98+
)
99+
testedBuilder.setAttribute(
100+
AttributeKey.stringKey(OtelConventions.ANALYTICS_EVENT_SPECIFIC_ATTRIBUTES),
101+
"false"
102+
)
103+
104+
// Then
105+
verifyNoInteractions(mockDelegateBuilder)
106+
testedBuilder.startSpan()
107+
108+
verify(mockAgentSpan).operationName = "op_name"
109+
verify(mockAgentSpan).setMetric(DatadogTracingConstants.Tags.KEY_ANALYTICS_SAMPLE_RATE, 0)
110+
}
111+
112+
// endregion
113+
}

0 commit comments

Comments
 (0)