Skip to content

Commit

Permalink
feat: start scraping stats from the query log
Browse files Browse the repository at this point in the history
  • Loading branch information
henrywhitaker3 committed Mar 28, 2024
1 parent 98b84bd commit 5e16fce
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 0 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/joho/godotenv v1.5.1
github.com/labstack/echo-contrib v0.16.0
github.com/labstack/echo/v4 v4.11.4
github.com/mitchellh/mapstructure v1.5.0
github.com/prometheus/client_golang v1.19.0
github.com/sethvargo/go-envconfig v1.0.1
)
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
Expand Down
27 changes: 27 additions & 0 deletions internal/adguard/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import (
"net/http"
"net/url"
"slices"
"strconv"

"github.com/henrywhitaker3/adguard-exporter/internal/config"
"github.com/mitchellh/mapstructure"
)

type Client struct {
Expand Down Expand Up @@ -91,6 +93,31 @@ func (c *Client) GetDhcp(ctx context.Context) (*DhcpStatus, error) {
return out, nil
}

func (c *Client) GetQueryTypes(ctx context.Context) (map[string]int, error) {
log := &queryLog{}
err := c.do(ctx, http.MethodGet, "/control/querylog?limit=1000&response_status=all", log)
if err != nil {
return nil, err
}

out := map[string]int{}
for _, d := range log.Log {
if d.Answer != nil && len(d.Answer) > 0 {
for i := range d.Answer {
switch v := d.Answer[i].Value.(type) {
case string:
out[d.Answer[i].Type]++
case map[string]any:
dns65 := &type65{}
mapstructure.Decode(v, dns65)
out["TYPE"+strconv.Itoa(dns65.Hdr.Rrtype)]++
}
}
}
}
return out, nil
}

func (c *Client) Url() string {
return c.conf.Url
}
43 changes: 43 additions & 0 deletions internal/adguard/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,46 @@ type DhcpStatus struct {
StaticLeases []DhcpLease `json:"static_leases"`
Leases []DhcpLease
}

type query struct {
Class string `json:"class"`
Host string `json:"host"`
Type string `json:"type"`
}

type answer struct {
Type string `json:"type"`
TTL float64 `json:"ttl"`
Value any `json:"value"`
}

type dnsHeader struct {
Name string `json:"Name"`
Rrtype int `json:"Rrtype"`
Class int `json:"Class"`
TTL int `json:"Ttl"`
Rdlength int `json:"Rdlength"`
}

type type65 struct {
Hdr dnsHeader `json:"Hdr"`
RData string `json:"Rdata"`
}

type logEntry struct {
Answer []answer `json:"answer"`
DNSSec Bool `json:"answer_dnssec"`
Client string `json:"client"`
ClientProto string `json:"client_proto"`
Elapsed string `json:"elapsed_ms"`
Question query `json:"question"`
Reason string `json:"reason"`
Status string `json:"status"`
Time string `json:"time"`
Upstream string `json:"upstream"`
}

type queryLog struct {
Log []logEntry `json:"data"`
Oldest string `json:"oldest"`
}
6 changes: 6 additions & 0 deletions internal/metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ var (
Namespace: "adguard",
Help: "The average response time for each of the top upstream servers",
}, []string{"server", "upstream"})
QueryTypes = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: "query_types",
Namespace: "adguard",
Help: "The number of queries for a specific type",
}, []string{"server", "type"})

// DHCP
DhcpEnabled = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Expand Down Expand Up @@ -151,6 +156,7 @@ func Init() {
prometheus.MustRegister(TopQueriedDomains)
prometheus.MustRegister(TopUpstreams)
prometheus.MustRegister(TopUpstreamsAvgTimes)
prometheus.MustRegister(QueryTypes)

// Status
prometheus.MustRegister(Running)
Expand Down
14 changes: 14 additions & 0 deletions internal/worker/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func collect(ctx context.Context, client *adguard.Client) error {
go collectStats(ctx, client)
go collectStatus(ctx, client)
go collectDhcp(ctx, client)
go collectQueryTypeStats(ctx, client)

return nil
}
Expand Down Expand Up @@ -104,3 +105,16 @@ func collectDhcp(ctx context.Context, client *adguard.Client) {
metrics.DhcpEnabled.WithLabelValues(client.Url()).Set(float64(dhcp.Enabled.Int()))
metrics.DhcpLeases.Record(client.Url(), dhcp.Leases)
}

func collectQueryTypeStats(ctx context.Context, client *adguard.Client) {
stats, err := client.GetQueryTypes(ctx)
if err != nil {
log.Printf("ERROR - could not get query type stats: %v\n", err)
metrics.ScrapeErrors.WithLabelValues(client.Url()).Inc()
return
}

for t, v := range stats {
metrics.QueryTypes.WithLabelValues(client.Url(), t).Set(float64(v))
}
}

0 comments on commit 5e16fce

Please sign in to comment.