Class HttpTraceHeaderCarrier
@Logged call chain's FlowContext across a
synchronous HTTP call, by writing it into the outgoing request's headers
and reading it back from the incoming request's headers.
Unlike KafkaTraceHeaderCarrier
and RabbitTraceHeaderCarrier,
which operate on one concrete header type each (Headers,
MessageProperties), no single header type is common to every HTTP
client a consuming application might use — RestTemplate, Feign,
WebClient, and a hand-rolled HttpURLConnection each expose
headers through a different API. This class instead operates on plain
BiConsumer/Function references, so it can be pointed at
whichever client's own header-writing/reading method already exists:
// RestTemplate / a plain HttpHeaders instance
HttpTraceHeaderCarrier.writeToHeaders(headers::set);
// Feign
HttpTraceHeaderCarrier.writeToHeaders(requestTemplate::header);
// java.net.HttpURLConnection
HttpTraceHeaderCarrier.writeToHeaders(connection::setRequestProperty);
HttpTraceClientHttpRequestInterceptor,
FeignTraceRequestInterceptor,
HttpTraceExchangeFilterFunction,
and HttpTraceServletFilter are
ready-made integrations built on top of this class for
RestTemplate, Feign, WebClient, and inbound Servlet
requests, respectively. A consuming application using a different HTTP
client can still participate in cross-service tracing by calling this
class directly, the same way those four classes do internally.
Only the traceId and depth cross the wire — never any
other request data — under the "X-Logged-Trace-Id"/
"X-Logged-Depth" header names.
Unlike KafkaTraceHeaderCarrier/
RabbitTraceHeaderCarrier,
whose message headers typically originate from another of a consuming
application's own services, an HTTP request's headers can originate from
a completely untrusted caller if the endpoint receiving it is reachable
from outside the application's own trust boundary. Without validation, an
external caller could set TRACE_ID_HEADER to an arbitrary string
— including one crafted to look like a fabricated log line, if it
contains characters like \n and the receiving side's logging
pattern does not escape them — which would then flow, unexamined, into
this thread's @Logged log output and MDC. readAndAdopt(java.util.function.Function<java.lang.String, java.lang.String>, java.lang.Runnable)
therefore only accepts a TRACE_ID_HEADER value that matches the
same shape this library itself always produces (a short hexadecimal
string, see FlowContext.root());
anything else is treated exactly like a missing header, not merely
logged-but-rejected, so no attacker-controlled string ever reaches this
thread's context at all.
-
Field Summary
Fields -
Method Summary
Modifier and TypeMethodDescriptionstatic voidreadAndAdopt(Function<String, String> headerReader, Runnable work) Reads aFlowContextthroughheaderReader, if present, adopts it as the active context on this thread for the duration ofwork, and restores this thread's previous context again afterward, regardless of whetherworkcompletes normally or throws.static voidwriteToHeaders(BiConsumer<String, String> headerWriter) Writes the current thread'sFlowContext, if any is active, throughheaderWriterunderTRACE_ID_HEADER/DEPTH_HEADER.
-
Field Details
-
TRACE_ID_HEADER
- See Also:
-
DEPTH_HEADER
- See Also:
-
-
Method Details
-
writeToHeaders
Writes the current thread'sFlowContext, if any is active, throughheaderWriterunderTRACE_ID_HEADER/DEPTH_HEADER.Does nothing if no
@Loggedcall is currently active on this thread: an outgoing request made from outside any call chain simply carries no trace headers, exactly as if this method had never been called.- Parameters:
headerWriter- a reference to the target's own(name, value) -> voidheader-writing method
-
readAndAdopt
Reads aFlowContextthroughheaderReader, if present, adopts it as the active context on this thread for the duration ofwork, and restores this thread's previous context again afterward, regardless of whetherworkcompletes normally or throws.If no
TRACE_ID_HEADERis found, or its value does not matchVALID_TRACE_ID— for example, a request from a caller that does not use this library, or one crafted by an untrusted caller to inject something other than a real trace id —workis simply run as-is, with no context adopted. Any@Loggedcall made from within it then starts a new chain of its own, exactly as it would without this class involved at all.- Parameters:
headerReader- a reference to the source's own(name) -> Stringheader-reading method; may returnnullfor a missing headerwork- the request-handling code to run with the incoming request's trace context active
-