Skip to content

Spans

Span capture, per-trace span viewing, span deletion, and the HTTP span diagnostic command are provided by the native_observability_spans submodule. It is part of the RAW install tier; enable it with drush no:preset:raw, or directly with drush en native_observability_spans -y.

Routes

Route Path Permission
native_observability_spans.trace_spans /admin/reports/native-observability/traces/{id}/spans view native observability traces
native_observability_spans.trace_spans_delete /admin/reports/native-observability/trace/{id}/spans/delete delete all native observability traces
native_observability_spans.spans_delete_all /admin/reports/native-observability/spans/delete-all delete all native observability traces

Span capture

Spans record timed units of work inside a request. They are written through SpanRecorderInterface::startSpan() / endSpan(), and correlated to a trace by request_id. Three sources feed the span table:

  • Outbound HTTP calls. GuzzleSpanMiddleware is pushed onto the shared Guzzle handler stack (tagged http_client_middleware), so every outbound request made through Drupal's http_client produces a span under the http.client category. Callers can pass a native_observability request option with a subtype and/or name to get a more specific category (http.client.<subtype>) and a custom span name. A call made from cron or from drush produces a span too, with no request id, because no HTTP request is behind it. Those spans carry no trace either, so they never appear under a single trace, but they are counted in the Response Time breakdown on the Overview tab. That is how an outbound call started from the command line shows up at all. The stored uri, url, target and error_message never carry credentials: the password in https://user:pass@host and the value of any query parameter whose name is sensitive are replaced with [REDACTED], the same rule applied to request parameters. Which names are sensitive is set by capture.sensitive_keys and the whole rule can be switched off with capture.redact_sensitive_keys, see Sensitive keys. With the switch off, nothing is redacted, the user:password part included. Request headers are not stored, and of the request options only timeouts and a few boolean flags are kept. The error_message of a failed call is cut before the response excerpt that Guzzle appends, and the URLs left in it are redacted.
  • Request summary. RequestSummarySpanSubscriber writes one synthetic HTTP request summary span per response, enriched through tagged RequestSummaryEnrichmentProviderInterface providers contributed by other modules.
  • Database summary. DatabaseSummarySpanSubscriber optionally writes one synthetic database summary span per response when native_observability_database_observer is enabled. It has no hard dependency on that module: if it is absent, span capture continues without it.

The payload of a custom span is capped at spans_payload_max_bytes. A larger one is stored as a marker with _truncated, _original_bytes and a _preview, see Custom span payloads.

Viewing spans for a trace

Open a trace detail page and follow through to /admin/reports/native-observability/traces/{id}/spans, or navigate there directly with the trace's numeric ID. TraceSpansController::build() loads the trace, then loads its spans by request_id (falling back to loadByTraceId() when no request-ID match exists), and renders a table with span ID, parent span ID, name, category, duration, start and end timestamps.

The page exposes two actions: Back to trace and Delete spans.

Deleting spans

For a single trace

/admin/reports/native-observability/trace/{id}/spans/delete opens DeleteTraceSpansForm. It loads the trace, resolves its request_id, and on confirmation deletes every span matching that request_id via SpanStorageInterface::deleteByRequestId(). It redirects back to the trace detail page.

All spans

/admin/reports/native-observability/spans/delete-all opens DeleteAllSpansForm, which deletes every stored span via SpanStorageInterface::deleteAll(). Confirming or cancelling returns to the trace listing. Spans have no listing of their own, and nothing in the interface links to this route, so reaching it means typing the URL.

Drush: HTTP span diagnostic

native-observability-span:http-test (alias nos:http-test) drives a fixed set of outbound HTTP requests through Drupal's global http_client service to verify that span generation is wired up correctly. It is a diagnostic tool, not a data source: it does not read or write trace data directly, it only exercises the same code path outbound application traffic uses.

drush native-observability-span:http-test
drush nos:http-test --timeout=15 --connect-timeout=5

Options:

  • --timeout: request timeout in seconds. Defaults to 8.
  • --connect-timeout: connection timeout in seconds. Defaults to 4.

The command calls five targets (a 200 response, a 204 response, a 200 and a 503 from httpbin, and one request to a domain designed to fail DNS resolution) and prints a table with status code, error, and a truncated response body for each. Check /admin/reports/native-observability/execution or the spans list of a fresh trace afterward to confirm each call produced an http.client span.