Skip to content

Commit d0c5732

Browse files
authored
Add lazy-transformer to KeyClassifier for deferred header decoding (#11466)
Add lazy-transformer to KeyClassifier for deferred header decoding Merge branch 'master' into andrea.marziali/propagators-transform Co-authored-by: andrea.marziali <andrea.marziali@datadoghq.com>
1 parent b5a08a7 commit d0c5732

2 files changed

Lines changed: 97 additions & 0 deletions

File tree

internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentPropagation.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import datadog.context.propagation.Concern;
1111
import datadog.context.propagation.Propagators;
1212
import java.util.function.BiConsumer;
13+
import java.util.function.Function;
1314
import javax.annotation.ParametersAreNonnullByDefault;
1415

1516
public final class AgentPropagation {
@@ -38,6 +39,24 @@ public static <C> AgentSpanContext.Extracted extractContextAndGetSpanContext(
3839

3940
public interface KeyClassifier {
4041
boolean accept(String key, String value);
42+
43+
/**
44+
* Variant of {@link #accept(String, String)} for carriers that store header values in a raw
45+
* form (e.g. {@code byte[]}) and want to defer string conversion until after the key is known
46+
* to be relevant.
47+
*
48+
* <p>The default implementation applies {@code transformer} eagerly and delegates to {@link
49+
* #accept(String, String)}, so existing classifiers work without any changes.
50+
*
51+
* @param key the header name
52+
* @param value the raw header value, in whatever form the carrier provides
53+
* @param transformer converts {@code value} to a string; called at most once by the default
54+
* implementation
55+
* @return {@code false} to stop iteration, {@code true} to continue
56+
*/
57+
default <T> boolean accept(String key, T value, Function<T, String> transformer) {
58+
return accept(key, transformer.apply(value));
59+
}
4160
}
4261

4362
public interface ContextVisitor<C> extends CarrierVisitor<C> {
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package datadog.trace.bootstrap.instrumentation.api;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertTrue;
5+
6+
import java.nio.charset.StandardCharsets;
7+
import java.util.concurrent.atomic.AtomicInteger;
8+
import java.util.concurrent.atomic.AtomicReference;
9+
import org.junit.jupiter.api.Test;
10+
11+
class KeyClassifierTest {
12+
13+
static class RecordingClassifier implements AgentPropagation.KeyClassifier {
14+
String lastKey;
15+
String lastValue;
16+
boolean returnValue;
17+
18+
RecordingClassifier(boolean returnValue) {
19+
this.returnValue = returnValue;
20+
}
21+
22+
@Override
23+
public boolean accept(String key, String value) {
24+
lastKey = key;
25+
lastValue = value;
26+
return returnValue;
27+
}
28+
}
29+
30+
@Test
31+
void defaultTransformerMethodAppliesTransformerAndDelegates() {
32+
RecordingClassifier classifier = new RecordingClassifier(true);
33+
34+
boolean result =
35+
classifier.accept(
36+
"my-key",
37+
"raw".getBytes(StandardCharsets.UTF_8),
38+
bytes -> new String(bytes, StandardCharsets.UTF_8));
39+
40+
assertEquals("my-key", classifier.lastKey);
41+
assertEquals("raw", classifier.lastValue);
42+
assertTrue(result);
43+
}
44+
45+
@Test
46+
void transformerIsCalledExactlyOnce() {
47+
AtomicInteger callCount = new AtomicInteger(0);
48+
AtomicReference<String> transformed = new AtomicReference<>();
49+
50+
AgentPropagation.KeyClassifier classifier =
51+
(key, value) -> {
52+
transformed.set(value);
53+
return true;
54+
};
55+
56+
classifier.accept(
57+
"key",
58+
"input",
59+
v -> {
60+
callCount.incrementAndGet();
61+
return v.toUpperCase();
62+
});
63+
64+
assertEquals(1, callCount.get());
65+
assertEquals("INPUT", transformed.get());
66+
}
67+
68+
@Test
69+
void existingAcceptStringStringContractUnchanged() {
70+
RecordingClassifier classifier = new RecordingClassifier(true);
71+
72+
boolean result = classifier.accept("trace-id", "abc123");
73+
74+
assertEquals("trace-id", classifier.lastKey);
75+
assertEquals("abc123", classifier.lastValue);
76+
assertTrue(result);
77+
}
78+
}

0 commit comments

Comments
 (0)