Skip to content

Commit a9a1d1e

Browse files
authored
Merge pull request #2911 from DataDog/tvaleev/feature/RUM-11854-account-id_user-id_support
[RUM-11854]: Account id and User id propagated in baggage header
2 parents 8612241 + 44d776f commit a9a1d1e

File tree

11 files changed

+313
-79
lines changed

11 files changed

+313
-79
lines changed

features/dd-sdk-android-trace-internal/api/dd-sdk-android-trace-internal.api

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3135,7 +3135,8 @@ public class com/datadog/trace/core/propagation/ExtractedContext : com/datadog/t
31353135
}
31363136

31373137
public class com/datadog/trace/core/propagation/HttpCodec {
3138-
public static final field RUM_SESSION_ID_KEY Ljava/lang/String;
3138+
public static final field RUM_KEY_ACCOUNT_ID Ljava/lang/String;
3139+
public static final field RUM_KEY_USER_ID Ljava/lang/String;
31393140
public fun <init> ()V
31403141
public static fun allInjectorsFor (Lcom/datadog/trace/api/Config;Ljava/util/Map;)Ljava/util/Map;
31413142
public static fun createExtractor (Lcom/datadog/trace/api/Config;Lcom/datadog/android/trace/internal/compat/function/Supplier;)Lcom/datadog/trace/core/propagation/HttpCodec$Extractor;

features/dd-sdk-android-trace-internal/src/main/java/com/datadog/trace/core/propagation/HttpCodec.java

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,14 @@ public class HttpCodec {
5050
static final String FASTLY_CLIENT_IP_KEY = "fastly-client-ip";
5151
static final String CF_CONNECTING_IP_KEY = "cf-connecting-ip";
5252
static final String CF_CONNECTING_IP_V6_KEY = "cf-connecting-ipv6";
53-
static final String RUM_SESSION_ID_BAGGAGE_KEY = "session.id";
5453

55-
public static final String RUM_SESSION_ID_KEY = "session_id";
54+
static final String BAGGAGE_SESSION_ID = "session.id";
55+
static final String BAGGAGE_USER_ID = "user.id";
56+
static final String BAGGAGE_ACCOUNT_ID = "account.id";
57+
58+
static final String RUM_KEY_SESSION_ID = "session_id";
59+
public static final String RUM_KEY_USER_ID = "user_id";
60+
public static final String RUM_KEY_ACCOUNT_ID = "account_id";
5661

5762
public interface Injector {
5863
<C> void inject(
@@ -192,7 +197,7 @@ public <C> void inject(
192197
final DDSpanContext context, final C carrier, final AgentPropagation.Setter<C> setter) {
193198
log.debug("Inject context {}", context);
194199
// Update session ide before injecting propagation tags
195-
final String sessionId = (String) context.getTags().get(RUM_SESSION_ID_KEY);
200+
final String sessionId = (String) context.getTags().get(RUM_KEY_SESSION_ID);
196201
if (sessionId != null) {
197202
context.getPropagationTags().updateRumSessionId(sessionId);
198203
}
@@ -369,10 +374,20 @@ static String firstHeaderValue(final String value) {
369374
@NonNull
370375
static Baggage composeBaggage(@NonNull DDSpanContext context) {
371376
Baggage baggage = new Baggage();
372-
final String sessionId = (String) context.getTags().get(RUM_SESSION_ID_KEY);
373377

378+
final String sessionId = (String) context.getTags().get(RUM_KEY_SESSION_ID);
374379
if (sessionId != null) {
375-
baggage.put(RUM_SESSION_ID_BAGGAGE_KEY, sessionId);
380+
baggage.put(BAGGAGE_SESSION_ID, sessionId);
381+
}
382+
383+
final String userId = (String) context.getTags().get(RUM_KEY_USER_ID);
384+
if (userId != null) {
385+
baggage.put(BAGGAGE_USER_ID, userId);
386+
}
387+
388+
final String accountId = (String) context.getTags().get(RUM_KEY_ACCOUNT_ID);
389+
if (accountId != null) {
390+
baggage.put(BAGGAGE_ACCOUNT_ID, accountId);
376391
}
377392

378393
return baggage;

features/dd-sdk-android-trace-internal/src/test/kotlin/com/datadog/trace/core/propagation/DatadogHttpCodecTest.kt

Lines changed: 71 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,23 @@ import com.datadog.trace.bootstrap.instrumentation.api.AgentPropagation
1111
import com.datadog.trace.core.DDSpanContext
1212
import com.datadog.utils.forge.Configurator
1313
import fr.xgouchet.elmyr.Forge
14-
import fr.xgouchet.elmyr.annotation.StringForgery
1514
import fr.xgouchet.elmyr.junit5.ForgeConfiguration
1615
import fr.xgouchet.elmyr.junit5.ForgeExtension
1716
import org.assertj.core.api.Assertions.assertThat
1817
import org.junit.jupiter.api.BeforeEach
1918
import org.junit.jupiter.api.Test
2019
import org.junit.jupiter.api.extension.ExtendWith
2120
import org.junit.jupiter.api.extension.Extensions
21+
import org.junit.jupiter.params.ParameterizedTest
22+
import org.junit.jupiter.params.provider.Arguments
23+
import org.junit.jupiter.params.provider.MethodSource
2224
import org.mockito.Mock
2325
import org.mockito.junit.jupiter.MockitoExtension
2426
import org.mockito.junit.jupiter.MockitoSettings
2527
import org.mockito.kotlin.argumentCaptor
2628
import org.mockito.kotlin.eq
2729
import org.mockito.kotlin.mock
30+
import org.mockito.kotlin.never
2831
import org.mockito.kotlin.verify
2932
import org.mockito.kotlin.whenever
3033
import org.mockito.quality.Strictness
@@ -46,22 +49,33 @@ internal class DatadogHttpCodecTest {
4649
@Mock
4750
lateinit var mockSetter: AgentPropagation.Setter<Any>
4851

52+
private val testedInjector = DatadogHttpCodec.newInjector(emptyMap<String, String>())
53+
4954
@BeforeEach
5055
fun `set up`(forge: Forge) {
5156
whenever(mockContext.traceId).thenReturn(DDTraceId.from(forge.aLong(min = 0L)))
5257
whenever(mockContext.propagationTags).thenReturn(mock())
5358
}
5459

55-
@Test
56-
fun `M add baggage W inject { sessionId is in context }`(
57-
@StringForgery fakeSessionId: String
60+
@ParameterizedTest
61+
@MethodSource("rumContext")
62+
fun `M add baggage W inject { rum context present }`(
63+
userId: String?,
64+
accountId: String?,
65+
sessionId: String?,
66+
expected: String
5867
) {
5968
// Given
60-
val injector = DatadogHttpCodec.newInjector(emptyMap<String, String>())
61-
whenever(mockContext.tags).thenReturn(mapOf(HttpCodec.RUM_SESSION_ID_KEY to fakeSessionId))
69+
whenever(mockContext.tags).thenReturn(
70+
mapOf(
71+
HttpCodec.RUM_KEY_USER_ID to userId,
72+
HttpCodec.RUM_KEY_ACCOUNT_ID to accountId,
73+
HttpCodec.RUM_KEY_SESSION_ID to sessionId
74+
)
75+
)
6276

6377
// When
64-
injector.inject(mockContext, mockCarrier, mockSetter)
78+
testedInjector.inject(mockContext, mockCarrier, mockSetter)
6579

6680
// Then
6781
argumentCaptor<String> {
@@ -71,7 +85,56 @@ internal class DatadogHttpCodecTest {
7185
capture()
7286
)
7387

74-
assertThat(firstValue).isEqualTo("session.id=$fakeSessionId")
88+
assertThat(firstValue).isEqualTo(expected)
89+
}
90+
}
91+
92+
@Test
93+
fun `M not add baggage W inject { no rum context }`() {
94+
// Given
95+
whenever(mockContext.tags).thenReturn(emptyMap())
96+
97+
// When
98+
testedInjector.inject(mockContext, mockCarrier, mockSetter)
99+
100+
// Then
101+
argumentCaptor<String> {
102+
verify(mockSetter, never()).set(
103+
eq(mockCarrier),
104+
eq(W3CHttpCodec.BAGGAGE_KEY),
105+
capture()
106+
)
75107
}
76108
}
109+
110+
companion object {
111+
@Suppress("unused")
112+
@JvmStatic
113+
fun rumContext() = listOf(
114+
Arguments.of(
115+
"userId",
116+
"accountId",
117+
"sessionId",
118+
"account.id=accountId,user.id=userId,session.id=sessionId"
119+
),
120+
Arguments.of(
121+
null,
122+
"accountId",
123+
"sessionId",
124+
"account.id=accountId,session.id=sessionId"
125+
),
126+
Arguments.of(
127+
"userId",
128+
null,
129+
"sessionId",
130+
"user.id=userId,session.id=sessionId"
131+
),
132+
Arguments.of(
133+
"userId",
134+
"accountId",
135+
null,
136+
"user.id=userId,account.id=accountId"
137+
)
138+
)
139+
}
77140
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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+
package com.datadog.trace.core.propagation
7+
8+
import com.datadog.trace.core.DDSpanContext
9+
import com.datadog.utils.forge.Configurator
10+
import fr.xgouchet.elmyr.annotation.StringForgery
11+
import fr.xgouchet.elmyr.junit5.ForgeConfiguration
12+
import fr.xgouchet.elmyr.junit5.ForgeExtension
13+
import org.assertj.core.api.Assertions.assertThat
14+
import org.junit.jupiter.api.Test
15+
import org.junit.jupiter.api.extension.ExtendWith
16+
import org.junit.jupiter.api.extension.Extensions
17+
import org.mockito.Mock
18+
import org.mockito.junit.jupiter.MockitoExtension
19+
import org.mockito.junit.jupiter.MockitoSettings
20+
import org.mockito.kotlin.whenever
21+
import org.mockito.quality.Strictness
22+
23+
@Extensions(
24+
ExtendWith(MockitoExtension::class),
25+
ExtendWith(ForgeExtension::class)
26+
)
27+
@MockitoSettings(strictness = Strictness.LENIENT)
28+
@ForgeConfiguration(Configurator::class)
29+
internal class HttpCodecTest {
30+
31+
@Mock
32+
private lateinit var mockContext: DDSpanContext
33+
34+
@Test
35+
fun `M return correct baggage header W composeBaggage`(
36+
@StringForgery fakeUserId: String,
37+
@StringForgery fakeSessionId: String,
38+
@StringForgery fakeAccountId: String
39+
) {
40+
// Given
41+
val expected = Baggage().apply {
42+
put(HttpCodec.BAGGAGE_USER_ID, fakeUserId)
43+
put(HttpCodec.BAGGAGE_ACCOUNT_ID, fakeAccountId)
44+
put(HttpCodec.BAGGAGE_SESSION_ID, fakeSessionId)
45+
}.toString()
46+
47+
whenever(mockContext.tags).thenReturn(
48+
mapOf<String, Any>(
49+
HttpCodec.RUM_KEY_SESSION_ID to fakeSessionId,
50+
HttpCodec.RUM_KEY_USER_ID to fakeUserId,
51+
HttpCodec.RUM_KEY_ACCOUNT_ID to fakeAccountId
52+
)
53+
)
54+
55+
// When
56+
val actual = HttpCodec.composeBaggage(mockContext).toString()
57+
58+
// Then
59+
assertThat(actual).isEqualTo(expected)
60+
}
61+
}

features/dd-sdk-android-trace-internal/src/test/kotlin/com/datadog/trace/core/propagation/W3CHttpCodecTest.kt

Lines changed: 71 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,23 @@ import com.datadog.trace.bootstrap.instrumentation.api.AgentPropagation
1111
import com.datadog.trace.core.DDSpanContext
1212
import com.datadog.utils.forge.Configurator
1313
import fr.xgouchet.elmyr.Forge
14-
import fr.xgouchet.elmyr.annotation.StringForgery
1514
import fr.xgouchet.elmyr.junit5.ForgeConfiguration
1615
import fr.xgouchet.elmyr.junit5.ForgeExtension
1716
import org.assertj.core.api.Assertions.assertThat
1817
import org.junit.jupiter.api.BeforeEach
1918
import org.junit.jupiter.api.Test
2019
import org.junit.jupiter.api.extension.ExtendWith
2120
import org.junit.jupiter.api.extension.Extensions
21+
import org.junit.jupiter.params.ParameterizedTest
22+
import org.junit.jupiter.params.provider.Arguments
23+
import org.junit.jupiter.params.provider.MethodSource
2224
import org.mockito.Mock
2325
import org.mockito.junit.jupiter.MockitoExtension
2426
import org.mockito.junit.jupiter.MockitoSettings
2527
import org.mockito.kotlin.argumentCaptor
2628
import org.mockito.kotlin.eq
2729
import org.mockito.kotlin.mock
30+
import org.mockito.kotlin.never
2831
import org.mockito.kotlin.verify
2932
import org.mockito.kotlin.whenever
3033
import org.mockito.quality.Strictness
@@ -46,22 +49,33 @@ internal class W3CHttpCodecTest {
4649
@Mock
4750
lateinit var mockSetter: AgentPropagation.Setter<Any>
4851

52+
private val testedInjector = W3CHttpCodec.newInjector(emptyMap<String, String>())
53+
4954
@BeforeEach
5055
fun `set up`(forge: Forge) {
5156
whenever(mockContext.traceId).thenReturn(DDTraceId.from(forge.aLong(min = 0L)))
5257
whenever(mockContext.propagationTags).thenReturn(mock())
5358
}
5459

55-
@Test
56-
fun `M add baggage W inject { sessionId is in context }`(
57-
@StringForgery fakeSessionId: String
60+
@ParameterizedTest
61+
@MethodSource("rumContext")
62+
fun `M add baggage W inject { rum context present }`(
63+
userId: String?,
64+
accountId: String?,
65+
sessionId: String?,
66+
expected: String
5867
) {
5968
// Given
60-
val injector = W3CHttpCodec.newInjector(emptyMap<String, String>())
61-
whenever(mockContext.tags).thenReturn(mapOf(HttpCodec.RUM_SESSION_ID_KEY to fakeSessionId))
69+
whenever(mockContext.tags).thenReturn(
70+
mapOf(
71+
HttpCodec.RUM_KEY_USER_ID to userId,
72+
HttpCodec.RUM_KEY_ACCOUNT_ID to accountId,
73+
HttpCodec.RUM_KEY_SESSION_ID to sessionId
74+
)
75+
)
6276

6377
// When
64-
injector.inject(mockContext, mockCarrier, mockSetter)
78+
testedInjector.inject(mockContext, mockCarrier, mockSetter)
6579

6680
// Then
6781
argumentCaptor<String> {
@@ -71,7 +85,56 @@ internal class W3CHttpCodecTest {
7185
capture()
7286
)
7387

74-
assertThat(firstValue).isEqualTo("session.id=$fakeSessionId")
88+
assertThat(firstValue).isEqualTo(expected)
89+
}
90+
}
91+
92+
@Test
93+
fun `M not add baggage W inject { no rum context }`() {
94+
// Given
95+
whenever(mockContext.tags).thenReturn(emptyMap())
96+
97+
// When
98+
testedInjector.inject(mockContext, mockCarrier, mockSetter)
99+
100+
// Then
101+
argumentCaptor<String> {
102+
verify(mockSetter, never()).set(
103+
eq(mockCarrier),
104+
eq(W3CHttpCodec.BAGGAGE_KEY),
105+
capture()
106+
)
75107
}
76108
}
109+
110+
companion object {
111+
@Suppress("unused")
112+
@JvmStatic
113+
fun rumContext() = listOf(
114+
Arguments.of(
115+
"userId",
116+
"accountId",
117+
"sessionId",
118+
"account.id=accountId,user.id=userId,session.id=sessionId"
119+
),
120+
Arguments.of(
121+
null,
122+
"accountId",
123+
"sessionId",
124+
"account.id=accountId,session.id=sessionId"
125+
),
126+
Arguments.of(
127+
"userId",
128+
null,
129+
"sessionId",
130+
"user.id=userId,session.id=sessionId"
131+
),
132+
Arguments.of(
133+
"userId",
134+
"accountId",
135+
null,
136+
"user.id=userId,account.id=accountId"
137+
)
138+
)
139+
}
77140
}

features/dd-sdk-android-trace/src/main/kotlin/com/datadog/android/trace/internal/RumContextPropagator.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import com.datadog.android.log.LogAttributes
1515
import com.datadog.android.trace.api.span.DatadogSpan
1616
import com.datadog.android.trace.api.span.DatadogSpanBuilder
1717
import com.datadog.trace.core.DDSpan
18+
import com.datadog.trace.core.propagation.HttpCodec
1819
import java.util.concurrent.Future
1920
import java.util.concurrent.TimeUnit
2021
import java.util.concurrent.TimeoutException
@@ -61,6 +62,8 @@ class RumContextPropagator(private val sdkCoreProvider: () -> FeatureSdkCore?) {
6162
instance.setTag(LogAttributes.RUM_SESSION_ID, rumContext["session_id"])
6263
instance.setTag(LogAttributes.RUM_VIEW_ID, rumContext["view_id"])
6364
instance.setTag(LogAttributes.RUM_ACTION_ID, rumContext["action_id"])
65+
instance.setTag(HttpCodec.RUM_KEY_USER_ID, datadogContext.userInfo.id)
66+
instance.setTag(HttpCodec.RUM_KEY_ACCOUNT_ID, datadogContext.accountInfo?.id)
6467
}
6568
instance.setTag(DATADOG_INITIAL_CONTEXT, null)
6669
}

0 commit comments

Comments
 (0)