You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: AGENTS.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,8 +4,8 @@ Context and instructions for AI coding agents working on **pgwd** (Postgres Watc
4
4
5
5
## Project overview
6
6
7
-
-**What it is:** Go CLI that monitors PostgreSQL connection counts (total, active, idle, stale), optional **long-running query** alerts (`db.long_query_*`, cooldown via metrics store), and notifies via Slackand/or Loki when configured thresholds are exceeded.
-**What it is:** Go CLI that monitors PostgreSQL connection counts (total, active, idle, stale), optional **long-running query** alerts (`db.long_query_*`, cooldown via metrics store), and notifies via Slack, Loki, PagerDuty, Teams, and/or generic webhook when configured thresholds are exceeded.
-**Config:** Config file (YAML) at `/etc/pgwd/pgwd.conf` or `-config` / `PGWD_CONFIG`. Use `databases:` for one or more Postgres (canonical). Legacy `db:` deprecated (emits warning, removed in v1.0). **`kube.postgres` / `-kube-postgres` is not supported with `databases:`** (multi-DB requires direct URLs; single-DB + kube until per-db kube exists). **SQLite / hysteresis** rows are keyed by **`(client, cluster, database)`** — not by URL host; use a **unique `client` per `databases:` entry** when the same DB name is used on different hosts. When file loads, env vars ignored; otherwise `ApplyDefaults` + `ApplyEnv`. CLI flags override. See `internal/config`, `contrib/pgwd.conf.example`, README “Multi-database limitations”.
10
10
-**Kubernetes:** Optional `-kube-postgres namespace/svc/name` (or `pod/name`) runs client-go port-forward and connects to localhost. **Deprecated:** URL password `DISCOVER_MY_PASSWORD` reads pod env via `pods/exec` (removed in 0.9.x) — decision record [docs/kubernetes-passwords.md](docs/kubernetes-passwords.md). Optional `-kube-loki namespace/svc/loki` port-forwards to Loki when Loki is inside the cluster and pgwd runs outside. Requires loadable kubeconfig (client-go; no kubectl binary). See `internal/kube`. **Helm / in-cluster deployment manifests** are in **[pgwd-selfhosted](https://github.com/hrodrig/pgwd-selfhosted)**; see `contrib/HELM.md` and `contrib/k8s/README.md`.
11
11
-**Metrics persistence:** Daemon writes check history to **`sqlite.path`** (SQLite) or **`metrics_store.driver`** + **`metrics_store.dsn`** (PostgreSQL / MySQL via **`internal/store/sqlstore`**) for hysteresis, resolution alerts, and `/metrics`. **`internal/metricsstore`** selects the backend for export; **`store.MetricsStorer`** is the interface used by **`cmd/pgwd`** and **`internal/httpsrv`**. **CSV export:**`-export-metrics-format csv` + `-export-metrics-destination` → **`internal/metricsexport`** + **`metricsstore.ExportRows`** — see README.
@@ -54,7 +54,7 @@ Context and instructions for AI coding agents working on **pgwd** (Postgres Watc
54
54
-`internal/validator/` — config validation returning errors (extracted from main for testability).
55
55
-`internal/config/` — config from file (YAML), env (`PGWD_*`), and CLI. `file.go`: FromFile, ApplyDefaults.
56
56
-`internal/postgres/` — pool, stats, stale count, max_connections.
57
-
-`internal/notify/` — Slack and Loki senders, event type.
-**Generic webhook** with custom headers (JWT bearer), optional HMAC-SHA256 signing, and Go `body_template` for custom JSON payloads.
16
+
-**Shared HTTP retry/backoff** for all notifiers (`notifications.retry`, `-notifications-retry-*`). Slack and Loki migrated to shared retry. Defaults: 3 attempts, 1s initial backoff, 10s max backoff; retry on 5xx and network errors only.
10
17
11
18
### Documentation
12
19
13
20
-**[ROADMAP.md](ROADMAP.md)** — canonical release index (0.7 → 1.0, calendar, document map, key decisions).
14
-
-**[SPECIFICATIONS.md](SPECIFICATIONS.md)** — config load order fixed (env ignored when file loads); client-go kube (not kubectl); HTTP `/metrics` = Prometheus text exposition; dry-run bypass for connect failure documented; **`DISCOVER_MY_PASSWORD` deprecated** (removed 0.9.x).
15
-
-**[docs/kubernetes-passwords.md](docs/kubernetes-passwords.md)** — decision record for deprecating `DISCOVER_MY_PASSWORD` (RBAC, exec vs Secret, alternatives, migration).
| `-notifications-retry-max-backoff` | `PGWD_NOTIFICATIONS_RETRY_MAX_BACKOFF` | Max retry backoff, e.g. `10s` |
553
570
| `-interval` | `PGWD_INTERVAL` | Run every N seconds; 0 = run once |
554
571
| `-dry-run` | `PGWD_DRY_RUN` | Only print stats, do not send notifications |
555
572
| `-force-notification` | `PGWD_FORCE_NOTIFICATION` | Always send at least one notification: test event when connected (to validate delivery, format, and channel). Requires at least one notifier. (Connection failure is always notified when a notifier is configured, with or without this flag.) |
@@ -738,14 +755,14 @@ Using **127.0.0.1** and host port **5433** avoids hitting a local Postgres on 54
738
755
## Requirements
739
756
740
757
- At least one of: a threshold (`-db-threshold-levels` for 3-tier, `-db-threshold-idle`, or `-db-threshold-stale` with `-db-stale-age`), `-dry-run`, or `-force-notification`. If you set only `-db-url` and a notifier, pgwd uses 3-tier levels (75,85,95%) of `max_connections`.
741
-
- If not using `-dry-run`: at least one notifier (`-notifications-slack-webhook`, `-notifications-loki-url`, or `-kube-loki`). For `-force-notification`, a notifier is required.
758
+
- If not using `-dry-run`: at least one notifier (Slack, Loki, `-kube-loki`, PagerDuty, Teams, or generic webhook). For `-force-notification`, a notifier is required.
742
759
- For `threshold-stale`, `stale-age` must be set and greater than 0.
743
760
744
761
## Behavior and exit
745
762
746
763
- **One-shot** (`interval` 0 or unset): runs one check, sends alerts if thresholds are exceeded, then exits. Exit code 0 on success; non-zero on fatal errors (e.g. DB connection failure).
747
764
- **Daemon** (`interval` greater than 0): runs every `interval` seconds until interrupted (Ctrl+C or SIGTERM). Exits with 0 after a clean shutdown.
748
-
- **Dry run**: same as above but no HTTP calls to Slack/Loki; only logs stats to stdout.
765
+
- **Dry run**: same as above but no HTTP calls to notifiers; only logs stats to stdout.
Same placeholders as Slack. Timestamp is the time of the push. You can query in Grafana or LogCLI by label (e.g. `{app="pgwd", threshold="total"}` or `{app="pgwd", level="danger"}`). For Grafana alert rules, see [docs/loki-grafana-alerts.md](docs/loki-grafana-alerts.md) (labels, LogQL examples, payload structure).
798
815
816
+
## PagerDuty
817
+
818
+
Set `notifications.pagerduty.routing_key` (or `-notifications-pagerduty-routing-key` / `PGWD_NOTIFICATIONS_PAGERDUTY_ROUTING_KEY`) and enable PagerDuty (`enabled: true` or set routing key via env/CLI). Events POST to PagerDuty Events API v2 with severity derived from pgwd levels (`danger` / connect failures → `critical`, `alert` → `warning`, `attention` / resolution / test → `info`). Optional `severity` and `source` (default `pgwd`).
819
+
820
+
## Microsoft Teams
821
+
822
+
Create an [Incoming Webhook](https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook) in your Teams channel. Set `notifications.teams.webhook_url` or `-notifications-teams-webhook`. Payload is plain text (`{"text": "..."}`) with the same summary fields as Slack (connections, cluster, database, client).
823
+
824
+
## Generic webhook
825
+
826
+
For custom APIs (including JWT bearer auth), set `notifications.generic.webhook_url`. Default JSON: `{"text": "<summary>", ...extra_fields}`. Set `headers` for auth (e.g. `Authorization: Bearer <token>`). Optional `body_template` (Go template, must render valid JSON). Optional `hmac_secret` signs the body as `sha256=<hex>` in `hmac_header` (default `X-Pgwd-Signature`).
827
+
828
+
All notifiers share HTTP retry settings under `notifications.retry` (or `-notifications-retry-*`).
829
+
799
830
---
800
831
801
832
## Troubleshooting
@@ -804,9 +835,9 @@ Same placeholders as Slack. Timestamp is the time of the push. You can query in
804
835
|--------|----------------|
805
836
| **"missing database URL"** | Set `PGWD_DB_URL` or `-db-url`. The URL must be a valid [PostgreSQL connection string](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING). |
806
837
| **"no thresholds set and could not default from server..."** | pgwd could not read `max_connections` from the server (error or 0). Use `-test-max-connections N` to override, or `-dry-run`, or `-force-notification`. With a normal Postgres, only `-db-url` and a notifier should be enough (defaults to 3-tier levels 75,85,95%). |
807
-
| **"no notifier configured"** | Set `PGWD_NOTIFICATIONS_SLACK_WEBHOOK`, `PGWD_NOTIFICATIONS_LOKI_URL`, or `PGWD_KUBE_LOKI` (or use `-dry-run` to skip notifications). |
808
-
| **"force-notification requires at least one notifier"** | Use `-force-notification` together with `-notifications-slack-webhook` and/or `-notifications-loki-url` or `-kube-loki`. |
809
-
| **"notify-on-connect-failure requires at least one notifier"** | You set `-notify-on-connect-failure` but have no notifier. Add `-notifications-slack-webhook` and/or `-notifications-loki-url` or `-kube-loki`. (Connect failure is always notified when a notifier is configured; the flag is optional.) |
838
+
| **"no notifier configured"** | Set a notification channel: Slack, Loki, `-kube-loki`, PagerDuty, Teams, or generic webhook (or use `-dry-run`). |
839
+
| **"force-notification requires at least one notifier"** | Use `-force-notification` together with at least one configured notifier. |
840
+
| **"notify-on-connect-failure requires at least one notifier"** | You set `-notify-on-connect-failure` but have no notifier. Add a notification channel. (Connect failure is always notified when a notifier is configured; the flag is optional.) |
810
841
| **"load kubeconfig" / cluster unreachable** | When using `-kube-postgres` or `-kube-loki`, ensure a valid kubeconfig exists (`KUBECONFIG` env or `~/.kube/config`). pgwd uses client-go; no kubectl binary required. |
811
842
| **"when using -db-threshold-stale, -db-stale-age must be > 0"** | Set `-db-stale-age N` (e.g. 600) when using `-db-threshold-stale`. |
812
843
| **Slack/Loki not receiving alerts** | Run once with `-force-notification` to send a test message. Check webhook URL, network/firewall, and that the app can reach Slack/Loki. |
0 commit comments