Interface TracerHook
- All Known Implementing Classes:
NoOpTracerHook,OtelTracerHook
- Functional Interface:
- This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.
juneau-rest-server.
startSpan(RestRequest) fires immediately before every @RestOp handler runs —
the returned Scope is closed by the framework after the handler completes (including the
exception path). Bridge implementations create whatever the downstream tracer expects (an
OpenTelemetry io.opentelemetry.api.trace.Span, a Brave Span, an application
tracing object, etc.) and surface the close / status / error transitions through the Scope.
Off-by-default contract
juneau-rest-server resolves the TracerHook via
RestContext.getBeanStore().getBean(TracerHook.class). When no bean is supplied,
NoOpTracerHook.INSTANCE is used — the framework never reaches for a tracer, never
inspects headers for W3C trace context, and adds no per-request cost beyond a single static-field
read plus a single AutoCloseable.close() on a singleton noop scope. To opt in, the consumer
registers a TracerHook bean — typically via @Bean TracerHook on the resource
or its parent.
Usage
Lifecycle
For each @RestOp invocation, the framework:
- Calls
startSpan(RestRequest)just before parameter resolution, passing the in-flightRestRequestso the bridge can read trace-context headers (traceparent/tracestate) and set request-derived attributes. - Runs the handler (which may throw).
- Calls
Scope.setStatusCode(int)with the resolved response status, thenScope.setError(Throwable)if the handler threw, thenScope.close()— always in afinallyblock so the span closes even on exception.
Implementations must be thread-safe — the same TracerHook bean is invoked
concurrently from every request thread for the lifetime of the RestContext.
See Also:
- Since:
- 10.0.0
-
Method Summary
Modifier and TypeMethodDescriptiondefault voidinject(TraceContextCarrier carrier) Renders this hook's active trace context (if any) intocarrier .default ScopeOpens a new span for a custom (non-request) observation.startSpan(RestRequest request) Opens a new span for the in-flight request.default ScopestartSpan(RestRequest request, TraceContextCarrier carrier, TraceOperation operation) Opens a new span for the in-flight request, given a pre-extracted non-HTTPTraceContextCarrierand derivedTraceOperation.
-
Method Details
-
startSpan
Opens a new span for the in-flight request.- Parameters:
request- The in-flightRestRequest. Nevernull . Bridges may read headers for distributed-tracing context propagation (e.g. W3Ctraceparent/tracestate), the HTTP method, the path, etc. Bridges must not mutate the request.- Returns:
- The opened
Scope. Nevernull . Returningnullis a contract violation — bridges that cannot open a span (e.g. because the trace context is invalid) should returnNoOpTracerHook.NoOpScope.INSTANCEso the framework's close-in-finally contract still holds.
-
startSpan
Opens a new span for a custom (non-request) observation.Unlike
startSpan(RestRequest), this entry point is not tied to an in-flightRestRequest— it is the substrate for the explicit programmatic observation API (Observations) so application code can trace an arbitrary block of work that has no associated HTTP request. Bridge implementations typically open a span of kindINTERNAL(rather thanSERVER) namedspanName.The default implementation returns
NoOpTracerHook.NoOpScope.INSTANCE— a bridge that does not override this method simply does not trace custom observations, and the no-backend path stays zero-allocation. Both shipped bridges (the OpenTelemetryTracerHook) override it.- Parameters:
spanName- The span name (e.g."loadOrder"). Nevernull ; never blank.- Returns:
- The opened
Scope. Nevernull — implementations that cannot open a span must returnNoOpTracerHook.NoOpScope.INSTANCEso the close-in-finally contract holds.
-
startSpan
Opens a new span for the in-flight request, given a pre-extracted non-HTTPTraceContextCarrierand derivedTraceOperation.Added as a source-compatible default overload so every existing
TracerHookimplementation — including a bare lambda implementing onlystartSpan(RestRequest)— keeps compiling unchanged. The default implementation simply delegates tostartSpan(RestRequest), ignoringcarrier andoperation ; a bridge only needs to override this overload if it wants to honor a non-HTTP carrier (for example MCP'sparams._meta) or name the span afteroperation instead of its own HTTP-derived default.- Parameters:
request- The in-flightRestRequest. Nevernull .carrier- TheTraceContextCarrieran activeTraceContextExtractorrecognized among the resolved operation arguments, ornull if none was recognized (the bridge should then fall back to HTTP headers only).operation- TheTraceOperationan activeTraceContextExtractorderived for this invocation. Nevernull ;TraceOperation.DEFAULTwhen the extractor supplied no override.- Returns:
- The opened
Scope. Nevernull .
-
inject
Renders this hook's active trace context (if any) intocarrier .The substrate for
TraceContexts.inject(TracerHook, TraceContextCarrier). The default implementation is a no-op —NoOpTracerHookand any bridge that does not override this method write nothing. A bridge with an actual trace context to render (for example the OpenTelemetry bridge injuneau-rest-server-tracing-otel) overrides this to writetraceparent/tracestate/baggagekeys viaTraceContextCarrier.set(String, String).- Parameters:
carrier- TheTraceContextCarrierto write into. Nevernull .
-