Statistics per view: toggle views on the Statistics page
Answers, result codes, record types, zones, blocking, rate limiting and the top lists are also counted per view, from named's response log. The Statistics page has a toggle per view with All and None, remembered per browser; jarl stats --view and ?views= on the API. named's own counters stay for the whole server, and the page says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ead749dd3d
commit
12820b17bb
13 files changed
+526
-61
No files matched your search
+32
-8
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net/url"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -21,8 +22,22 @@ func statsCmd() *cobra.Command {
|
||||
Long: `Query statistics collected from named (see docs/stats.md). They must be
|
||||
enabled in /etc/jarl/jarl.yaml (stats.enabled: true).
|
||||
|
||||
Ranges are given with --since: 90m, 24h, 7d, 2w. Use -o json or -o yaml to
|
||||
export the data.`,
|
||||
Ranges are given with --since: 90m, 24h, 7d, 2w. --view limits the figures
|
||||
to some views (repeat it, or separate with commas): answers from named's
|
||||
response log, per view; named's own counters stay for the whole server.
|
||||
Use -o json or -o yaml to export the data.`,
|
||||
}
|
||||
var statsViews []string
|
||||
cmd.PersistentFlags().StringSliceVar(&statsViews, "view", nil, "only these views (repeat, or comma separated)")
|
||||
// withViews adds the --view filter to a query.
|
||||
withViews := func(v url.Values) url.Values {
|
||||
if len(statsViews) > 0 {
|
||||
if v == nil {
|
||||
v = url.Values{}
|
||||
}
|
||||
v.Set("views", strings.Join(statsViews, ","))
|
||||
}
|
||||
return v
|
||||
}
|
||||
// Each command has its own --since variable: their defaults differ, and
|
||||
// a shared variable would take the last default for all of them.
|
||||
@@ -77,12 +92,21 @@ export the data.`,
|
||||
return err
|
||||
}
|
||||
var s stats.Summary
|
||||
if err := c.Get(ctx(), "/stats/summary", q("since", summarySince, "top", strconv.Itoa(topN)), &s); err != nil {
|
||||
if err := c.Get(ctx(), "/stats/summary", withViews(q("since", summarySince, "top", strconv.Itoa(topN))), &s); err != nil {
|
||||
return err
|
||||
}
|
||||
return output(s, func(w io.Writer) {
|
||||
fmt.Fprintf(w, "Range:\t%s to %s\n", s.From.Local().Format("2006-01-02 15:04"), s.To.Local().Format("2006-01-02 15:04"))
|
||||
fmt.Fprintf(w, "Queries:\t%d (%.2f per second on average)\n", s.Queries, s.AvgQPS)
|
||||
if len(s.FilterViews) > 0 {
|
||||
since := ""
|
||||
if s.ViewsSince != nil {
|
||||
since = ", per view since " + s.ViewsSince.Local().Format("2006-01-02 15:04")
|
||||
}
|
||||
fmt.Fprintf(w, "Views:\t%s (from the response log%s; named's own counters are left out)\n", strings.Join(s.FilterViews, ", "), since)
|
||||
fmt.Fprintf(w, "Answers:\t%d (%.2f per second on average)\n", s.Queries, s.AvgQPS)
|
||||
} else {
|
||||
fmt.Fprintf(w, "Queries:\t%d (%.2f per second on average)\n", s.Queries, s.AvgQPS)
|
||||
}
|
||||
if s.Peak != nil {
|
||||
fmt.Fprintf(w, "Busiest %s:\t%s with %d queries\n", s.Peak.Per, s.Peak.Time.Local().Format("2006-01-02 15:04"), s.Peak.Queries)
|
||||
}
|
||||
@@ -157,7 +181,7 @@ export the data.`,
|
||||
return err
|
||||
}
|
||||
var es []stats.Entry
|
||||
if err := c.Get(ctx(), "/stats/top", q("kind", kind, "since", topSince, "limit", strconv.Itoa(limit)), &es); err != nil {
|
||||
if err := c.Get(ctx(), "/stats/top", withViews(q("kind", kind, "since", topSince, "limit", strconv.Itoa(limit))), &es); err != nil {
|
||||
return err
|
||||
}
|
||||
return output(es, func(w io.Writer) {
|
||||
@@ -207,7 +231,7 @@ export the data.`,
|
||||
qv.Add("key", k)
|
||||
}
|
||||
var tl stats.Timeline
|
||||
if err := c.Get(ctx(), "/stats/timeline", qv, &tl); err != nil {
|
||||
if err := c.Get(ctx(), "/stats/timeline", withViews(qv), &tl); err != nil {
|
||||
return err
|
||||
}
|
||||
return output(tl, func(w io.Writer) {
|
||||
@@ -256,7 +280,7 @@ export the data.`,
|
||||
return err
|
||||
}
|
||||
var hm stats.Heatmap
|
||||
if err := c.Get(ctx(), "/stats/heatmap", q("since", heatmapSince, "key", hmKey), &hm); err != nil {
|
||||
if err := c.Get(ctx(), "/stats/heatmap", withViews(q("since", heatmapSince, "key", hmKey)), &hm); err != nil {
|
||||
return err
|
||||
}
|
||||
return output(hm, func(w io.Writer) {
|
||||
@@ -308,7 +332,7 @@ export the data.`,
|
||||
return err
|
||||
}
|
||||
var es []stats.Entry
|
||||
if err := c.Get(ctx(), "/stats/breakdown", q("group", args[0], "since", breakdownSince), &es); err != nil {
|
||||
if err := c.Get(ctx(), "/stats/breakdown", withViews(q("group", args[0], "since", breakdownSince)), &es); err != nil {
|
||||
return err
|
||||
}
|
||||
return output(es, func(w io.Writer) {
|
||||
|
||||
Reference in new issue
Block a user