Class OtelTracerHook

java.lang.Object
org.apache.juneau.rest.server.tracing.otel.OtelTracerHook
All Implemented Interfaces:
TracerHook

public class OtelTracerHook extends Object implements TracerHook
TracerHook bridge that opens an OpenTelemetry Span for every @RestOp call.
Span shape

Each request becomes a single span with kind SpanKind.SERVER, named after the HTTP method (e.g. "GET", "POST") per the OpenTelemetry HTTP semantic conventions. Three OTel HTTP semantic-convention attributes are populated:

  • http.request.method — uppercased HTTP method.
  • http.response.status_code — HTTP response status (set right before the span is closed, so error paths get the framework's resolved status).
  • http.route — the @RestOp path template (e.g. "/users/{id}"), not the raw concrete URI. Keeps trace cardinality bounded for the same reason the Micrometer bridge uses the template as its uri tag.

On the exception path, the throwable is recorded via Span.recordException(Throwable), the span status is set to StatusCode.ERROR, and an exception.type attribute carries the exception's simple-name.

W3C trace context propagation

Incoming traceparent / tracestate request headers are extracted via the configured TextMapPropagator (default: W3CTraceContextPropagator) so the server span continues a caller-supplied distributed trace. Downstream HTTP calls made from inside the handler will pick up the active span's context automatically when the consumer's outbound HTTP client honors the OTel current context (the standard OTel client instrumentations do).

Wiring

@Configuration public class ObservabilityConfig { // Option A: rely on the JVM-wide GlobalOpenTelemetry (recommended). @Bean public TracerHook tracerHook() { return new OtelTracerHook(); } // Option B: pass a specific OpenTelemetry instance (e.g. for tests or multi-tenant setups). @Bean public TracerHook tracerHook(OpenTelemetry otel) { return new OtelTracerHook(otel); } }

See Also:
Since:
10.0.0
  • Field Details

    • DEFAULT_INSTRUMENTATION_NAME

      public static final String DEFAULT_INSTRUMENTATION_NAME
      Default tracer instrumentation scope name.
      See Also:
    • ATTR_HTTP_REQUEST_METHOD

      public static final io.opentelemetry.api.common.AttributeKey<String> ATTR_HTTP_REQUEST_METHOD
      OTel HTTP semantic-convention attribute key http.request.method.
    • ATTR_HTTP_RESPONSE_STATUS_CODE

      public static final io.opentelemetry.api.common.AttributeKey<Long> ATTR_HTTP_RESPONSE_STATUS_CODE
      OTel HTTP semantic-convention attribute key http.response.status_code.
    • ATTR_HTTP_ROUTE

      public static final io.opentelemetry.api.common.AttributeKey<String> ATTR_HTTP_ROUTE
      OTel HTTP semantic-convention attribute key http.route.
    • ATTR_EXCEPTION_TYPE

      public static final io.opentelemetry.api.common.AttributeKey<String> ATTR_EXCEPTION_TYPE
      OTel attribute key exception.type used when recording a thrown exception.
  • Constructor Details

    • OtelTracerHook

      public OtelTracerHook()
      Constructor using GlobalOpenTelemetry.get() as the OpenTelemetry source.

      Convenient when the deployment installs a single global OpenTelemetry (the dominant pattern with the OTel auto-instrumentation agent). Equivalent to new OtelTracerHook(GlobalOpenTelemetry.get()).

    • OtelTracerHook

      public OtelTracerHook(io.opentelemetry.api.OpenTelemetry openTelemetry)
      Constructor with an explicit OpenTelemetry instance.

      The instance is used to obtain both the Tracer (named "org.apache.juneau.rest.server") and the TextMapPropagator used for incoming / outgoing W3C trace-context header transfer.

      Parameters:
      openTelemetry - The OpenTelemetry instance. Must not be null.
    • OtelTracerHook

      public OtelTracerHook(io.opentelemetry.api.trace.Tracer tracer, io.opentelemetry.context.propagation.TextMapPropagator propagator)
      Constructor with an explicit Tracer and TextMapPropagator.

      Useful for tests where in-memory tracer / propagator instances are wired directly without going through a full OpenTelemetry SDK assembly.

      Parameters:
      tracer - The Tracer used to build per-request spans. Must not be null.
      propagator - The TextMapPropagator used for incoming / outgoing W3C trace-context header transfer. Must not be null.
  • Method Details

    • startSpan

      public Scope startSpan(RestRequest request)
      Description copied from interface: TracerHook
      Opens a new span for the in-flight request.
      Specified by:
      startSpan in interface TracerHook
      Parameters:
      request - The in-flight RestRequest. Never null. Bridges may read headers for distributed-tracing context propagation (e.g. W3C traceparent / tracestate), the HTTP method, the path, etc. Bridges must not mutate the request.
      Returns:
      The opened Scope. Never null. Returning null is a contract violation — bridges that cannot open a span (e.g. because the trace context is invalid) should return NoOpTracerHook.NoOpScope.INSTANCE so the framework's close-in-finally contract still holds.
    • startSpan

      public Scope startSpan(RestRequest request, TraceContextCarrier carrier, TraceOperation operation)
      Description copied from interface: TracerHook
      Opens a new span for the in-flight request, given a pre-extracted non-HTTP TraceContextCarrier and derived TraceOperation.

      Added as a source-compatible default overload so every existing TracerHook implementation — including a bare lambda implementing only TracerHook.startSpan(RestRequest) — keeps compiling unchanged. The default implementation simply delegates to TracerHook.startSpan(RestRequest), ignoring carrier and operation; a bridge only needs to override this overload if it wants to honor a non-HTTP carrier (for example MCP's params._meta) or name the span after operation instead of its own HTTP-derived default.

      Specified by:
      startSpan in interface TracerHook
      Parameters:
      request - The in-flight RestRequest. Never null.
      carrier - The TraceContextCarrier an active TraceContextExtractor recognized among the resolved operation arguments, or null if none was recognized (the bridge should then fall back to HTTP headers only).
      operation - The TraceOperation an active TraceContextExtractor derived for this invocation. Never null; TraceOperation.DEFAULT when the extractor supplied no override.
      Returns:
      The opened Scope. Never null.
    • startSpan

      public Scope startSpan(String spanName)
      Description copied from interface: TracerHook
      Opens a new span for a custom (non-request) observation.

      Unlike TracerHook.startSpan(RestRequest), this entry point is not tied to an in-flight RestRequest — 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 kind INTERNAL (rather than SERVER) named spanName.

      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 OpenTelemetry TracerHook) override it.

      Specified by:
      startSpan in interface TracerHook
      Parameters:
      spanName - The span name (e.g. "loadOrder"). Never null; never blank.
      Returns:
      The opened Scope. Never null — implementations that cannot open a span must return NoOpTracerHook.NoOpScope.INSTANCE so the close-in-finally contract holds.
    • inject

      public void inject(TraceContextCarrier carrier)
      Description copied from interface: TracerHook
      Renders this hook's active trace context (if any) into carrier.

      The substrate for TraceContexts.inject(TracerHook, TraceContextCarrier). The default implementation is a no-op — NoOpTracerHook and any bridge that does not override this method write nothing. A bridge with an actual trace context to render (for example the OpenTelemetry bridge in juneau-rest-server-tracing-otel) overrides this to write traceparent / tracestate / baggage keys via TraceContextCarrier.set(String, String).

      Specified by:
      inject in interface TracerHook
      Parameters:
      carrier - The TraceContextCarrier to write into. Never null.
    • getTracer

      public io.opentelemetry.api.trace.Tracer getTracer()
      Returns the Tracer this hook publishes spans to.
      Returns:
      The Tracer.
    • getPropagator

      public io.opentelemetry.context.propagation.TextMapPropagator getPropagator()
      Returns the TextMapPropagator used to extract W3C trace-context headers from incoming requests.
      Returns:
      The TextMapPropagator.