Skip to content

Commit 7ca0c2b

Browse files
committed
Add getAll to Getter for repeated metadata
It's known that some metadata can be repeated on a carrier. W3C baggage is one example of this in HTTP request headers. The current get API returns a String, and for performance reasons we may not want to check all headers to combine repeated headers when we don't expect there should be repeated headers. This updates the one non-deprecated main code implementation of Getter (in ObservationGrpcServerInterceptor) to implement the new getAll method.
1 parent 2a15e4b commit 7ca0c2b

File tree

2 files changed

+46
-5
lines changed

2 files changed

+46
-5
lines changed

micrometer-core/src/main/java/io/micrometer/core/instrument/binder/grpc/ObservationGrpcServerInterceptor.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@
2121
import io.grpc.ServerCall.Listener;
2222
import io.micrometer.observation.Observation;
2323
import io.micrometer.observation.ObservationRegistry;
24+
import io.micrometer.observation.transport.Propagator;
2425
import org.jspecify.annotations.Nullable;
2526

2627
import java.net.URI;
28+
import java.util.Collections;
2729
import java.util.Map;
2830
import java.util.concurrent.ConcurrentHashMap;
2931
import java.util.function.Supplier;
@@ -61,10 +63,21 @@ public ObservationGrpcServerInterceptor(ObservationRegistry registry) {
6163
public <ReqT, RespT> Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers,
6264
ServerCallHandler<ReqT, RespT> next) {
6365
Supplier<GrpcServerObservationContext> contextSupplier = () -> {
64-
GrpcServerObservationContext context = new GrpcServerObservationContext((carrier, keyName) -> {
65-
Metadata.Key<String> key = KEY_CACHE.computeIfAbsent(keyName,
66-
(k) -> Metadata.Key.of(keyName, Metadata.ASCII_STRING_MARSHALLER));
67-
return carrier.get(key);
66+
GrpcServerObservationContext context = new GrpcServerObservationContext(new Propagator.Getter<Metadata>() {
67+
@Override
68+
public @Nullable String get(Metadata carrier, String keyName) {
69+
Metadata.Key<String> key = KEY_CACHE.computeIfAbsent(keyName,
70+
(k) -> Metadata.Key.of(keyName, Metadata.ASCII_STRING_MARSHALLER));
71+
return carrier.get(key);
72+
}
73+
74+
@Override
75+
public Iterable<String> getAll(Metadata carrier, String keyName) {
76+
Metadata.Key<String> key = KEY_CACHE.computeIfAbsent(keyName,
77+
(k) -> Metadata.Key.of(keyName, Metadata.ASCII_STRING_MARSHALLER));
78+
Iterable<String> all = carrier.getAll(key);
79+
return all == null ? Collections.emptyList() : all;
80+
}
6881
});
6982
context.setCarrier(headers);
7083

micrometer-observation/src/main/java/io/micrometer/observation/transport/Propagator.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
import org.jspecify.annotations.Nullable;
1919

20+
import java.util.Collections;
21+
2022
/**
2123
* Inspired by OpenZipkin Brave and OpenTelemetry. Most of the documentation is taken
2224
* directly from OpenTelemetry.
@@ -75,14 +77,40 @@ interface Getter<C> {
7577

7678
/**
7779
* Returns the first value of the given propagation {@code key} or returns
78-
* {@code null}.
80+
* {@code null}. This method should be preferred over
81+
* {@link #getAll(Object, String)}} for better performance in cases where it is
82+
* expected that the key is not repeated.
7983
* @param carrier carrier of propagation fields, such as an http request.
8084
* @param key the key of the field.
8185
* @return the first value of the given propagation {@code key} or returns
8286
* {@code null}.
8387
*/
8488
@Nullable String get(C carrier, String key);
8589

90+
/**
91+
* Get all values of the given propagation {@code key}, if any exist. This should
92+
* only be used when it is expected that the key may be repeated.
93+
* {@link #get(Object, String)} should be preferred in other cases for
94+
* performance.
95+
* @param carrier carrier of propagation fields, such as an http request.
96+
* @param key the key of the field.
97+
* @return all values of the given propagation {@code key} or returns an empty
98+
* {@code Iterable} if no values are found.
99+
* @implNote For backward-compatibility, a default implementation is provided that
100+
* returns a list with the value of {@link #get(Object, String)} or an empty list
101+
* if no values are found. Implementors of this interface should override this
102+
* method to provide an implementation that returns all present values of the
103+
* given propagation {@code key}.
104+
* @since 1.16.0
105+
*/
106+
default Iterable<String> getAll(C carrier, String key) {
107+
String firstValue = get(carrier, key);
108+
if (firstValue == null) {
109+
return Collections.emptyList();
110+
}
111+
return Collections.singletonList(firstValue);
112+
}
113+
86114
}
87115

88116
}

0 commit comments

Comments
 (0)