Label Loki streams with the Compose service name as service_name

Without an explicit service_name, Loki derived it from the container
label (ledgerline-sanctions-1), while spans carry service.name
"sanctions". Grafana's Tempo->Loki link selects on
{service_name="<service.name>"}, so it matched no stream. The czy agent
now sets service_name from com.docker.compose.service; `container` is
unchanged. CLAUDE.md's description of the labels is updated to match.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Movses Aslanyan
2026-10-13 21:18:55 +03:30
co-authored by Claude Opus 5.5
parent bc11638a15
commit 2c18962243
2 changed files with 17 additions and 4 deletions
+5 -3
View File
@@ -341,9 +341,11 @@ curl -s -u "$A" 'https://prometheus.vione.cloud/api/v1/status/tsdb' | jq '.data.
``` ```
**Logs (Loki)** — confirm `trace_id` is actually in the payload, not just **Logs (Loki)** — confirm `trace_id` is actually in the payload, not just
in the code that was supposed to put it there. The czy agent labels streams with in the code that was supposed to put it there. The czy agent labels each stream
the full container name (`container` and `service_name` are both e.g. with `container` (the full container name, e.g. `ledgerline-gateway-1`) and
`ledgerline-gateway-1`): `service_name` (the Compose service name, e.g. `gateway`, matching the spans'
`service.name` so Grafana's Tempo→Loki link selects the right stream). Streams
from before that relabel (2026-10-13) have `service_name` = the container name:
```bash ```bash
curl -s -u "$A" -G 'https://loki.vione.cloud/loki/api/v1/query_range' \ curl -s -u "$A" -G 'https://loki.vione.cloud/loki/api/v1/query_range' \
--data-urlencode 'query={container="ledgerline-gateway-1"} | json | trace_id != ""' \ --data-urlencode 'query={container="ledgerline-gateway-1"} | json | trace_id != ""' \
+12 -1
View File
@@ -4,7 +4,8 @@
// (ansible/roles/observability/templates/grafana-stack/config/alloy/config.alloy.j2), // (ansible/roles/observability/templates/grafana-stack/config/alloy/config.alloy.j2),
// moved here because the platform itself now runs on k3s (k8s/), where there is // moved here because the platform itself now runs on k3s (k8s/), where there is
// no Docker socket. Components are unchanged except loki.write, which pushes // no Docker socket. Components are unchanged except loki.write, which pushes
// to the cluster's Loki over HTTPS with basic auth instead of http://loki:3100. // to the cluster's Loki over HTTPS with basic auth instead of http://loki:3100,
// and one extra relabel rule that sets service_name (see below).
// //
// OTLP is NOT received here: apps send spans to the platform's Alloy at // OTLP is NOT received here: apps send spans to the platform's Alloy at
// https://otlp.vione.cloud (k8s/alloy/config.alloy). // https://otlp.vione.cloud (k8s/alloy/config.alloy).
@@ -25,6 +26,16 @@ discovery.relabel "docker" {
regex = "/(.*)" regex = "/(.*)"
target_label = "container" target_label = "container"
} }
// Not in the Ansible config. Without it Loki derives service_name from
// `container` (ledgerline-sanctions-1), while spans carry service.name
// "sanctions" -- and Grafana's Tempo->Loki link selects on
// {service_name="<service.name>"}, so it matched no stream. The Compose
// service name is the services/ directory name, i.e. the OTel service.name.
rule {
source_labels = ["__meta_docker_container_label_com_docker_compose_service"]
target_label = "service_name"
}
} }
loki.source.docker "local" { loki.source.docker "local" {