Skip to main content
The Services page (at /monitoring) reads the spans in your span store as request-level metrics: request volume, error rate, and latency per service, the endpoints taking the most time, each service’s downstream calls, and the individual spans that failed. Nothing extra is ingested for it. The page reads the same OTLP spans as the trace waterfall — see Send traces — so it stays empty until spans are arriving.

The summary strip

The summary strip is the same on every tab, and covers the current service and time range: A service can serve every request successfully while its outbound calls fail, so a non-zero Error spans count next to a 0% Error rate is a valid combination.

Tabs

Below the strip, the rest of the page is tabbed. The tabs you see depend on whether a service is selected in the picker. All charts share one cursor: hovering any of them moves the readout on all. Dragging across any chart narrows the whole page to that window.

What counts as a request

Only SERVER spans (span_kind:2) are counted as requests — one span per inbound request. Client, internal, and producer/consumer spans are ignored there, so a request crossing three services counts once in each of them. A request is an error when its span status is error. The Errors tab is the exception: it lists failing spans of every kind.

How Rootprint identifies an endpoint

An endpoint name comes from the first of these that the span carries:
  1. http.route — the templated route (/users/:id)
  2. url.path
  3. http.target
  4. url.full
  5. the span name
Rows built from anything other than http.route or a path are marked, because a raw URL yields one endpoint per distinct URL: /users/1 and /users/2 become two rows instead of one. If the table reads as a long tail of near-duplicates, the fix is in the instrumentation — enable HTTP route recording in the SDK or framework instrumentation that produces those spans.

Downstream calls

The Dependencies tab groups a service’s outbound spans — client (span_kind:3) and producer (span_kind:4) — by span name, and ranks them by total time, with call count, p50, and p95. Under each call name it lists up to three peers, read from server.address, so an HTTP client span shows which hosts it called. Select a service to see it.

Failing spans

The Errors tab lists error spans newest first, one row per span: time, service, kind, operation, message, HTTP status, and duration. A row opens its trace in a new tab with that span preselected in the waterfall. The message is the span’s own status message, falling back to exception.message (then exception.type) from the first exception event on the span, truncated at 300 characters. HTTP status is read from http.response.status_code, or http.status_code from older SDKs; a span carrying neither shows . Three filters narrow the list, and each one is part of the URL:
  • Kind — server, client, producer, consumer, or internal.
  • HTTP4xx, 5xx, or spans with no HTTP status at all.
  • Top operations — chips for the 20 operations with the most errors in the range. Click one to scope the list to it.
The list loads 50 spans at a time behind Load more.

Limits

Access and auditing

Reading service health or failing spans needs logs: read — a session cookie or a personal API key. Neither is admin-only, and neither is scoped per index: any actor that can read logs can read them. Each request is recorded in the search audit like any other search, and both count against the read rate limit. See Rate limiting.
A missing span store is not an error. If TRACE_INDEX_ID points at an index that does not exist, the page reports that trace telemetry is unavailable rather than failing. See Environment variables.

Next steps

Send traces

Point an OpenTelemetry SDK or Collector at the trace endpoint.

Service health API

GET /api/monitoring/services and GET /api/monitoring/errors, the endpoints behind the page, for your own dashboards.