Files
infra-observability/k8s/grafana/provisioning/datasources.yaml
T
Stéphane Tailland 367ebd1da5 Add a traces dashboard and make the span correlations work
Trace search lived only in Explore. `obs-traces` brings it into a dashboard:
TraceQL assembled from a service selector, a minimum duration, a status and a
free-text field, plus the aggregate RED view from the span metrics Tempo derives
from the traces themselves.

The status and free-text variables hold TraceQL fragments rather than values, so
an empty one contributes nothing and the query stays valid — the same reason the
log dashboards inject their search term the way they do.

Both span correlations were declared but non-functional.

tracesToLogsV2 mapped service.name onto Loki's `app` label, which Alloy derives
from app.kubernetes.io/name. That label exists for Keycloak and the Classic
Models API but not for the six Kong gateways or LibreChat — and the gateways are
the only place the trace id actually appears in the logs, so the mapping pointed
squarely at the services where it could not resolve. Replaced with a custom
query on ${__trace.traceId}, which matches any source writing the id anywhere in
the line.

tracesToMetrics had no queries at all and rendered a bare datasource link. It
now carries rate, error-rate and p95 against traces_spanmetrics_*, scoped to the
span's own service.

The service graph stays a table: serviceMap is a query type Grafana's frontend
assembles for Explore and returns no frames through the dashboard query API.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 07:44:57 +02:00

106 lines
3.5 KiB
YAML

# Declarative datasource provisioning.
# The `uid` values are STABLE and are what dashboard JSON files reference:
# "datasource": { "type": "prometheus", "uid": "prometheus" }
apiVersion: 1
deleteDatasources:
- name: Prometheus
orgId: 1
- name: Loki
orgId: 1
- name: Tempo
orgId: 1
datasources:
- name: Prometheus
uid: prometheus
type: prometheus
access: proxy
orgId: 1
url: http://prometheus:9090
isDefault: true
editable: false
jsonData:
httpMethod: POST
timeInterval: 30s
manageAlerts: false
exemplarTraceIdDestinations:
- name: trace_id
datasourceUid: tempo
- name: Loki
uid: loki
type: loki
access: proxy
orgId: 1
url: http://loki:3100
editable: false
jsonData:
timeout: 60
maxLines: 1000
# Logs -> traces: a trace_id in the log line opens Tempo.
derivedFields:
- name: TraceID
matcherType: regex
matcherRegex: '"?trace[_-]?id"?[:=]"?([a-f0-9]{16,32})'
url: '$${__value.raw}'
datasourceUid: tempo
urlDisplayLabel: View trace
- name: Tempo
uid: tempo
type: tempo
access: proxy
orgId: 1
url: http://tempo:3200
editable: false
jsonData:
httpMethod: GET
streamingEnabled:
search: true
metrics: true
# Service graph fed by the metrics_generator -> Prometheus.
serviceMap:
datasourceUid: prometheus
nodeGraph:
enabled: true
# Span -> logs by trace id rather than by service name.
#
# The service-name mapping this replaces resolved `service.name` to Loki's
# `app` label, which Alloy derives from app.kubernetes.io/name. That label
# exists for keycloak and classic-models-api but not for the six Kong
# gateways or librechat — and the gateways are precisely where the trace
# id does appear in the logs. The mapping pointed at the services where it
# could not work.
#
# A custom query on ${__trace.traceId} sidesteps the label entirely: every
# source that writes the id anywhere in the line is matched. The stream
# selector is spelled out rather than `.+` so the query stays bounded.
tracesToLogsV2:
datasourceUid: loki
spanStartTimeShift: -1h
spanEndTimeShift: 1h
filterByTraceID: false
filterBySpanID: false
customQuery: true
query: '{job=~"kong-audit|keycloak/keycloak|classic-models/classic-models-api|librechat/librechat"} |= "$${__trace.traceId}"'
# Span -> metrics against the span metrics Tempo's own metrics_generator
# feeds into Prometheus. Without explicit queries this block renders a
# bare datasource link and nothing else, which is what it did before.
# $$__tags expands to the tag mapping below, so each query is scoped to
# the span's own service.
tracesToMetrics:
datasourceUid: prometheus
spanStartTimeShift: -30m
spanEndTimeShift: 30m
tags:
- key: service.name
value: service
queries:
- name: 'Request rate'
query: 'sum by (span_name) (rate(traces_spanmetrics_calls_total{$$__tags}[$$__rate_interval]))'
- name: 'Error rate'
query: 'sum by (span_name) (rate(traces_spanmetrics_calls_total{$$__tags,status_code="STATUS_CODE_ERROR"}[$$__rate_interval]))'
- name: 'Latency p95'
query: 'histogram_quantile(0.95, sum by (span_name, le) (rate(traces_spanmetrics_latency_bucket{$$__tags}[$$__rate_interval])))'