Class TraceContextResponseProcessor

java.lang.Object
org.apache.juneau.rest.server.tracing.TraceContextResponseProcessor
All Implemented Interfaces:
ResponseProcessor

Writes the W3C Trace Context response headers (traceparent and, when present, tracestate) so a client calling this server can read the resulting trace identifiers back off the response.
How it works

A TracerHook bridge (e.g. the OpenTelemetry bridge in juneau-rest-server-tracing-otel) renders the W3C traceparent / tracestate values from the server-started span context at span-start time — the only point where that context is reliably active — and stashes them as the request attributes ATTR_TRACEPARENT / ATTR_TRACESTATE. This processor runs later, during response rendering (after the span scope has already closed), reads those stashed strings, and writes them as response headers.

This capture-at-span-start / write-at-response-time split is deliberate: the framework opens and closes the tracing scope around the @RestOp handler in RestOpInvoker.invokeOp(RestOpSession), which completes before response processors run, so Span.current() is no longer valid here. Keeping the rendered values on the request also keeps this processor free of any OpenTelemetry (or other tracer) dependency — it works with any TracerHook bridge that populates the two attributes.

Off-by-default behavior

The first action in process(RestOpSession) is a single request-attribute read. When no non-no-op TracerHook ran for the request, no ATTR_TRACEPARENT attribute is present and the processor returns ResponseProcessor.NEXT immediately with no allocations — matching the off-by-default, zero-cost contract of the observability hooks. Registration of this processor is itself gated on RestContext.responseTraceparent (default true); setting it to false keeps the processor out of the chain entirely.

Already-committed responses

If the response has already been committed (for example a streaming / SSE handler that flushed its headers before returning), the headers can no longer be set. In that case the processor logs a FINE message and skips the write — it never throws.

See Also:
Since:
10.0.0
  • Field Details

    • ATTR_TRACEPARENT

      public static final String ATTR_TRACEPARENT
      Request-attribute key under which a TracerHook bridge stashes the rendered W3C traceparent value (e.g. 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01) for this processor to emit as a response header.
      See Also:
    • ATTR_TRACESTATE

      public static final String ATTR_TRACESTATE
      Request-attribute key under which a TracerHook bridge stashes the rendered W3C tracestate value (a comma-separated key=value list). Only set when the active trace state is non-empty.
      See Also:
    • ATTR_BAGGAGE

      public static final String ATTR_BAGGAGE
      Request-attribute key under which a TracerHook bridge stashes the rendered, non-empty W3C baggage value.

      Unlike ATTR_TRACEPARENT / ATTR_TRACESTATE, this processor does not read this attribute and never emits a baggage response header from it — baggage is stashed purely so a dated MCP adapter can echo it into a successful result's _meta (added in a later task). Ordinary HTTP response-header behavior for traceparent / tracestate is unaffected by this constant's existence.

      Since:
      10.0.0
      See Also:
    • ATTR_SCOPE

      public static final String ATTR_SCOPE
      Request-attribute key under which RestOpInvoker stashes the active Scope for the duration of one @RestOp handler invocation.

      Populated only on the active-tracer path — see the no-tracer fast-path contract documented on TracerHook — and cleared once that invocation's synchronous or deferred observability lifecycle closes the scope. A dated MCP adapter running inside the handler already resolves this same RestRequest through its own request-scoped BeanStore entry; reading this attribute off that request lets it call Scope.recordRpcError(int, String) before returning a JSON-RPC error response — a JSON-RPC error is dispatched over HTTP 200, so it never otherwise reaches Scope.setStatusCode(int) with anything but the adapter's uniform success status.

      Since:
      10.0.0
      See Also:
  • Constructor Details

  • Method Details

    • process

      public int process(RestOpSession opSession) throws IOException, BasicHttpException
      Description copied from interface: ResponseProcessor
      Process this response if possible.
      Specified by:
      process in interface ResponseProcessor
      Parameters:
      opSession - The HTTP call.
      Returns:
      One of the following codes:
      • 0 - The processor could not handle the request.
      • 1 - The processor was able to fully handle the request.
      • 2 - The processor was able to partially handle the request by replacing the output. The response processors should start over.
      Throws:
      IOException - If low-level exception occurred on output stream.
      Results in a HttpServletResponse.SC_INTERNAL_SERVER_ERROR error.
      BasicHttpException - If some other exception occurred.
      Can be used to provide an appropriate HTTP response code and message.