chore(observability): externalize stack from root compose files
Manage now connects to existing Grafana/Prometheus/Alertmanager instances and never deploys its own stack. - docker-compose.yml / docker-compose.dev.yml: removed prometheus, loki, alloy, grafana, alertmanager, node-exporter services, the monitoring network, and observability named volumes; they now ship only backend + frontend. Dev frontend now joins the web network so the Vite dev proxy can reach the backend. - backend: alertmanager_url default is now empty; /api/monitoring/alerts and /alertmanager-status return graceful "not configured" responses when ALERTMANAGER_URL is unset. Added not-configured tests. - docker-compose.observability.yml: kept as the optional standalone example; header clarifies Manage does not deploy it. - Removed orphaned combined monitoring/prometheus/prometheus.yml (standalone stack uses prometheus.standalone.yml). - Docs (README, REQUIREMENTS decision log, monitoring-logging-design, observability-runbooks, context.md, MIGRATION_PLAN, frontend/README, CHANGELOG) updated to the connect-to-existing model. VITE_GRAFANA_URL / VITE_PROMETHEUS_URL remain as optional frontend deep-link overrides. .env.example still needs a manual update (safety policy blocks assistant edits): set ALERTMANAGER_URL empty/optional and move standalone-only vars out of the root file.
This commit is contained in:
+28
-2
@@ -1,6 +1,16 @@
|
||||
# Code Context
|
||||
|
||||
> **Status (2026-06-23):** Manage no longer deploys an observability stack.
|
||||
> The root `docker-compose.yml` / `docker-compose.dev.yml` ship **only** the
|
||||
> backend and frontend; Grafana, Prometheus, Loki, Alertmanager, Alloy, and Node
|
||||
> Exporter were removed from them. Manage connects to **existing** instances.
|
||||
> The standalone example stack lives in `docker-compose.observability.yml`. Some
|
||||
> snippets below still reference the former in-compose services and are kept as
|
||||
> historical context; treat `docker-compose.observability.yml` as authoritative
|
||||
> for the stack layout.
|
||||
|
||||
## Files Retrieved
|
||||
|
||||
1. `docker-compose.yml` (lines 1–262) – production Compose stack; defines observability services and Traefik routing.
|
||||
2. `docker-compose.dev.yml` (lines 1–234) – development Compose stack; same observability services but with host ports exposed and auth disabled.
|
||||
3. `.env.example` (lines 1–55) – template with all required environment variables for the stack, including Prometheus/Grafana/Alertmanager/Alloy/Loki and Node Exporter settings.
|
||||
@@ -20,7 +30,9 @@
|
||||
## Key Code
|
||||
|
||||
### Backend `/metrics` endpoint
|
||||
|
||||
`backend/src/media_library_viewer_api/main.py`:
|
||||
|
||||
```python
|
||||
@app.middleware("http")
|
||||
async def enforce_jwt_auth(request: Request, call_next):
|
||||
@@ -36,7 +48,9 @@ def metrics() -> Response:
|
||||
```
|
||||
|
||||
### Metrics emitted by the backend
|
||||
|
||||
`backend/src/media_library_viewer_api/observability.py`:
|
||||
|
||||
```python
|
||||
REQUESTS_TOTAL = Counter("manage_api_requests_total", "Total API requests", ["method", "path", "status_code"])
|
||||
REQUEST_DURATION = Histogram("manage_api_request_duration_seconds", "API request duration", ["method", "path"], ...)
|
||||
@@ -48,7 +62,9 @@ MAIL_QUEUE_SIZE = Counter("manage_mail_queue_messages_total", "Total messages en
|
||||
```
|
||||
|
||||
### Prometheus scrape configuration
|
||||
|
||||
`monitoring/prometheus/prometheus.yml`:
|
||||
|
||||
```yaml
|
||||
scrape_configs:
|
||||
- job_name: manage-backend
|
||||
@@ -71,7 +87,9 @@ scrape_configs:
|
||||
```
|
||||
|
||||
### Backend-managed remote Node Exporter targets
|
||||
|
||||
`backend/src/media_library_viewer_api/services/targets.py`:
|
||||
|
||||
```python
|
||||
def build_node_exporter_targets(store: SettingsStore) -> list[dict[str, Any]]:
|
||||
...
|
||||
@@ -96,6 +114,7 @@ The observability stack is a standard self-hosted Prometheus/Grafana/Loki/Alertm
|
||||
- **Alertmanager** routes alerts by severity (critical vs warning) and delivers email notifications (and optionally a webhook back to the backend).
|
||||
|
||||
The backend bridges the stack with the application:
|
||||
|
||||
- It exposes `/metrics` (unauthenticated, along with `/api/health` and `/api/version`).
|
||||
- On startup it writes `${PROMETHEUS_FILE_SD_DIR}/node_exporter_targets.json` based on enabled SSH machines in the settings store.
|
||||
- It provides proxy endpoints (`/api/monitoring/alerts`, `/api/monitoring/alertmanager-status`, `/api/monitoring/prometheus-targets`) consumed by the frontend.
|
||||
@@ -105,6 +124,7 @@ The backend bridges the stack with the application:
|
||||
Open `monitoring/prometheus/prometheus.yml` first to understand what is scraped and how the backend is wired, then read `backend/src/media_library_viewer_api/observability.py` to see the metric names and labels. For environment requirements, read `.env.example`.
|
||||
|
||||
## Supervisor coordination
|
||||
|
||||
Not needed — this is a read-only scouting summary.
|
||||
|
||||
---
|
||||
@@ -113,7 +133,7 @@ Not needed — this is a read-only scouting summary.
|
||||
|
||||
## 1. Observability services defined in Compose
|
||||
|
||||
Both `docker-compose.yml` and `docker-compose.dev.yml` define the following services:
|
||||
Both `docker-compose.yml` and `docker-compose.dev.yml` define **only the backend and frontend**. The observability services (Prometheus, Loki, Grafana, Alertmanager, Alloy, Node Exporter) were extracted to the standalone `docker-compose.observability.yml` example stack and are **no longer** deployed by Manage. Summary of what remains in the app compose files:
|
||||
|
||||
| Service | Image | Internal endpoint | Purpose |
|
||||
|---------|-------|-------------------|---------|
|
||||
@@ -126,6 +146,7 @@ Both `docker-compose.yml` and `docker-compose.dev.yml` define the following serv
|
||||
| `backend` | Build from `backend/Dockerfile` | `http://backend:8000` | FastAPI app exposing `/metrics` |
|
||||
|
||||
Differences:
|
||||
|
||||
- Production (`docker-compose.yml`): services attach to an external `web` network for Traefik, use `expose` instead of host ports for most services, and require OIDC/auth variables.
|
||||
- Development (`docker-compose.dev.yml`): Prometheus/Grafana/Loki/Alertmanager/Node Exporter are published on host ports `9090`, `3000`, `3100`, `9093`, `9100`; auth is disabled (`AUTH_ENABLED=false`).
|
||||
|
||||
@@ -134,6 +155,7 @@ Differences:
|
||||
From `.env.example` and the Compose files, the variables relevant to the observability stack are:
|
||||
|
||||
### Backend / metrics
|
||||
|
||||
- `PROMETHEUS_ENABLED` – enable metrics endpoint (set to `"true"` in both compose files).
|
||||
- `PROMETHEUS_FILE_SD_DIR` – directory where the backend writes `node_exporter_targets.json` (default `/app/backend/.cache/prometheus-file-sd`).
|
||||
- `ALERTMANAGER_URL` – backend proxy target (default `http://alertmanager:9093`).
|
||||
@@ -141,6 +163,7 @@ From `.env.example` and the Compose files, the variables relevant to the observa
|
||||
- `BACKEND_CACHE_DIR` – host directory mounted into backend and Prometheus for file-SD.
|
||||
|
||||
### Grafana
|
||||
|
||||
- `GRAFANA_APP_HOST` – public hostname for Grafana (production; required).
|
||||
- `GRAFANA_APP_PORT` – defaults to `3000`.
|
||||
- `GRAFANA_APP_NAME` – defaults to `grafana`.
|
||||
@@ -152,16 +175,19 @@ From `.env.example` and the Compose files, the variables relevant to the observa
|
||||
- `GF_AUTH_GENERIC_OAUTH_API_URL`
|
||||
|
||||
### Alertmanager
|
||||
|
||||
- `SMTP_HOST` / `SMTP_PORT`
|
||||
- `SMTP_USERNAME` / `SMTP_PASSWORD`
|
||||
- `SMTP_FROM_ADDRESS`
|
||||
- `ALERT_EMAIL_TO`
|
||||
|
||||
### Traefik / network (production)
|
||||
|
||||
- `BACKEND_APP_HOST` / `FRONTEND_APP_HOST` / `GRAFANA_APP_HOST`
|
||||
- `CERT_RESOLVER` – e.g. `letsencrypt`
|
||||
|
||||
### General
|
||||
|
||||
- `LOG_LEVEL` / `LOG_FORMAT` – also passed to Grafana and backend.
|
||||
|
||||
## 3. Monitoring config files
|
||||
@@ -193,7 +219,7 @@ Remote Node Exporter targets are not static: the backend reads machine settings
|
||||
|
||||
## 5. Setup steps and gotchas
|
||||
|
||||
- The observability stack is brought up with the app itself:
|
||||
- Manage's own compose stack does **not** include observability services. To run a full local stack, bring up the app and the standalone observability example separately:
|
||||
- Production: `docker compose -f docker-compose.yml up --build`
|
||||
- Development: `docker compose -f docker-compose.dev.yml up --build`
|
||||
- Production requires the external `web` network and Traefik already configured; `docker-compose.dev.yml` does not use Traefik and binds ports directly.
|
||||
|
||||
Reference in New Issue
Block a user