Tracing and propagation
Span names and attributes
ClientSpanDataProvider.openTelemetry and ServerSpanDataProvider.openTelemetry provide span
names and attributes that follow the OpenTelemetry HTTP semantic conventions. Client spans have
kind Client. Server spans have kind Server.
Span names contain a known request method and a URL template or route when configured, such as
GET /users/{id}. Unknown methods use HTTP in span names and _OTHER in the method
attribute.
Providers supply names, request attributes, response attributes and exception attributes.
Implement SpanDataProvider for custom behavior, or use the OpenTelemetry provider's builder
methods to add attributes. Header capture is disabled by default.
URL and header redaction
A client provider needs a UriRedactor. A server provider needs a path and query redactor.
These control which parts of a URL appear in span attributes. For example:
import org.http4s.otel4s.middleware.trace.client.{ClientSpanDataProvider, UriRedactor}
import org.http4s.otel4s.middleware.trace.redact.{HeaderRedactor, QueryRedactor}
val redactor = new UriRedactor.OnlyRedactUserInfo with QueryRedactor.RedactSensitive {
override def sensitiveQueryParameters: Set[String] =
QueryRedactor.DefaultSensitiveQueryParameters ++ Set("access_token", "api_key")
}
val spanDataProvider = ClientSpanDataProvider.openTelemetry(redactor)
.optIntoHttpRequestHeaders(HeaderRedactor.default)
OnlyRedactUserInfo masks URI credentials but keeps paths, query values and fragments. Adding
RedactSensitive also masks values for selected query keys. Matching is case-sensitive.
Overriding sensitiveQueryParameters replaces the defaults, so extend the set when you want to
preserve them. Only the selected keys are masked. Check whether paths, fragments or other query
parameters contain sensitive values too.
Server providers accept a redactor such as new PathRedactor.NeverRedact with
QueryRedactor.RedactSensitive {}. If paths contain sensitive data, provide a redactor that
masks it. Redaction changes the span attributes. The HTTP request sent to the service stays the
same.
Context across a request
With combined client and server instrumentation, context flows like this:
caller span
└─ client HTTP span ── propagated request headers ──► server HTTP span
request/response body effects app/response body effects
Client request propagation is enabled by default for traced requests. The server extracts the incoming context, including baggage. Configure propagators on your otel4s backend. The middleware uses those propagators to read and write context headers.
Request and response body effects keep the HTTP context even when they run later. The code that consumes the body keeps its own context. Use the meter provider, tracer provider and context manager from the same telemetry instance.
If the tracing filter disables tracing for a request, the combined middleware also skips context injection on the client and context extraction on the server. Disabling only the propagation filter still allows the client to create a local span. Metrics use a separate filter. See Filtering and errors.
Response propagation
Server response propagation is disabled by default. Use
ServerTracingConfig.withReversePropagationFilter to choose which responses get context
headers. This setting does not affect context extraction from incoming requests. Other response
headers stay unchanged.
When spans end
The combined middleware ends its span after recording metrics, once the body finishes or an unread client response is released.
The tracing-only builders end spans at different points. Client spans end when the response resource is released. Server spans end when the app returns a response. See Streaming lifecycle before choosing an API.