diff --git a/README.md b/README.md index ffbb132..daea081 100644 --- a/README.md +++ b/README.md @@ -230,9 +230,11 @@ dnswatcher includes an unauthenticated, read-only web dashboard at the root URL - **Summary counts** for monitored domains, hostnames, ports, and certificates. - **Domains** with their discovered nameservers. -- **Hostnames** with per-nameserver DNS records and status. +- **Hostnames** with per-nameserver DNS records and status. For a nameserver + whose query failed, the reason is shown in place of the records. - **Ports** with open/closed state and associated hostnames. -- **TLS certificates** with CN, issuer, expiry, and status. +- **TLS certificates** with CN, issuer, expiry, and status. For a failed check, + the reason is shown in place of CN, issuer and expiry. - **Recent alerts** (last 100 notifications sent since the process started), displayed in reverse chronological order. @@ -259,6 +261,10 @@ dnswatcher exposes a lightweight HTTP API for operational visibility: | `GET /api/v1/status` | Current monitoring state | | `GET /metrics` | Prometheus metrics, see below | +In `/api/v1/status`, each nameserver entry and certificate entry whose `status` +is `error` also has `error`, the reason, as in the state file (see State File +Format). + `/metrics` is served only when `DNSWATCHER_METRICS_USERNAME` is set, behind Basic Auth. It has the Prometheus Go client's default metrics only (Go runtime, process, and counts of `/metrics` requests); dnswatcher records no metrics of diff --git a/TODO.md b/TODO.md index 4ce00d0..f71bbcf 100644 --- a/TODO.md +++ b/TODO.md @@ -19,6 +19,8 @@ trial run of the finished image: https://git.eeqj.de/sneak/dnswatcher/issues/149 # Completed Steps +- 2026-10-02: the dashboard and `/api/v1/status` show why a nameserver query or + a certificate check failed, which only the state file showed (closes #225). - 2026-10-02: a name's CNAME is stored once per nameserver, not once per record type asked for; a state file with repeats loads each value once (closes #220). - 2026-10-02: a DNS lookup that shutdown cuts short logs no error; one that diff --git a/internal/handlers/dashboard_test.go b/internal/handlers/dashboard_test.go index 554cf9d..d60a36e 100644 --- a/internal/handlers/dashboard_test.go +++ b/internal/handlers/dashboard_test.go @@ -1,6 +1,7 @@ package handlers_test import ( + "strings" "testing" "time" @@ -78,3 +79,39 @@ func TestFormatRecords(t *testing.T) { t.Errorf("unexpected format: %q", got) } } + +// dashboardRow returns the table row of page that contains name. +func dashboardRow(t *testing.T, page string, name string) string { + t.Helper() + + for row := range strings.SplitSeq(page, " + {{ if $nsr.Error }} + {{ $nsr.Error }} + {{ else }} {{ formatRecords $nsr.Records }} + {{ end }} {{ relTime $nsr.LastChecked }} @@ -258,6 +262,11 @@ > {{ end }} + {{ if $cs.Error }} + +
{{ $cs.Error }}
+ + {{ else }} {{ $cs.CommonName }} @@ -285,6 +294,7 @@ {{ end }} {{ end }} + {{ end }} {{ relTime $cs.LastChecked }}