Registry and Analytics: run, subnet, direction and protocol filters, successes-by-target chart
Registry (/registry):
- filters by run (slice by the address's cycle in that run), subnet
(drop-down of configured subnets), direction (egress/ingress) and
protocol (icmp, tcp, ssh, https, tls); status in scope is computed over
the narrowed checks
- chart "successful checks per target (egress) / site (ingress)" when both
direction and protocol are chosen; a row opens the list of addresses
(dialog, CSV)
- API: direction/protocol parameters and run in GET /admin/registry,
GET /admin/registry/breakdown and /breakdown/list
- subnet filter passes ids as one JSON parameter (SQLite variable limit)
Analytics (/analytics):
- subnet filter recomputes the whole page over the addresses of the run
inside the subnet; only their checks are read; cache per run and subnet
- direction and protocol focus the page; with both set the registry chart
is shown
- subnet parameter in GET /admin/analytics/runs/{id} and lists (JSON, CSV)
Docs: plans and summaries in docs/changes, README, API, USAGE.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
068c10ea1c
commit
ded196ec8d
40 files changed
+2545
-188
No files matched your search
@@ -3,6 +3,7 @@ package db
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"sort"
|
||||
@@ -273,13 +274,25 @@ type RunCheck struct {
|
||||
|
||||
// EachRunCheck calls fn for every check of the cycles that make up the run's
|
||||
// results (the latest cycle of each address in the run), in one pass over the
|
||||
// run_id index. fn must not call back into the DB (one connection).
|
||||
func (d *DB) EachRunCheck(ctx context.Context, runID int64, fn func(RunCheck)) error {
|
||||
rows, err := d.QueryContext(ctx, `
|
||||
// run_id index. With registryIDs (not nil) only the checks of those addresses
|
||||
// are read. fn must not call back into the DB (one connection).
|
||||
func (d *DB) EachRunCheck(ctx context.Context, runID int64, registryIDs []int64, fn func(RunCheck)) error {
|
||||
q := `
|
||||
SELECT c.registry_id, c.source, c.check_type, c.target, c.success, c.validator_id, c.detail,
|
||||
COALESCE(c.recorded_at, c.created_at), c.after_verdict
|
||||
FROM checks c JOIN run_results r ON r.run_id=c.run_id AND r.registry_id=c.registry_id AND r.cycle_id=c.cycle_id
|
||||
WHERE c.run_id=?`, runID)
|
||||
WHERE c.run_id=?`
|
||||
args := []any{runID}
|
||||
if registryIDs != nil {
|
||||
ids, err := json.Marshal(registryIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// One JSON parameter, not an id per "?" (SQLite's bound-variable limit).
|
||||
q += ` AND c.registry_id IN (SELECT value FROM json_each(?))`
|
||||
args = append(args, string(ids))
|
||||
}
|
||||
rows, err := d.QueryContext(ctx, q, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user