Sentinel combines application metrics, persisted domain state, Docker and host telemetry, and centralized logs. The stack is provisioned by docker-compose.yml; no manual Grafana datasource or dashboard setup is required.
Prometheus scrapes every 15 seconds:
| Job | Internal target | Category | Purpose |
|---|---|---|---|
sentinel-backend |
backend:8000/metrics |
Application | API HTTP behavior and Sentinel domain monitoring |
cadvisor |
cadvisor:8080 |
Containers | CPU, memory, filesystem, network, and lifecycle telemetry for real Docker containers |
node-exporter |
node-exporter:9100 |
Host | Host CPU, memory, load, filesystem, disk, and network telemetry |
prometheus-fastapi-instrumentator provides received-request metrics such as http_requests_total and http_request_duration_seconds. /metrics itself is excluded from HTTP instrumentation.
These HTTP metrics are distinct from Sentinel's outbound domain metrics:
| Metric | Type | Labels | Meaning |
|---|---|---|---|
sentinel_health_checks_total |
Counter | service_id, status |
Total completed outbound health checks, labelled online, degraded, or offline |
sentinel_health_check_duration_seconds |
Histogram | service_id |
Complete outbound health-check execution duration in seconds |
sentinel_open_incidents |
Gauge | none | Current persisted count of incidents with status=open |
sentinel_service_availability_ratio |
Gauge | service_id |
Persisted availability in the preceding 24 hours: online checks divided by all checks |
For availability, degraded and offline checks are unavailable. Checks outside the UTC 24-hour window are excluded, and a service with no checks in the window emits no sample.
The incident and availability gauges query PostgreSQL on each scrape. Sessions are closed on success and failure. When database state is unknown, the affected collector omits its metric instead of emitting a misleading zero or breaking unrelated metrics.
Metric labels deliberately exclude service URL, service name, environment, reason, error messages, and exception text.
Prometheus loads exactly five rules from infra/prometheus/alerts.yml:
| Alert | Expression | For | Severity | Operational meaning |
|---|---|---|---|---|
SentinelBackendDown |
up{job="sentinel-backend"} == 0 |
2m | critical | Prometheus cannot scrape the backend |
SentinelServiceAvailabilityLow |
sentinel_service_availability_ratio < 0.95 |
5m | warning | A service's persisted 24-hour availability is below 95% |
SentinelOpenIncidents |
sentinel_open_incidents > 0 |
2m | warning | One or more persisted incidents remain open |
SentinelIncidentMetricMissing |
absent(sentinel_open_incidents) and on() (up{job="sentinel-backend"} == 1) |
2m | warning | The backend is scrapeable but the database-backed incident metric is absent |
SentinelHealthCheckLatencyHigh |
histogram_quantile(0.95, sum by (le, service_id) (rate(sentinel_health_check_duration_seconds_bucket[5m]))) > 2 |
5m | warning | Outbound health-check p95 exceeds two seconds for a service |
The missing-metric rule requires up == 1, avoiding a duplicate signal when the backend itself is down. None of the rules invents zero for an absent domain metric.
Prometheus forwards alerts to alertmanager:9093. Alertmanager is active with an internal default receiver but has no email, Slack, Discord, or other external destination configured.
Provisioning creates:
- Prometheus datasource
Sentinel Prometheus, UIDsentinel-prometheus; - Loki datasource
Sentinel Loki, UIDsentinel-loki; - dashboard UID
sentinel-overview, titled Sentinel Overview, with 38 panels.
The dashboard separates Sentinel monitoring, API/runtime behavior, host/container infrastructure, and logs. Its domain panels show:
- current open incidents;
- 24-hour availability as a percentage per
service_id; - check rate by
service_idand status; - p95 outbound check duration per
service_id; - recent checks grouped by status.
The service_id variable supports multi-selection and an All option. The dashboard intentionally does not require service names or URLs as Prometheus labels.
The backend writes structured-looking JSON log lines to stdout. Promtail uses Docker service discovery through the read-only Docker socket, parses Docker log envelopes, and attaches:
container;compose_service;compose_project;stream;job=docker-containers.
Promtail sends records to Loki at http://loki:3100/loki/api/v1/push. Grafana queries Loki through the provisioned datasource. Alert delivery logs mask channel targets; database-backed metric collection errors are generic and omit database exception details.
Loki, Prometheus, Alertmanager, and Grafana use named volumes. Promtail's position file is local to its container and is not backed by a named volume.
| Check | Command or endpoint | Interpretation |
|---|---|---|
| API process | curl --fail http://localhost/health |
FastAPI is responding; this endpoint does not query PostgreSQL |
| PostgreSQL | docker compose exec postgres pg_isready -U sentinel -d sentinel |
Database accepts connections |
| Prometheus | curl --fail http://localhost:9090/-/healthy |
Prometheus process is healthy |
| Backend scrape | query up{job="sentinel-backend"} in Prometheus |
Value 1 confirms a successful scrape |
| Grafana | curl --fail http://localhost:3000/api/health |
Grafana process and internal database are healthy |
| Compose state | docker compose ps |
Container state and health checks |
- Filter the Sentinel UI by
offlineand inspect the service's latest HTTP status and error. - Review its check history and open incident in the UI/API.
- In Grafana, select its
service_idand compare check results with p95 duration. - Query Loki with
{compose_service="backend"}around the failed check. - Verify the target URL independently from an equivalent network location; Sentinel may be healthy while the monitored target or route is not.
- Inspect the Health-check latency p95 panel for the affected
service_id. - Compare it with status changes and
SentinelHealthCheckLatencyHigh. - Check backend CPU/memory and cAdvisor telemetry to distinguish target latency from local resource pressure.
- Review backend logs for timeouts or repeated network failures.
- Confirm
sentinel_open_incidentsand inspect the incident in Sentinel. - Check whether recent results remain degraded/offline and whether the service is still active.
- Review notification history to distinguish incident persistence from delivery failure.
- If
SentinelIncidentMetricMissingis firing instead, inspect PostgreSQL connectivity and backend collector logs; absence is not treated as zero.
-
Run
docker compose psand inspect its state:docker inspect --format '{{.RestartCount}} {{.State.OOMKilled}} {{.State.ExitCode}}' sentinel-<service>-1
-
Correlate cAdvisor memory/CPU with container logs in Loki.
-
Use
docker compose logs --since=15m <service>for startup errors. -
Check whether the configured CPU or memory limit is too close to observed use before changing it.
- Confirm Loki and Promtail are running with
docker compose ps. - Inspect
docker compose logs promtailfor Docker discovery or push errors. - Confirm the Docker socket is mounted read-only and the expected container has a
compose_servicelabel. - Query Loki's label endpoint or Grafana Explore for the expected
compose_project="sentinel". - Check Loki logs and storage availability if Promtail discovers containers but pushes fail.
- There is no distributed tracing.
- Alertmanager has no external notification receiver.
- Prometheus and Loki use local retention/sizing suitable for demonstration, not a production capacity plan.
- Promtail is tied to the local Docker socket.
- The API health endpoint verifies process responsiveness, not database health.