Skip to content

Commit dbbe55c

Browse files
feat(context): Add non default propagator registration (#8310)
1 parent 6ec8455 commit dbbe55c

File tree

7 files changed

+101
-21
lines changed

7 files changed

+101
-21
lines changed

components/context/src/main/java/datadog/context/EmptyContext.java

+5
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,9 @@ public <T> Context with(ContextKey<T> key, @Nullable T value) {
2424
}
2525
return new SingletonContext(key.index, value);
2626
}
27+
28+
@Override
29+
public String toString() {
30+
return "EmptyContext{}";
31+
}
2732
}

components/context/src/main/java/datadog/context/IndexedContext.java

+9-4
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@ final class IndexedContext implements Context {
2323
public <T> T get(ContextKey<T> key) {
2424
requireNonNull(key, "Context key cannot be null");
2525
int index = key.index;
26-
return index < store.length ? (T) store[index] : null;
26+
return index < this.store.length ? (T) this.store[index] : null;
2727
}
2828

2929
@Override
3030
public <T> Context with(ContextKey<T> key, @Nullable T value) {
3131
requireNonNull(key, "Context key cannot be null");
3232
int index = key.index;
33-
Object[] newStore = copyOfRange(store, 0, max(store.length, index + 1));
33+
Object[] newStore = copyOfRange(this.store, 0, max(this.store.length, index + 1));
3434
newStore[index] = value;
3535
return new IndexedContext(newStore);
3636
}
@@ -40,13 +40,18 @@ public boolean equals(Object o) {
4040
if (this == o) return true;
4141
if (o == null || getClass() != o.getClass()) return false;
4242
IndexedContext that = (IndexedContext) o;
43-
return Arrays.equals(store, that.store);
43+
return Arrays.equals(this.store, that.store);
4444
}
4545

4646
@Override
4747
public int hashCode() {
4848
int result = 31;
49-
result = 31 * result + Arrays.hashCode(store);
49+
result = 31 * result + Arrays.hashCode(this.store);
5050
return result;
5151
}
52+
53+
@Override
54+
public String toString() {
55+
return "IndexedContext{store=" + Arrays.toString(this.store) + '}';
56+
}
5257
}

components/context/src/main/java/datadog/context/SingletonContext.java

+5
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,9 @@ public int hashCode() {
5757
result = 31 * result + Objects.hashCode(this.value);
5858
return result;
5959
}
60+
61+
@Override
62+
public String toString() {
63+
return "SingletonContext{" + "index=" + this.index + ", value=" + this.value + '}';
64+
}
6065
}
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package datadog.context.propagation;
22

3-
import javax.annotation.Nullable;
4-
53
@FunctionalInterface
64
public interface CarrierSetter<C> {
75
/**
@@ -11,5 +9,5 @@ public interface CarrierSetter<C> {
119
* @param key the key to set.
1210
* @param value the value to set.
1311
*/
14-
void set(@Nullable C carrier, String key, String value);
12+
void set(C carrier, String key, String value);
1513
}

components/context/src/main/java/datadog/context/propagation/Propagators.java

+52-8
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,17 @@
66
import java.util.IdentityHashMap;
77
import java.util.Map;
88

9+
/**
10+
* This class is the entrypoint of the context propagation API allowing to retrieve the {@link
11+
* Propagator} to use.
12+
*/
913
public final class Propagators {
10-
private static final Map<Concern, Propagator> PROPAGATORS =
14+
private static final Map<Concern, RegisteredPropagator> PROPAGATORS =
1115
synchronizedMap(new IdentityHashMap<>());
16+
private static final RegisteredPropagator NOOP =
17+
RegisteredPropagator.of(NoopPropagator.INSTANCE, false);
1218
private static volatile Propagator defaultPropagator = null;
13-
private static volatile boolean defaultPropagatorSet = false;
19+
private static volatile boolean rebuildDefaultPropagator = true;
1420

1521
private Propagators() {}
1622

@@ -20,14 +26,16 @@ private Propagators() {}
2026
* @return The default propagator.
2127
*/
2228
public static Propagator defaultPropagator() {
23-
if (!defaultPropagatorSet) {
29+
if (rebuildDefaultPropagator) {
2430
Propagator[] propagatorsByPriority =
2531
PROPAGATORS.entrySet().stream()
32+
.filter(entry -> entry.getValue().isUsedAsDefault())
2633
.sorted(comparingInt(entry -> entry.getKey().priority()))
2734
.map(Map.Entry::getValue)
35+
.map(RegisteredPropagator::propagator)
2836
.toArray(Propagator[]::new);
2937
defaultPropagator = composite(propagatorsByPriority);
30-
defaultPropagatorSet = true;
38+
rebuildDefaultPropagator = false;
3139
}
3240
return defaultPropagator;
3341
}
@@ -39,7 +47,7 @@ public static Propagator defaultPropagator() {
3947
* @return the related propagator if registered, a {@link #noop()} propagator otherwise.
4048
*/
4149
public static Propagator forConcern(Concern concern) {
42-
return PROPAGATORS.getOrDefault(concern, NoopPropagator.INSTANCE);
50+
return PROPAGATORS.getOrDefault(concern, NOOP).propagator();
4351
}
4452

4553
/**
@@ -89,13 +97,49 @@ public static Propagator composite(Propagator... propagators) {
8997
* @param propagator The propagator to register.
9098
*/
9199
public static void register(Concern concern, Propagator propagator) {
92-
PROPAGATORS.put(concern, propagator);
93-
defaultPropagatorSet = false;
100+
register(concern, propagator, true);
101+
}
102+
103+
/**
104+
* Registers a propagator for concern.
105+
*
106+
* @param concern The concern to register a propagator for.
107+
* @param propagator The propagator to register.
108+
* @param usedAsDefault Whether the propagator should be used as default propagator.
109+
* @see Propagators#defaultPropagator()
110+
*/
111+
public static void register(Concern concern, Propagator propagator, boolean usedAsDefault) {
112+
PROPAGATORS.put(concern, RegisteredPropagator.of(propagator, usedAsDefault));
113+
if (usedAsDefault) {
114+
rebuildDefaultPropagator = true;
115+
}
94116
}
95117

96118
/** Clear all registered propagators. For testing purpose only. */
97119
static void reset() {
98120
PROPAGATORS.clear();
99-
defaultPropagatorSet = false;
121+
rebuildDefaultPropagator = true;
122+
}
123+
124+
static class RegisteredPropagator {
125+
private final Propagator propagator;
126+
private final boolean usedAsDefault;
127+
128+
private RegisteredPropagator(Propagator propagator, boolean usedAsDefault) {
129+
this.propagator = propagator;
130+
this.usedAsDefault = usedAsDefault;
131+
}
132+
133+
static RegisteredPropagator of(Propagator propagator, boolean useAsDefault) {
134+
return new RegisteredPropagator(propagator, useAsDefault);
135+
}
136+
137+
Propagator propagator() {
138+
return this.propagator;
139+
}
140+
141+
boolean isUsedAsDefault() {
142+
return this.usedAsDefault;
143+
}
100144
}
101145
}

components/context/src/test/java/datadog/context/ContextTest.java

+11
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import static org.junit.jupiter.api.Assertions.assertEquals;
66
import static org.junit.jupiter.api.Assertions.assertFalse;
77
import static org.junit.jupiter.api.Assertions.assertNotEquals;
8+
import static org.junit.jupiter.api.Assertions.assertNotNull;
89
import static org.junit.jupiter.api.Assertions.assertNull;
910
import static org.junit.jupiter.api.Assertions.assertThrows;
1011
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -154,6 +155,16 @@ void testEqualsAndHashCode() {
154155
assertNotEquals(context4.hashCode(), context1.hashCode());
155156
}
156157

158+
@ParameterizedTest
159+
@MethodSource("contextImplementations")
160+
void testToString(Context context) {
161+
String debugString = context.toString();
162+
assertNotNull(debugString, "Context string representation should not be null");
163+
assertTrue(
164+
debugString.contains(context.getClass().getSimpleName()),
165+
"Context string representation should contain implementation name");
166+
}
167+
157168
@SuppressWarnings({"SimplifiableAssertion"})
158169
@Test
159170
void testInflation() {

components/context/src/test/java/datadog/context/propagation/PropagatorsTest.java

+18-6
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66
import static org.junit.jupiter.api.Assertions.assertEquals;
77
import static org.junit.jupiter.api.Assertions.assertFalse;
88
import static org.junit.jupiter.api.Assertions.assertNotNull;
9+
import static org.junit.jupiter.api.Assertions.assertNull;
910
import static org.junit.jupiter.api.Assertions.assertTrue;
1011

1112
import datadog.context.Context;
1213
import datadog.context.ContextKey;
1314
import java.util.HashMap;
1415
import java.util.Map;
1516
import java.util.function.BiConsumer;
16-
import javax.annotation.Nullable;
17+
import javax.annotation.ParametersAreNonnullByDefault;
1718
import org.junit.jupiter.api.AfterEach;
1819
import org.junit.jupiter.api.BeforeEach;
1920
import org.junit.jupiter.api.Test;
@@ -46,11 +47,12 @@ class PropagatorsTest {
4647
.with(DEBUGGER_KEY, "debug")
4748
.with(PROFILING_KEY, "profile");
4849

50+
@ParametersAreNonnullByDefault
4951
static class MapCarrierAccessor
5052
implements CarrierSetter<Map<String, String>>, CarrierVisitor<Map<String, String>> {
5153
@Override
52-
public void set(@Nullable Map<String, String> carrier, String key, String value) {
53-
if (carrier != null && key != null) {
54+
public void set(Map<String, String> carrier, String key, String value) {
55+
if (carrier != null && key != null && value != null) {
5456
carrier.put(key, value);
5557
}
5658
}
@@ -136,12 +138,12 @@ void testDefaultPropagator() {
136138
Propagator single = Propagators.defaultPropagator();
137139
assertInjectExtractContext(CONTEXT, single, TRACING_KEY);
138140

139-
Propagators.register(IAST, IAST_PROPAGATOR);
141+
Propagators.register(IAST, IAST_PROPAGATOR, false);
140142
Propagators.register(DEBUGGER, DEBUGGER_PROPAGATOR);
141143
Propagators.register(PROFILING, PROFILING_PROPAGATOR);
142144
Propagator composite = Propagators.defaultPropagator();
143-
assertInjectExtractContext(
144-
CONTEXT, composite, TRACING_KEY, IAST_KEY, DEBUGGER_KEY, PROFILING_KEY);
145+
assertDoNotInjectExtractContext(CONTEXT, composite, IAST_KEY);
146+
assertInjectExtractContext(CONTEXT, composite, TRACING_KEY, DEBUGGER_KEY, PROFILING_KEY);
145147
assertFalse(
146148
DEBUGGER_PROPAGATOR.keyFound,
147149
"Debugger propagator should have run before tracing propagator");
@@ -219,4 +221,14 @@ void assertInjectExtractContext(Context context, Propagator propagator, ContextK
219221
context.get(key), extracted.get(key), "Key " + key + " not injected nor extracted");
220222
}
221223
}
224+
225+
private void assertDoNotInjectExtractContext(
226+
Context context, Propagator propagator, ContextKey<?>... keys) {
227+
Map<String, String> carrier = new HashMap<>();
228+
propagator.inject(context, carrier, ACCESSOR);
229+
Context extracted = propagator.extract(root(), carrier, ACCESSOR);
230+
for (ContextKey<?> key : keys) {
231+
assertNull(extracted.get(key), "Key " + key + " was injected");
232+
}
233+
}
222234
}

0 commit comments

Comments
 (0)