commit 58479bf180e8681f42a6e424c7fcd3ce8f41b640 from: Oliver Lowe date: Fri Dec 16 01:53:15 2022 UTC initial commit commit - /dev/null commit + 58479bf180e8681f42a6e424c7fcd3ce8f41b640 blob - /dev/null blob + e115458fc34367612136caf396dcea0b5e8a169a (mode 644) --- /dev/null +++ LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2022 Oliver Lowe + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. blob - /dev/null blob + c1bcbcf12b182b539cab145b196d66da704486ce (mode 644) --- /dev/null +++ cmd/nsd_exporter/nsd_exporter.go @@ -0,0 +1,39 @@ +package main + +import ( + "fmt" + "io" + "log" + "net/http" + "strings" + + "olowe.co/nlnet" +) + +const metricUp = "unbound_up 1" +const metricDown = "unbound_up 0" + +func printMetrics(w io.Writer, stats map[string]float64) { + for name, value := range stats { + name = strings.ReplaceAll(name, ".", "_") + if strings.HasSuffix(name, "avg") || strings.HasSuffix(name, "median") { + fmt.Fprintf(w, "# TYPE %s gauge\n", name) + } + fmt.Fprintf(w, "unbound_%s %f\n", name, value) + } +} + +func handleMetrics(w http.ResponseWriter, req *http.Request) { + stats, err := nlnet.ReadUnboundStats() + if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + printMetrics(w, stats) +} + +func main() { + http.HandleFunc("/metrics", handleMetrics) + log.Fatal(http.ListenAndServe(":9948", nil)) +} blob - /dev/null blob + d525d9f33c1693c0fa969552d519f98b047acb1e (mode 644) --- /dev/null +++ cmd/unbound_exporter/unbound_exporter.go @@ -0,0 +1,40 @@ +package main + +import ( + "fmt" + "io" + "log" + "net/http" + "strings" + + "olowe.co/nlnet" +) + +const metricUp = "unbound_up 1" +const metricDown = "unbound_up 0" + +func printMetrics(w io.Writer, stats map[string]float64) { + for name, value := range stats { + name = strings.ReplaceAll(name, ".", "_") + if strings.HasSuffix(name, "avg") || strings.HasSuffix(name, "median") { + fmt.Fprintf(w, "# TYPE %s gauge\n", name) + } + fmt.Fprintf(w, "unbound_%s %f\n", name, value) + } +} + +func handleMetrics(w http.ResponseWriter, req *http.Request) { + log.Println("ok here we go...") + stats, err := nlnet.ReadUnboundStats() + if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + printMetrics(w, stats) +} + +func main() { + http.HandleFunc("/metrics", handleMetrics) + log.Fatal(http.ListenAndServe(":9948", nil)) +} blob - /dev/null blob + 2248e8586594d0eb627e434795a9ad781f114898 (mode 644) --- /dev/null +++ go.mod @@ -0,0 +1,3 @@ +module olowe.co/nlnet + +go 1.18 blob - /dev/null blob + f247c296c0cb3f1b4b8b4675c0f4afcafe060ed9 (mode 644) --- /dev/null +++ stats.go @@ -0,0 +1,59 @@ +package nlnet + +import ( + "bufio" + "bytes" + "fmt" + "io" + "os/exec" + "strconv" + "strings" +) + +type stat struct { + name string + value float64 +} + +func parseStats(r io.Reader) (map[string]float64, error) { + stats := make(map[string]float64) + sc := bufio.NewScanner(r) + for sc.Scan() { + stat, err := parseStat(sc.Text()) + if err != nil { + return stats, fmt.Errorf("parse stat: %v", err) + } + stats[stat.name] = stat.value + } + return stats, sc.Err() +} + +func parseStat(line string) (stat, error) { + k, v, found := strings.Cut(line, "=") + if !found { + return stat{}, fmt.Errorf("%q not found", "=") + } + f, err := strconv.ParseFloat(v, 64) + if err != nil { + return stat{}, fmt.Errorf("parse %s value: %v", k, err) + } + return stat{name: k, value: f}, nil +} + +func execForStats(path string) (map[string]float64, error) { + cmd := exec.Command(path, "stats_noreset") + buf := &bytes.Buffer{} + cmd.Stdout = buf + if err := cmd.Run(); err != nil { + return nil, err + } + return parseStats(buf) +} + +func ReadUnboundStats() (map[string]float64, error) { + return execForStats("unbound-control") +} + +func ReadNSDStats() (map[string]float64, error) { + return execForStats("nsd-control") +} blob - /dev/null blob + d787101794c36711c91e67efd8347c0e4524db4a (mode 644) --- /dev/null +++ stats_test.go @@ -0,0 +1,19 @@ +package nlnet + +import ( + "os" + "testing" +) + +func TestParseStats(t *testing.T) { + f, err := os.Open("unbound.stats") + if err != nil { + t.Fatal(err) + } + defer f.Close() + m, err := parseStats(f) + if err != nil { + t.Fatal(err) + } + t.Log(m) +} \ No newline at end of file blob - /dev/null blob + 649c682e899059aa55dca89ae208612f01a7d5e7 (mode 644) --- /dev/null +++ unbound.stats @@ -0,0 +1,35 @@ +thread0.num.queries=286342 +thread0.num.queries_ip_ratelimited=0 +thread0.num.cachehits=105482 +thread0.num.cachemiss=180860 +thread0.num.prefetch=0 +thread0.num.expired=0 +thread0.num.recursivereplies=180860 +thread0.requestlist.avg=4.13004 +thread0.requestlist.max=287 +thread0.requestlist.overwritten=0 +thread0.requestlist.exceeded=0 +thread0.requestlist.current.all=0 +thread0.requestlist.current.user=0 +thread0.recursion.time.avg=0.170479 +thread0.recursion.time.median=0.0269844 +thread0.tcpusage=0 +total.num.queries=286342 +total.num.queries_ip_ratelimited=0 +total.num.cachehits=105482 +total.num.cachemiss=180860 +total.num.prefetch=0 +total.num.expired=0 +total.num.recursivereplies=180860 +total.requestlist.avg=4.13004 +total.requestlist.max=287 +total.requestlist.overwritten=0 +total.requestlist.exceeded=0 +total.requestlist.current.all=0 +total.requestlist.current.user=0 +total.recursion.time.avg=0.170479 +total.recursion.time.median=0.0269844 +total.tcpusage=0 +time.now=1671083975.298578 +time.up=1107885.990204 +time.elapsed=1107885.990204