# Burrow Observability

The forge host imports `services.burrow.observability`, which wires the first
production observability spine:

- Prometheus on `127.0.0.1:9090`
- OpenTelemetry collector OTLP gRPC on `127.0.0.1:4317`
- OpenTelemetry collector OTLP HTTP on `127.0.0.1:4318`
- collector Prometheus export on `127.0.0.1:9464`
- Jaeger all-in-one on local ports only
- Grafana at `graphs.burrow.net`, backed by Authentik SSO

Grafana datasources are provisioned by NixOS:

- `prometheus` points at local Prometheus
- `jaeger` points at the local Jaeger query API

OpenTofu owns checked-in dashboards under `services/grafana/dashboards/`:

- `burrow-overview.json`
- `headscale.json`
- `observability.json`

## Metrics

Prometheus scrapes:

- Prometheus self metrics
- node exporter
- systemd exporter
- Grafana `/metrics`
- Headscale `/metrics` on `127.0.0.1:9098`
- OpenTelemetry collector metrics
- Jaeger admin metrics
- Garage admin metrics when `services.burrow.garage.enable = true`
- the optional Tailscale exporter when its OAuth environment file is configured

Headscale and Tailscale are treated as the same Tailnet family in dashboards.
Headscale exposes a local Prometheus listener through
`services.burrow.headscale.enableMetrics`. Tailscale SaaS metrics require the
NixOS Tailscale exporter and an OAuth environment file; the module leaves that
disabled until the credential is provisioned.

## Traces

Burrow services that emit OpenTelemetry traces should use:

```sh
OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4317
OTEL_EXPORTER_OTLP_PROTOCOL=grpc
OTEL_SERVICE_NAME=burrow
```

The collector exports traces to Jaeger. Jaeger is intentionally local-only for
now; Grafana can query it server-side through the provisioned datasource.

Headscale and Tailscale currently enter the spine through Prometheus metrics and
systemd state. If an upstream Tailnet component starts emitting OTLP, point it
at the same local collector endpoint rather than exposing Jaeger or Prometheus
directly.
