diff --git a/cmd/godplugin/main.go b/cmd/godplugin/main.go index bdb1c3458..506f1d2ac 100644 --- a/cmd/godplugin/main.go +++ b/cmd/godplugin/main.go @@ -42,6 +42,7 @@ import ( _ "github.com/netdata/go.d.plugin/modules/solr" _ "github.com/netdata/go.d.plugin/modules/springboot2" _ "github.com/netdata/go.d.plugin/modules/tengine" + _ "github.com/netdata/go.d.plugin/modules/unbound" _ "github.com/netdata/go.d.plugin/modules/vcsa" _ "github.com/netdata/go.d.plugin/modules/vsphere" _ "github.com/netdata/go.d.plugin/modules/weblog" diff --git a/config/go.d/unbound.conf b/config/go.d/unbound.conf new file mode 100644 index 000000000..ddf435d01 --- /dev/null +++ b/config/go.d/unbound.conf @@ -0,0 +1,136 @@ +# netdata go.d.plugin configuration for unbound +# +# This file is in YaML format. Generally the format is: +# +# name: value +# +# There are 2 sections: +# - GLOBAL +# - JOBS +# +# +# [ GLOBAL ] +# These variables set the defaults for all JOBs, however each JOB may define its own, overriding the defaults. +# +# The GLOBAL section format: +# param1: value1 +# param2: value2 +# +# Currently supported global parameters: +# - update_every +# Data collection frequency in seconds. Default: 1. +# +# - autodetection_retry +# Re-check interval in seconds. Attempts to start the job are made once every interval. +# Zero means not to schedule re-check. Default: 0. +# +# - priority +# Priority is the relative priority of the charts as rendered on the web page, +# lower numbers make the charts appear before the ones with higher numbers. Default: 70000. +# +# +# [ JOBS ] +# JOBS allow you to collect values from multiple sources. +# Each source will have its own set of charts. +# +# IMPORTANT: +# - Parameter 'name' is mandatory. +# - Jobs with the same name are mutually exclusive. Only one of them will be allowed running at any time. +# +# This allows autodetection to try several alternatives and pick the one that works. +# Any number of jobs is supported. +# +# The JOBS section format: +# +# jobs: +# - name: job1 +# param1: value1 +# param2: value2 +# +# - name: job2 +# param1: value1 +# param2: value2 +# +# - name: job2 +# param1: value1 +# +# +# [ List of JOB specific parameters ]: +# - address +# Server address. +# Syntax: +# address: 127.0.0.1:8953 +# address: /var/run/unbound.sock +# +# - timeout +# Connection/read/write/ssl handshake timeout. +# Syntax: +# timeout: 1 +# +# - conf_path +# Absolute path to the unbound configuration file. Module uses the file to autodetect 'address', 'cumulative', +# 'use_tls', 'tls_cert' and 'tls_key' parameters. +# To disable parameters auto detection set it to empty string (""). +# Syntax: +# conf_path: /path/to/unbound.conf +# +# - cumulative +# Statistics collection mode. Should have the same value as the `statistics-cumulative` parameter in the unbound +# configuration file. +# Syntax: +# cumulative: yes/no +# +# - use_tls +# Whether to use or not TLS. +# Syntax: +# use_tls: yes/no +# +# - tls_skip_verify +# Whether to skip verifying server's certificate chain and hostname. +# Syntax: +# tls_skip_verify: yes/no +# +# - tls_cert +# Client tls certificate. +# Syntax: +# tls_cert: path/to/cert.pem +# +# - tls_key +# Client tls key. +# Syntax: +# tls_key: path/to/key.pem +# +# +# [ JOB defaults ]: +# address: 127.0.0.1:8953 +# timeout: 1 +# conf_path: /etc/unbound/unbound.conf +# cumulative: no +# use_tls: yes +# tls_skip_verify: yes +# tls_cert: /etc/unbound/unbound_control.pem +# tls_key: /etc/unbound/unbound_control.key +# +# +# [ JOB mandatory parameters ]: +# - name +# - address +# +# ------------------------------------------------MODULE-CONFIGURATION-------------------------------------------------- +# [ GLOBAL ] +# update_every: 1 +# autodetection_retry: 0 +# priority: 70000 +# +# +# [ JOBS ] +jobs: + - name: local + address: 127.0.0.1:8953 + timeout: 1 + conf_path: /etc/unbound/unbound.conf + cumulative: no + use_tls: yes + tls_skip_verify: yes + tls_cert: /etc/unbound/unbound_control.pem + tls_key: /etc/unbound/unbound_control.key diff --git a/modules/unbound/README.md b/modules/unbound/README.md new file mode 100644 index 000000000..38d8d5128 --- /dev/null +++ b/modules/unbound/README.md @@ -0,0 +1,131 @@ +# unbound + +This module monitors one or more [`Unbound`](https://nlnetlabs.nl/projects/unbound/about/) servers, depending on your configuration. + +## Requirements + +- `Unbound` with enabled `remote-control` interface (see [unbound.conf](https://nlnetlabs.nl/documentation/unbound/unbound.conf)) + +If using unix socket: + +- socket should be readable and writeable by `netdata` user + +If using ip socket and TLS is disabled: + +- socket should be accessible via network + +If TLS is enabled, in addition: + +- `control-key-file` should be readable by `netdata` user +- `control-cert-file` should be readable by `netdata` user + +For auto detection parameters from `unbound.conf`: + +- `unbound.conf` should be readable by `netdata` user + +## Charts + +Module produces following summary charts: + +- Received Queries in `queries` +- Rate Limited Queries in `queries` +- DNSCrypt Queries in `queries` +- Cache Statistics in `events` +- Cache Statistics Percentage in `events` +- Cache Prefetches in `prefetches` +- Replies Served From Expired Cache in `replies` +- Replies That Needed Recursive Processing in `replies` +- Time Spent On Recursive Processing in `milliseconds` +- Request List Usage in `queries` +- Current Request List Usage in `queries` +- Request List Jostle List Events in `queries` +- TCP Handler Buffers in `buffers` +- Uptime `seconds` + +If `extended-statistics` is enabled: + +- Queries By Type in `queries` +- Queries By Class in `queries` +- Queries By OpCode in `queries` +- Queries By Flag in `queries` +- Replies By RCode in `replies` +- Cache Items Count in `items` +- Cache Memory in `KB` +- Module Memory in `KB` +- TCP and TLS Stream Waif Buffer Memory in `KB` + +Per thread charts (only if number of threads > 1): + +- Received Queries in `queries` +- Rate Limited Queries in `queries` +- DNSCrypt Queries in `queries` +- Cache Statistics in `events` +- Cache Statistics Percentage in `events` +- Cache Prefetches in `prefetches` +- Replies Served From Expired Cache in `replies` +- Replies That Needed Recursive Processing in `replies` +- Time Spent On Recursive Processing in `milliseconds` +- Request List Usage in `queries` +- Current Request List Usage in `queries` +- Request List Jostle List Events in `queries` +- TCP Handler Buffers in `buffers` + + +## Configuration + +This Unbound collector only needs the `address` to aserver's `remote-control` interface if TLS is disabled or `address` is unix socket. +Otherwise you need to set path to the `control-key-file` and `control-cert-file` files. + +The module tries to auto-detect following parameters reading `unbound.conf`: +- address +- cumulative +- use_tls +- tls_cert +- tls_key + +Module supports both cumulative and non-cumulative modes. Default is non-cumulative. If your server has enabled +`statistics-cumulative`, but the module fails to auto-detect it (`unbound.conf` is not readable or it is a remote server), +you need to set it manually in the configuration file. + +Here is an example for several servers: + +```yaml +jobs: + - name: local + address: 127.0.0.1:8953 + use_tls: yes + tls_skip_verify: yes + tls_cert: /etc/unbound/unbound_control.pem + tls_key: /etc/unbound/unbound_control.key + + - name: remote + address: 203.0.113.10:8953 + use_tls: no + + - name: remote_cumulative + address: 203.0.113.11:8953 + use_tls: no + cumulative: yes + + - name: socket + address: /var/run/unbound.sock +``` + +For all available options, please see the module [configuration file](https://github.com/netdata/go.d.plugin/blob/master/config/go.d/unbound.conf). + + +## Troubleshooting + +Ensure that the control protocol is actually configured correctly. +Run following command as `root` user: +> unbound-control stats_noreset + +It should print out a bunch of info about the internal statistics of the server. +If this returns an error, you don't have the control protocol set up correctly. + +Check the module debug output. +Run following command as `netdata` user: + +> ./go.d.plugin -d -m unbound + +--- diff --git a/modules/unbound/charts.go b/modules/unbound/charts.go new file mode 100644 index 000000000..fed28d530 --- /dev/null +++ b/modules/unbound/charts.go @@ -0,0 +1,506 @@ +package unbound + +import ( + "fmt" + "strings" + + "github.com/netdata/go-orchestrator" + "github.com/netdata/go-orchestrator/module" +) + +type ( + // Charts is an alias for module.Charts + Charts = module.Charts + // Charts is an alias for module.Charts + Chart = module.Chart + // Dims is an alias for module.Dims + Dims = module.Dims + // Dim is an alias for module.Dim + Dim = module.Dim +) + +const ( + prioQueries = orchestrator.DefaultJobPriority + iota + prioIPRateLimitedQueries + prioQueryType + prioQueryClass + prioQueryOpCode + prioQueryFlag + prioDNSCryptQueries + + prioRecurReplies + prioReplyRCode + + prioRecurTime + + prioCache + prioCachePercentage + prioCachePrefetch + prioZeroTTL + prioCacheCount + + prioReqListUsage + prioReqListCurUsage + prioReqListJostle + + prioTCPUsage + + prioMemCache + prioMemMod + prioMemStreamWait + prioUptime + + prioThread +) + +func charts(cumulative bool) *Charts { + return &Charts{ + makeIncrIf(queriesChart.Copy(), cumulative), + makeIncrIf(ipRateLimitedQueriesChart.Copy(), cumulative), + makeIncrIf(cacheChart.Copy(), cumulative), + makePercOfIncrIf(cachePercentageChart.Copy(), cumulative), + makeIncrIf(prefetchChart.Copy(), cumulative), + makeIncrIf(zeroTTLChart.Copy(), cumulative), + makeIncrIf(dnsCryptChart.Copy(), cumulative), + makeIncrIf(recurRepliesChart.Copy(), cumulative), + recurTimeChart.Copy(), + reqListUsageChart.Copy(), + reqListCurUsageChart.Copy(), + makeIncrIf(reqListJostleChart.Copy(), cumulative), + tcpUsageChart.Copy(), + uptimeChart.Copy(), + } +} + +func extendedCharts(cumulative bool) *Charts { + return &Charts{ + memCacheChart.Copy(), + memModChart.Copy(), + memStreamWaitChart.Copy(), + cacheCountChart.Copy(), + makeIncrIf(queryTypeChart.Copy(), cumulative), + makeIncrIf(queryClassChart.Copy(), cumulative), + makeIncrIf(queryOpCodeChart.Copy(), cumulative), + makeIncrIf(queryFlagChart.Copy(), cumulative), + makeIncrIf(answerRCodeChart.Copy(), cumulative), + } +} + +func threadCharts(thread string, cumulative bool) *Charts { + charts := charts(cumulative) + _ = charts.Remove(uptimeChart.ID) + + for i, chart := range *charts { + convertTotalChartToThread(chart, thread, prioThread+i) + } + return charts +} + +func convertTotalChartToThread(chart *Chart, thread string, priority int) { + chart.ID = fmt.Sprintf("%s_%s", thread, chart.ID) + chart.Title = fmt.Sprintf("%s %s", strings.Title(thread), chart.Title) + chart.Fam = thread + "_stats" + chart.Ctx = fmt.Sprintf("%s_%s", chart.Ctx, thread) + chart.Priority = priority + for _, dim := range chart.Dims { + dim.ID = strings.Replace(dim.ID, "total", thread, 1) + } +} + +// Common stats charts +var ( + queriesChart = Chart{ + ID: "queries", + Title: "Received Queries", + Units: "queries", + Fam: "queries", + Ctx: "unbound.queries", + Priority: prioQueries, + Dims: Dims{ + {ID: "total.num.queries", Name: "queries"}, + }, + } + ipRateLimitedQueriesChart = Chart{ + ID: "queries_ip_ratelimited", + Title: "Rate Limited Queries", + Units: "queries", + Fam: "queries", + Ctx: "unbound.queries_ip_ratelimited", + Priority: prioIPRateLimitedQueries, + Dims: Dims{ + {ID: "total.num.queries_ip_ratelimited", Name: "ratelimited"}, + }, + } + // ifdef USE_DNSCRYPT + dnsCryptChart = Chart{ + ID: "dnscrypt_queries", + Title: "DNSCrypt Queries", + Units: "queries", + Fam: "queries", + Ctx: "unbound.dnscrypt_queries", + Priority: prioDNSCryptQueries, + Dims: Dims{ + {ID: "total.num.dnscrypt.crypted", Name: "crypted"}, + {ID: "total.num.dnscrypt.cert", Name: "cert"}, + {ID: "total.num.dnscrypt.cleartext", Name: "cleartext"}, + {ID: "total.num.dnscrypt.malformed", Name: "malformed"}, + }, + } + cacheChart = Chart{ + ID: "cache", + Title: "Cache Statistics", + Units: "events", + Fam: "cache", + Ctx: "unbound.cache", + Type: module.Stacked, + Priority: prioCache, + Dims: Dims{ + {ID: "total.num.cachehits", Name: "hits"}, + {ID: "total.num.cachemiss", Name: "miss"}, + }, + } + cachePercentageChart = Chart{ + ID: "cache_percentage", + Title: "Cache Statistics Percentage", + Units: "percentage", + Fam: "cache", + Ctx: "unbound.cache_percentage", + Type: module.Stacked, + Priority: prioCachePercentage, + Dims: Dims{ + {ID: "total.num.cachehits", Name: "hits", Algo: module.PercentOfAbsolute}, + {ID: "total.num.cachemiss", Name: "miss", Algo: module.PercentOfAbsolute}, + }, + } + prefetchChart = Chart{ + ID: "cache_prefetch", + Title: "Cache Prefetches", + Units: "prefetches", + Fam: "cache", + Ctx: "unbound.prefetch", + Priority: prioCachePrefetch, + Dims: Dims{ + {ID: "total.num.prefetch", Name: "prefetches"}, + }, + } + zeroTTLChart = Chart{ + ID: "zero_ttl_replies", + Title: "Replies Served From Expired Cache", + Units: "replies", + Fam: "cache", + Ctx: "unbound.zero_ttl_replies", + Priority: prioZeroTTL, + Dims: Dims{ + {ID: "total.num.zero_ttl", Name: "zero_ttl"}, + }, + } + recurRepliesChart = Chart{ + ID: "recursive_replies", + Title: "Replies That Needed Recursive Processing", + Units: "replies", + Fam: "replies", + Ctx: "unbound.recursive_replies", + Priority: prioRecurReplies, + Dims: Dims{ + {ID: "total.num.recursivereplies", Name: "recursive"}, + }, + } + recurTimeChart = Chart{ + ID: "recursion_time", + Title: "Time Spent On Recursive Processing", + Units: "milliseconds", + Fam: "recursion timings", + Ctx: "unbound.recursion_time", + Priority: prioRecurTime, + Dims: Dims{ + {ID: "total.recursion.time.avg", Name: "avg"}, + {ID: "total.recursion.time.median", Name: "median"}, + }, + } + reqListUsageChart = Chart{ + ID: "request_list_usage", + Title: "Request List Usage", + Units: "queries", + Fam: "request list", + Ctx: "unbound.request_list_usage", + Priority: prioReqListUsage, + Dims: Dims{ + {ID: "total.requestlist.avg", Name: "avg", Div: 1000}, + {ID: "total.requestlist.max", Name: "max"}, // all time max in cumulative mode, never resets + }, + } + reqListCurUsageChart = Chart{ + ID: "current_request_list_usage", + Title: "Current Request List Usage", + Units: "queries", + Fam: "request list", + Ctx: "unbound.current_request_list_usage", + Type: module.Area, + Priority: prioReqListCurUsage, + Dims: Dims{ + {ID: "total.requestlist.current.all", Name: "all"}, + {ID: "total.requestlist.current.user", Name: "user"}, + }, + } + reqListJostleChart = Chart{ + ID: "request_list_jostle_list", + Title: "Request List Jostle List Events", + Units: "queries", + Fam: "request list", + Ctx: "unbound.request_list_jostle_list", + Priority: prioReqListJostle, + Dims: Dims{ + {ID: "total.requestlist.overwritten", Name: "overwritten"}, + {ID: "total.requestlist.exceeded", Name: "dropped"}, + }, + } + tcpUsageChart = Chart{ + ID: "tcpusage", + Title: "TCP Handler Buffers", + Units: "buffers", + Fam: "tcp buffers", + Ctx: "unbound.tcpusage", + Priority: prioTCPUsage, + Dims: Dims{ + {ID: "total.tcpusage", Name: "usage"}, + }, + } + uptimeChart = Chart{ + ID: "uptime", + Title: "Uptime", + Units: "seconds", + Fam: "uptime", + Ctx: "unbound.uptime", + Priority: prioUptime, + Dims: Dims{ + {ID: "time.up", Name: "time"}, + }, + } +) + +// Extended stats charts +var ( + // TODO: do not add dnscrypt stuff by default? + memCacheChart = Chart{ + ID: "cache_memory", + Title: "Cache Memory", + Units: "KB", + Fam: "mem", + Ctx: "unbound.cache_memory", + Type: module.Stacked, + Priority: prioMemCache, + Dims: Dims{ + {ID: "mem.cache.message", Name: "message", Div: 1024}, + {ID: "mem.cache.rrset", Name: "rrset", Div: 1024}, + {ID: "mem.cache.dnscrypt_nonce", Name: "dnscrypt_nonce", Div: 1024}, // ifdef USE_DNSCRYPT + {ID: "mem.cache.dnscrypt_shared_secret", Name: "dnscrypt_shared_secret", Div: 1024}, // ifdef USE_DNSCRYPT + }, + } + // TODO: do not add subnet and ipsecmod stuff by default? + memModChart = Chart{ + ID: "mod_memory", + Title: "Module Memory", + Units: "KB", + Fam: "mem", + Ctx: "unbound.mod_memory", + Type: module.Stacked, + Priority: prioMemMod, + Dims: Dims{ + {ID: "mem.mod.iterator", Name: "iterator", Div: 1024}, + {ID: "mem.mod.respip", Name: "respip", Div: 1024}, + {ID: "mem.mod.validator", Name: "validator", Div: 1024}, + {ID: "mem.mod.subnet", Name: "subnet", Div: 1024}, // ifdef CLIENT_SUBNET + {ID: "mem.mod.ipsecmod", Name: "ipsec", Div: 1024}, // ifdef USE_IPSECMOD + }, + } + memStreamWaitChart = Chart{ + ID: "mem_stream_wait", + Title: "TCP and TLS Stream Waif Buffer Memory", + Units: "KB", + Fam: "mem", + Ctx: "unbound.mem_streamwait", + Priority: prioMemStreamWait, + Dims: Dims{ + {ID: "mem.streamwait", Name: "streamwait", Div: 1024}, + }, + } + // NOTE: same family as for cacheChart + cacheCountChart = Chart{ + ID: "cache_count", + Title: "Cache Items Count", + Units: "items", + Fam: "cache", + Ctx: "unbound.cache_count", + Type: module.Stacked, + Priority: prioCacheCount, + Dims: Dims{ + {ID: "infra.cache.count", Name: "infra"}, + {ID: "key.cache.count", Name: "key"}, + {ID: "msg.cache.count", Name: "msg"}, + {ID: "rrset.cache.count", Name: "rrset"}, + {ID: "dnscrypt_nonce.cache.count", Name: "dnscrypt_nonce"}, + {ID: "dnscrypt_shared_secret.cache.count", Name: "shared_secret"}, + }, + } + queryTypeChart = Chart{ + ID: "queries_by_type", + Title: "Queries By Type", + Units: "queries", + Fam: "queries", + Ctx: "unbound.type_queries", + Type: module.Stacked, + Priority: prioQueryType, + } + queryClassChart = Chart{ + ID: "queries_by_class", + Title: "Queries By Class", + Units: "queries", + Fam: "queries", + Ctx: "unbound.class_queries", + Type: module.Stacked, + Priority: prioQueryClass, + } + queryOpCodeChart = Chart{ + ID: "queries_by_opcode", + Title: "Queries By OpCode", + Units: "queries", + Fam: "queries", + Ctx: "unbound.opcode_queries", + Type: module.Stacked, + Priority: prioQueryOpCode, + } + queryFlagChart = Chart{ + ID: "queries_by_flag", + Title: "Queries By Flag", + Units: "queries", + Fam: "queries", + Ctx: "unbound.flag_queries", + Type: module.Stacked, + Priority: prioQueryFlag, + Dims: Dims{ + {ID: "num.query.flags.QR", Name: "QR"}, + {ID: "num.query.flags.AA", Name: "AA"}, + {ID: "num.query.flags.TC", Name: "TC"}, + {ID: "num.query.flags.RD", Name: "RD"}, + {ID: "num.query.flags.RA", Name: "RA"}, + {ID: "num.query.flags.Z", Name: "Z"}, + {ID: "num.query.flags.AD", Name: "AD"}, + {ID: "num.query.flags.CD", Name: "CD"}, + }, + } + answerRCodeChart = Chart{ + ID: "replies_by_rcode", + Title: "Replies By RCode", + Units: "replies", + Fam: "replies", + Ctx: "unbound.rcode_answers", + Type: module.Stacked, + Priority: prioReplyRCode, + } +) + +func (u *Unbound) updateCharts() { + if len(u.curCache.threads) > 1 { + for v := range u.curCache.threads { + if !u.cache.threads[v] { + u.cache.threads[v] = true + u.addThreadCharts(v) + } + } + } + // 0-6 rcodes always included + if hasExtendedData := len(u.curCache.answerRCode) > 0; !hasExtendedData { + return + } + + if !u.extChartsCreated { + charts := extendedCharts(u.Cumulative) + if err := u.Charts().Add(*charts...); err != nil { + u.Warningf("add extended charts: %v", err) + } + u.extChartsCreated = true + } + + for v := range u.curCache.queryType { + if !u.cache.queryType[v] { + u.cache.queryType[v] = true + u.addDimToQueryTypeChart(v) + } + } + for v := range u.curCache.queryClass { + if !u.cache.queryClass[v] { + u.cache.queryClass[v] = true + u.addDimToQueryClassChart(v) + } + } + for v := range u.curCache.queryOpCode { + if !u.cache.queryOpCode[v] { + u.cache.queryOpCode[v] = true + u.addDimToQueryOpCodeChart(v) + } + } + for v := range u.curCache.answerRCode { + if !u.cache.answerRCode[v] { + u.cache.answerRCode[v] = true + u.addDimToAnswerRcodeChart(v) + } + } +} + +func (u *Unbound) addThreadCharts(thread string) { + charts := threadCharts(thread, u.Cumulative) + if err := u.Charts().Add(*charts...); err != nil { + u.Warningf("add '%s' charts: %v", thread, err) + } +} + +func (u *Unbound) addDimToQueryTypeChart(typ string) { + u.addDimToChart(queryTypeChart.ID, "num.query.type."+typ, typ) +} +func (u *Unbound) addDimToQueryClassChart(class string) { + u.addDimToChart(queryClassChart.ID, "num.query.class."+class, class) +} +func (u *Unbound) addDimToQueryOpCodeChart(opcode string) { + u.addDimToChart(queryOpCodeChart.ID, "num.query.opcode."+opcode, opcode) +} +func (u *Unbound) addDimToAnswerRcodeChart(rcode string) { + u.addDimToChart(answerRCodeChart.ID, "num.answer.rcode."+rcode, rcode) +} + +func (u *Unbound) addDimToChart(chartID, dimID, dimName string) { + chart := u.Charts().Get(chartID) + if chart == nil { + u.Warningf("add '%s' dim: couldn't find '%s' chart", dimID, chartID) + return + } + dim := &Dim{ID: dimID, Name: dimName} + if u.Cumulative { + dim.Algo = module.Incremental + } + if err := chart.AddDim(dim); err != nil { + u.Warningf("add '%s' dim: %v", dimID, err) + return + } + chart.MarkNotCreated() +} + +func makeIncrIf(chart *Chart, do bool) *Chart { + if !do { + return chart + } + chart.Units += "/s" + for _, d := range chart.Dims { + d.Algo = module.Incremental + } + return chart +} + +func makePercOfIncrIf(chart *Chart, do bool) *Chart { + if !do { + return chart + } + for _, d := range chart.Dims { + d.Algo = module.PercentOfIncremental + } + return chart +} diff --git a/modules/unbound/client.go b/modules/unbound/client.go new file mode 100644 index 000000000..e0645b341 --- /dev/null +++ b/modules/unbound/client.go @@ -0,0 +1,120 @@ +package unbound + +import ( + "bufio" + "crypto/tls" + "fmt" + "io" + "net" + "strings" + "time" +) + +type clientConfig struct { + address string + timeout time.Duration + useTLS bool + tlsConf *tls.Config +} + +func newClient(config clientConfig) *client { + network := "tcp" + if strings.HasPrefix("/", config.address) { + network = "unix" + } + return &client{ + network: network, + address: config.address, + timeout: config.timeout, + useTLS: config.useTLS, + tlsConf: config.tlsConf, + reuseRecord: true, + record: nil, + conn: nil, + } +} + +type client struct { + network string + address string + timeout time.Duration + useTLS bool + tlsConf *tls.Config + reuseRecord bool + record []string + conn net.Conn +} + +func (c client) dial() (net.Conn, error) { + if !c.useTLS { + return net.DialTimeout(c.network, c.address, c.timeout) + } + var d net.Dialer + d.Timeout = c.timeout + return tls.DialWithDialer(&d, c.network, c.address, c.tlsConf) +} + +func (c *client) connect() (err error) { + c.conn, err = c.dial() + return err +} + +func (c *client) disconnect() error { + err := c.conn.Close() + c.conn = nil + return err +} + +func (c *client) write(command string) (int, error) { + err := c.conn.SetWriteDeadline(time.Now().Add(c.timeout)) + if err != nil { + return 0, err + } + return c.conn.Write([]byte(command)) +} + +func (c *client) read() (record []string, err error) { + if err = c.conn.SetReadDeadline(time.Now().Add(c.timeout)); err != nil { + return nil, err + } + if c.reuseRecord { + record, err = read(c.record, c.conn) + c.record = record + } else { + record, err = read(nil, c.conn) + } + return record, err +} + +func (c *client) send(command string) (lines []string, err error) { + if err = c.connect(); err != nil { + return nil, err + } + defer func() { + _ = c.disconnect() + }() + if _, err = c.write(command); err != nil { + return nil, err + } + return c.read() +} + +// just a high value, number of lines depends on number of threads, every thread adds 20 lines +const maxLinesToRead = 2000 + +// https://github.com/NLnetLabs/unbound/blob/master/doc/control_proto_spec.txt +// Server executes command. And sends reply in ascii text over channel, closes the channel when done. +func read(dst []string, reader io.Reader) ([]string, error) { + dst = dst[:0] + var num int + s := bufio.NewScanner(reader) + + for s.Scan() { + dst = append(dst, s.Text()) + num++ + if num > maxLinesToRead { + return nil, fmt.Errorf("read line limit exceeded (%d)", maxLinesToRead) + } + } + return dst, s.Err() +} diff --git a/modules/unbound/client_test.go b/modules/unbound/client_test.go new file mode 100644 index 000000000..8f9667c3d --- /dev/null +++ b/modules/unbound/client_test.go @@ -0,0 +1,98 @@ +package unbound + +import ( + "bufio" + "errors" + "net" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +const ( + srvAddress = "127.0.0.1:38002" +) + +func Test_clientSend(t *testing.T) { + srv := &tcpServer{addr: srvAddress, respNumLines: 10} + go srv.Run() + defer srv.Close() + time.Sleep(time.Second) + + c := newClient(clientConfig{ + address: srvAddress, + timeout: time.Second, + }) + + lines, err := c.send("whatever\n") + assert.NoError(t, err) + assert.Len(t, lines, 10) + + lines, err = c.send("whatever\n") + assert.NoError(t, err) + assert.Len(t, lines, 10) +} + +func Test_clientSend_ReadLineLimitExceeded(t *testing.T) { + srv := &tcpServer{addr: srvAddress, respNumLines: maxLinesToRead + 1} + go srv.Run() + defer srv.Close() + time.Sleep(time.Second) + + c := newClient(clientConfig{ + address: srvAddress, + timeout: time.Second, + }) + + lines, err := c.send("whatever\n") + assert.Error(t, err) + assert.Len(t, lines, 0) +} + +type tcpServer struct { + addr string + server net.Listener + respNumLines int +} + +func (t *tcpServer) Run() (err error) { + t.server, err = net.Listen("tcp", t.addr) + if err != nil { + return + } + return t.handleConnections() +} + +func (t *tcpServer) Close() (err error) { + return t.server.Close() +} + +func (t *tcpServer) handleConnections() error { + for { + conn, err := t.server.Accept() + if err != nil || conn == nil { + return errors.New("could not accept connection") + } + go t.handleConnection(conn) + } +} + +func (t *tcpServer) handleConnection(conn net.Conn) { + defer conn.Close() + _ = conn.SetDeadline(time.Now().Add(time.Second * 2)) + + rw := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + + req, err := rw.ReadString('\n') + if err != nil { + _, _ = rw.WriteString("error failed to read input") + _ = rw.Flush() + return + } + + resp := strings.Repeat(req, t.respNumLines) + _, _ = rw.WriteString(resp) + _ = rw.Flush() +} diff --git a/modules/unbound/collect.go b/modules/unbound/collect.go new file mode 100644 index 000000000..2094fb730 --- /dev/null +++ b/modules/unbound/collect.go @@ -0,0 +1,196 @@ +package unbound + +import ( + "fmt" + "strconv" + "strings" +) + +// https://github.com/NLnetLabs/unbound/blob/master/daemon/remote.c (do_stats: print_stats, print_thread_stats, print_mem, print_uptime, print_ext) +// https://github.com/NLnetLabs/unbound/blob/master/libunbound/unbound.h (structs: ub_server_stats, ub_shm_stat_info) +// https://docs.datadoghq.com/integrations/unbound/#metrics (stats description) +// https://docs.menandmice.com/display/MM/Unbound+request-list+demystified (request lists explanation) + +func (u *Unbound) collect() (map[string]int64, error) { + stats, err := u.scrapeUnboundStats() + if err != nil { + return nil, err + } + + mx := u.collectStats(stats) + u.updateCharts() + return mx, nil +} + +func (u *Unbound) scrapeUnboundStats() ([]entry, error) { + var command = "UBCT1 stats" + if u.Cumulative { + command = "UBCT1 stats_noreset" + } + output, err := u.client.send(command + "\n") + if err != nil { + return nil, fmt.Errorf("send command '%s': %w", command, err) + } + switch len(output) { + case 0: + return nil, fmt.Errorf("command '%s': empty resopnse", command) + case 1: + // in case of error the first line of the response is: error \n + return nil, fmt.Errorf("command '%s': '%s'", command, output[0]) + } + return parseStatsOutput(output) +} + +func (u *Unbound) collectStats(stats []entry) map[string]int64 { + if u.Cumulative { + return u.collectCumulativeStats(stats) + } + return u.collectNonCumulativeStats(stats) +} + +func (u *Unbound) collectCumulativeStats(stats []entry) map[string]int64 { + mul := float64(1000) + // following stats change only on cachemiss event in cumulative mode + // - *.requestlist.avg, + // - *.recursion.time.avg + // - *.recursion.time.median + v := findEntry("total.num.cachemiss", stats) + if v == u.prevCacheMiss { + // so we need to reset them if there is no such event + mul = 0 + } + u.prevCacheMiss = v + return u.processStats(stats, mul) +} + +func (u *Unbound) collectNonCumulativeStats(stats []entry) map[string]int64 { + mul := float64(1000) + mx := u.processStats(stats, mul) + + // see 'static int print_ext(RES* ssl, struct ub_stats_info* s)' in + // https://github.com/NLnetLabs/unbound/blob/master/daemon/remote.c + // - zero value queries type not included + // - zero value queries class not included + // - zero value queries opcode not included + // - only 0-6 rcodes answers always included, other zero value rcodes not included + for k := range u.cache.queryType { + if _, ok := u.curCache.queryType[k]; !ok { + mx["num.query.type."+k] = 0 + } + } + for k := range u.cache.queryClass { + if _, ok := u.curCache.queryClass[k]; !ok { + mx["num.query.class."+k] = 0 + } + } + for k := range u.cache.queryOpCode { + if _, ok := u.curCache.queryOpCode[k]; !ok { + mx["num.query.opcode."+k] = 0 + } + } + for k := range u.cache.answerRCode { + if _, ok := u.curCache.answerRCode[k]; !ok { + mx["num.answer.rcode."+k] = 0 + } + } + return mx +} + +func (u *Unbound) processStats(stats []entry, mul float64) map[string]int64 { + u.curCache.clear() + mx := make(map[string]int64, len(stats)) + for _, e := range stats { + switch { + // *.requestlist.avg, *.recursion.time.avg, *.recursion.time.median + case e.hasSuffix(".avg"), e.hasSuffix(".median"): + e.value *= mul + case e.hasPrefix("thread") && e.hasSuffix("num.queries"): + v := extractThread(e.key) + u.curCache.threads[v] = true + case e.hasPrefix("num.query.type"): + v := extractQueryType(e.key) + u.curCache.queryType[v] = true + case e.hasPrefix("num.query.class"): + v := extractQueryClass(e.key) + u.curCache.queryClass[v] = true + case e.hasPrefix("num.query.opcode"): + v := extractQueryOpCode(e.key) + u.curCache.queryOpCode[v] = true + case e.hasPrefix("num.answer.rcode"): + v := extractAnswerRCode(e.key) + u.curCache.answerRCode[v] = true + } + mx[e.key] = int64(e.value) + } + return mx +} + +func extractThread(key string) string { idx := strings.IndexByte(key, '.'); return key[:idx] } +func extractQueryType(key string) string { i := len("num.query.type."); return key[i:] } +func extractQueryClass(key string) string { i := len("num.query.class."); return key[i:] } +func extractQueryOpCode(key string) string { i := len("num.query.opcode."); return key[i:] } +func extractAnswerRCode(key string) string { i := len("num.answer.rcode."); return key[i:] } + +type entry struct { + key string + value float64 +} + +func (e entry) hasPrefix(prefix string) bool { return strings.HasPrefix(e.key, prefix) } +func (e entry) hasSuffix(suffix string) bool { return strings.HasSuffix(e.key, suffix) } + +func findEntry(key string, entries []entry) float64 { + for _, e := range entries { + if e.key == key { + return e.value + } + } + return -1 +} + +func parseStatsOutput(output []string) ([]entry, error) { + var es []entry + for _, v := range output { + e, err := parseStatsLine(v) + if err != nil { + return nil, err + } + if e.hasPrefix("histogram") { + continue + } + es = append(es, e) + } + return es, nil +} + +func parseStatsLine(line string) (entry, error) { + // 'stats' output is a list of [key]=[value] lines. + parts := strings.Split(line, "=") + if len(parts) != 2 { + return entry{}, fmt.Errorf("bad line syntax: %s", line) + } + f, err := strconv.ParseFloat(parts[1], 10) + return entry{key: parts[0], value: f}, err +} + +func newCollectCache() collectCache { + return collectCache{ + threads: make(map[string]bool), + queryType: make(map[string]bool), + queryClass: make(map[string]bool), + queryOpCode: make(map[string]bool), + answerRCode: make(map[string]bool), + } +} + +type collectCache struct { + threads map[string]bool + queryType map[string]bool + queryClass map[string]bool + queryOpCode map[string]bool + answerRCode map[string]bool +} + +func (c *collectCache) clear() { + *c = newCollectCache() +} diff --git a/modules/unbound/init.go b/modules/unbound/init.go new file mode 100644 index 000000000..348db8d8a --- /dev/null +++ b/modules/unbound/init.go @@ -0,0 +1,177 @@ +package unbound + +import ( + "bytes" + "crypto/tls" + "errors" + "fmt" + "io/ioutil" + "net" + "strings" + + "github.com/netdata/go.d.plugin/pkg/web" + + "gopkg.in/yaml.v2" +) + +type ( + str string + strBool string +) + +func (s str) isSet() bool { return s != "" } +func (s str) value() string { return string(s) } +func (s strBool) isSet() bool { return s != "" } +func (s strBool) value() bool { return s == "yes" } + +type unboundConfig struct { + Srv *struct { + Cumulative strBool `yaml:"statistics-cumulative,omitempty"` + } `yaml:"server"` + RC *struct { + Enable strBool `yaml:"control-enable,omitempty"` + Interface str `yaml:"control-interface,omitempty"` + Port str `yaml:"control-port,omitempty"` + UseCert strBool `yaml:"control-use-cert,omitempty"` + KeyFile str `yaml:"control-key-file,omitempty"` + CertFile str `yaml:"control-cert-file,omitempty"` + } `yaml:"remote-control"` +} + +func (c unboundConfig) String() string { b, _ := yaml.Marshal(c); return string(b) } +func (c unboundConfig) hasServer() bool { return c.Srv != nil } +func (c unboundConfig) hasRemoteControl() bool { return c.RC != nil } + +func (c unboundConfig) isRemoteControlDisabled() bool { + return c.hasRemoteControl() && c.RC.Enable.isSet() && !c.RC.Enable.value() +} + +func (u *Unbound) initConfig() (enabled bool) { + // TODO: config parameters auto detection by reading the config file feature is questionable + // unbound config file is not in yaml format, it looks like yaml but it is not, for example it allows such config + // remote-control: + // control-interface: 0.0.0.0 + // control-interface: /var/run/unbound.sock + // Module will try to get stats from /var/run/unbound.sock and fail. Unbound doesnt allow to query stats from + // unix socket when control-interface enabled on ip interface + if u.ConfPath == "" { + u.Info("'conf_path' not set, skipping parameters auto detection") + return true + } + u.Infof("reading '%s'", u.ConfPath) + cfg, err := readConfig(u.ConfPath) + if err != nil { + u.Warningf("%v, skipping parameters auto detection", err) + return true + } + if cfg.isRemoteControlDisabled() { + u.Info("remote control is disabled in the configuration file") + return false + } + u.applyConfig(cfg) + return true +} + +func (u *Unbound) applyConfig(cfg *unboundConfig) { + u.Debugf("applying configuration:\n%s", cfg) + if cfg.hasServer() && cfg.Srv.Cumulative.isSet() { + if cfg.Srv.Cumulative.value() != u.Cumulative { + u.Debugf("changing 'cumulative_stats': %v => %v", u.Cumulative, cfg.Srv.Cumulative.value()) + u.Cumulative = cfg.Srv.Cumulative.value() + } + } + + if !cfg.hasRemoteControl() { + return + } + if cfg.RC.UseCert.isSet() { + if cfg.RC.UseCert.value() != u.UseTLS { + u.Debugf("changing 'use_tls': %v => %v", u.UseTLS, cfg.RC.UseCert.value()) + u.UseTLS = cfg.RC.UseCert.value() + } + } + + if cfg.RC.KeyFile.isSet() { + if cfg.RC.KeyFile.value() != u.TLSKey { + u.Debugf("changing 'tls_key': '%s' => '%s'", u.TLSKey, cfg.RC.KeyFile) + u.TLSKey = cfg.RC.KeyFile.value() + } + } + + if cfg.RC.CertFile.isSet() { + if cfg.RC.CertFile.value() != u.TLSCert { + u.Debugf("changing 'tls_cert': '%s' => '%s'", u.TLSCert, cfg.RC.CertFile) + u.TLSCert = cfg.RC.CertFile.value() + } + } + + if cfg.RC.Interface.isSet() { + if v := adjustControlInterface(cfg.RC.Interface.value()); v != u.Address { + u.Debugf("changing 'address': '%s' => '%s'", u.Address, v) + u.Address = v + } + } + + if cfg.RC.Port.isSet() && !isUnixSocket(u.Address) { + if host, port, err := net.SplitHostPort(u.Address); err == nil && port != cfg.RC.Port.value() { + address := net.JoinHostPort(host, cfg.RC.Port.value()) + u.Debugf("changing 'address': '%s' => '%s'", u.Address, address) + u.Address = address + } + } +} + +func (u *Unbound) initClient() (err error) { + var tlsCfg *tls.Config + useTLS := !isUnixSocket(u.Address) && u.UseTLS + if useTLS && (u.TLSCert == "" || u.TLSKey == "") { + return errors.New("'tls_cert' or 'tls_key' is missing") + } + if useTLS { + if tlsCfg, err = web.NewTLSConfig(u.ClientTLSConfig); err != nil { + return err + } + } + + u.client = newClient(clientConfig{ + address: u.Address, + timeout: u.Timeout.Duration, + useTLS: useTLS, + tlsConf: tlsCfg, + }) + return nil +} + +func adjustControlInterface(value string) string { + if isUnixSocket(value) { + return value + } + if value == "0.0.0.0" { + value = "127.0.0.1" + } + return net.JoinHostPort(value, "8953") +} + +func isUnixSocket(address string) bool { + return strings.HasPrefix(address, "/") +} + +func readConfig(config string) (*unboundConfig, error) { + b, err := ioutil.ReadFile(config) + if err != nil { + return nil, fmt.Errorf("error on reading config: %v", err) + } + + b = adjustUnboundConfig(b) + + var cfg unboundConfig + if err := yaml.Unmarshal(b, &cfg); err != nil { + return nil, fmt.Errorf("error on parsing config: %v", err) + } + return &cfg, nil +} + +func adjustUnboundConfig(cfg []byte) []byte { + // unbound config format is not yaml, but the fix makes it readable at least + return bytes.ReplaceAll(cfg, []byte("\t"), []byte(" ")) +} diff --git a/modules/unbound/testdata/stats/common.txt b/modules/unbound/testdata/stats/common.txt new file mode 100644 index 000000000..a62657cd6 --- /dev/null +++ b/modules/unbound/testdata/stats/common.txt @@ -0,0 +1,63 @@ +thread0.num.queries=28 +thread0.num.queries_ip_ratelimited=0 +thread0.num.cachehits=21 +thread0.num.cachemiss=7 +thread0.num.prefetch=0 +thread0.num.zero_ttl=0 +thread0.num.recursivereplies=7 +thread0.num.dnscrypt.crypted=0 +thread0.num.dnscrypt.cert=0 +thread0.num.dnscrypt.cleartext=0 +thread0.num.dnscrypt.malformed=0 +thread0.requestlist.avg=0.857143 +thread0.requestlist.max=6 +thread0.requestlist.overwritten=0 +thread0.requestlist.exceeded=0 +thread0.requestlist.current.all=0 +thread0.requestlist.current.user=0 +thread0.recursion.time.avg=1.255822 +thread0.recursion.time.median=0.480597 +thread0.tcpusage=0 +thread1.num.queries=16 +thread1.num.queries_ip_ratelimited=0 +thread1.num.cachehits=13 +thread1.num.cachemiss=3 +thread1.num.prefetch=0 +thread1.num.zero_ttl=0 +thread1.num.recursivereplies=3 +thread1.num.dnscrypt.crypted=0 +thread1.num.dnscrypt.cert=0 +thread1.num.dnscrypt.cleartext=0 +thread1.num.dnscrypt.malformed=0 +thread1.requestlist.avg=0 +thread1.requestlist.max=0 +thread1.requestlist.overwritten=0 +thread1.requestlist.exceeded=0 +thread1.requestlist.current.all=0 +thread1.requestlist.current.user=0 +thread1.recursion.time.avg=0.093941 +thread1.recursion.time.median=0 +thread1.tcpusage=0 +total.num.queries=44 +total.num.queries_ip_ratelimited=0 +total.num.cachehits=34 +total.num.cachemiss=10 +total.num.prefetch=0 +total.num.zero_ttl=0 +total.num.recursivereplies=10 +total.num.dnscrypt.crypted=0 +total.num.dnscrypt.cert=0 +total.num.dnscrypt.cleartext=0 +total.num.dnscrypt.malformed=0 +total.requestlist.avg=0.6 +total.requestlist.max=6 +total.requestlist.overwritten=0 +total.requestlist.exceeded=0 +total.requestlist.current.all=0 +total.requestlist.current.user=0 +total.recursion.time.avg=0.907258 +total.recursion.time.median=0.240299 +total.tcpusage=0 +time.now=1574094836.941149 +time.up=88.434983 +time.elapsed=88.4349831 \ No newline at end of file diff --git a/modules/unbound/testdata/stats/extended.txt b/modules/unbound/testdata/stats/extended.txt new file mode 100644 index 000000000..222b70831 --- /dev/null +++ b/modules/unbound/testdata/stats/extended.txt @@ -0,0 +1,159 @@ +thread0.num.queries=28 +thread0.num.queries_ip_ratelimited=0 +thread0.num.cachehits=21 +thread0.num.cachemiss=7 +thread0.num.prefetch=0 +thread0.num.zero_ttl=0 +thread0.num.recursivereplies=7 +thread0.num.dnscrypt.crypted=0 +thread0.num.dnscrypt.cert=0 +thread0.num.dnscrypt.cleartext=0 +thread0.num.dnscrypt.malformed=0 +thread0.requestlist.avg=0.857143 +thread0.requestlist.max=6 +thread0.requestlist.overwritten=0 +thread0.requestlist.exceeded=0 +thread0.requestlist.current.all=0 +thread0.requestlist.current.user=0 +thread0.recursion.time.avg=1.255822 +thread0.recursion.time.median=0.480597 +thread0.tcpusage=0 +thread1.num.queries=16 +thread1.num.queries_ip_ratelimited=0 +thread1.num.cachehits=13 +thread1.num.cachemiss=3 +thread1.num.prefetch=0 +thread1.num.zero_ttl=0 +thread1.num.recursivereplies=3 +thread1.num.dnscrypt.crypted=0 +thread1.num.dnscrypt.cert=0 +thread1.num.dnscrypt.cleartext=0 +thread1.num.dnscrypt.malformed=0 +thread1.requestlist.avg=0 +thread1.requestlist.max=0 +thread1.requestlist.overwritten=0 +thread1.requestlist.exceeded=0 +thread1.requestlist.current.all=0 +thread1.requestlist.current.user=0 +thread1.recursion.time.avg=0.093941 +thread1.recursion.time.median=0 +thread1.tcpusage=0 +total.num.queries=44 +total.num.queries_ip_ratelimited=0 +total.num.cachehits=34 +total.num.cachemiss=10 +total.num.prefetch=0 +total.num.zero_ttl=0 +total.num.recursivereplies=10 +total.num.dnscrypt.crypted=0 +total.num.dnscrypt.cert=0 +total.num.dnscrypt.cleartext=0 +total.num.dnscrypt.malformed=0 +total.requestlist.avg=0.6 +total.requestlist.max=6 +total.requestlist.overwritten=0 +total.requestlist.exceeded=0 +total.requestlist.current.all=0 +total.requestlist.current.user=0 +total.recursion.time.avg=0.907258 +total.recursion.time.median=0.240299 +total.tcpusage=0 +time.now=1574094836.941149 +time.up=88.434983 +time.elapsed=88.434983 +mem.cache.rrset=178642 +mem.cache.message=90357 +mem.mod.iterator=16588 +mem.mod.validator=81059 +mem.mod.respip=0 +mem.mod.subnet=74504 +mem.cache.dnscrypt_shared_secret=0 +mem.cache.dnscrypt_nonce=0 +mem.streamwait=0 +histogram.000000.000000.to.000000.000001=0 +histogram.000000.000001.to.000000.000002=0 +histogram.000000.000002.to.000000.000004=0 +histogram.000000.000004.to.000000.000008=0 +histogram.000000.000008.to.000000.000016=0 +histogram.000000.000016.to.000000.000032=0 +histogram.000000.000032.to.000000.000064=0 +histogram.000000.000064.to.000000.000128=0 +histogram.000000.000128.to.000000.000256=0 +histogram.000000.000256.to.000000.000512=0 +histogram.000000.000512.to.000000.001024=0 +histogram.000000.001024.to.000000.002048=0 +histogram.000000.002048.to.000000.004096=0 +histogram.000000.004096.to.000000.008192=0 +histogram.000000.008192.to.000000.016384=0 +histogram.000000.016384.to.000000.032768=0 +histogram.000000.032768.to.000000.065536=2 +histogram.000000.065536.to.000000.131072=0 +histogram.000000.131072.to.000000.262144=2 +histogram.000000.262144.to.000000.524288=3 +histogram.000000.524288.to.000001.000000=2 +histogram.000001.000000.to.000002.000000=0 +histogram.000002.000000.to.000004.000000=0 +histogram.000004.000000.to.000008.000000=1 +histogram.000008.000000.to.000016.000000=0 +histogram.000016.000000.to.000032.000000=0 +histogram.000032.000000.to.000064.000000=0 +histogram.000064.000000.to.000128.000000=0 +histogram.000128.000000.to.000256.000000=0 +histogram.000256.000000.to.000512.000000=0 +histogram.000512.000000.to.001024.000000=0 +histogram.001024.000000.to.002048.000000=0 +histogram.002048.000000.to.004096.000000=0 +histogram.004096.000000.to.008192.000000=0 +histogram.008192.000000.to.016384.000000=0 +histogram.016384.000000.to.032768.000000=0 +histogram.032768.000000.to.065536.000000=0 +histogram.065536.000000.to.131072.000000=0 +histogram.131072.000000.to.262144.000000=0 +histogram.262144.000000.to.524288.000000=0 +num.query.type.A=13 +num.query.type.PTR=5 +num.query.type.MX=13 +num.query.type.AAAA=13 +num.query.class.IN=44 +num.query.opcode.QUERY=44 +num.query.tcp=0 +num.query.tcpout=1 +num.query.tls=0 +num.query.tls.resume=0 +num.query.ipv6=39 +num.query.flags.QR=0 +num.query.flags.AA=0 +num.query.flags.TC=0 +num.query.flags.RD=44 +num.query.flags.RA=0 +num.query.flags.Z=0 +num.query.flags.AD=0 +num.query.flags.CD=0 +num.query.edns.present=0 +num.query.edns.DO=0 +num.answer.rcode.NOERROR=40 +num.answer.rcode.FORMERR=0 +num.answer.rcode.SERVFAIL=0 +num.answer.rcode.NXDOMAIN=4 +num.answer.rcode.NOTIMPL=0 +num.answer.rcode.REFUSED=0 +num.query.ratelimited=0 +num.answer.secure=0 +num.answer.bogus=0 +num.rrset.bogus=0 +num.query.aggressive.NOERROR=2 +num.query.aggressive.NXDOMAIN=0 +unwanted.queries=0 +unwanted.replies=0 +msg.cache.count=81 +rrset.cache.count=314 +infra.cache.count=205 +key.cache.count=9 +dnscrypt_shared_secret.cache.count=0 +dnscrypt_nonce.cache.count=0 +num.query.dnscrypt.shared_secret.cachemiss=0 +num.query.dnscrypt.replay=0 +num.query.authzone.up=0 +num.query.authzone.down=0 +num.query.subnet=0 +num.query.subnet_cache=0 \ No newline at end of file diff --git a/modules/unbound/testdata/stats/lifecycle/cumulative/extended1.txt b/modules/unbound/testdata/stats/lifecycle/cumulative/extended1.txt new file mode 100644 index 000000000..ac2b6c958 --- /dev/null +++ b/modules/unbound/testdata/stats/lifecycle/cumulative/extended1.txt @@ -0,0 +1,159 @@ +thread0.num.queries=90 +thread0.num.queries_ip_ratelimited=0 +thread0.num.cachehits=80 +thread0.num.cachemiss=10 +thread0.num.prefetch=0 +thread0.num.zero_ttl=0 +thread0.num.recursivereplies=10 +thread0.num.dnscrypt.crypted=0 +thread0.num.dnscrypt.cert=0 +thread0.num.dnscrypt.cleartext=0 +thread0.num.dnscrypt.malformed=0 +thread0.requestlist.avg=0.1 +thread0.requestlist.max=1 +thread0.requestlist.overwritten=0 +thread0.requestlist.exceeded=0 +thread0.requestlist.current.all=0 +thread0.requestlist.current.user=0 +thread0.recursion.time.avg=0.222018 +thread0.recursion.time.median=0.337042 +thread0.tcpusage=0 +thread1.num.queries=110 +thread1.num.queries_ip_ratelimited=0 +thread1.num.cachehits=101 +thread1.num.cachemiss=9 +thread1.num.prefetch=0 +thread1.num.zero_ttl=0 +thread1.num.recursivereplies=9 +thread1.num.dnscrypt.crypted=0 +thread1.num.dnscrypt.cert=0 +thread1.num.dnscrypt.cleartext=0 +thread1.num.dnscrypt.malformed=0 +thread1.requestlist.avg=0.222222 +thread1.requestlist.max=1 +thread1.requestlist.overwritten=0 +thread1.requestlist.exceeded=0 +thread1.requestlist.current.all=0 +thread1.requestlist.current.user=0 +thread1.recursion.time.avg=0.844506 +thread1.recursion.time.median=0.360448 +thread1.tcpusage=0 +total.num.queries=200 +total.num.queries_ip_ratelimited=0 +total.num.cachehits=181 +total.num.cachemiss=19 +total.num.prefetch=0 +total.num.zero_ttl=0 +total.num.recursivereplies=19 +total.num.dnscrypt.crypted=0 +total.num.dnscrypt.cert=0 +total.num.dnscrypt.cleartext=0 +total.num.dnscrypt.malformed=0 +total.requestlist.avg=0.157895 +total.requestlist.max=1 +total.requestlist.overwritten=0 +total.requestlist.exceeded=0 +total.requestlist.current.all=0 +total.requestlist.current.user=0 +total.recursion.time.avg=0.516881 +total.recursion.time.median=0.348745 +total.tcpusage=0 +time.now=1574103378.552596 +time.up=122.956436 +time.elapsed=122.956436 +mem.cache.rrset=175745 +mem.cache.message=93392 +mem.mod.iterator=16588 +mem.mod.validator=81479 +mem.mod.respip=0 +mem.mod.subnet=74504 +mem.cache.dnscrypt_shared_secret=0 +mem.cache.dnscrypt_nonce=0 +mem.streamwait=0 +histogram.000000.000000.to.000000.000001=0 +histogram.000000.000001.to.000000.000002=0 +histogram.000000.000002.to.000000.000004=0 +histogram.000000.000004.to.000000.000008=0 +histogram.000000.000008.to.000000.000016=0 +histogram.000000.000016.to.000000.000032=0 +histogram.000000.000032.to.000000.000064=0 +histogram.000000.000064.to.000000.000128=0 +histogram.000000.000128.to.000000.000256=0 +histogram.000000.000256.to.000000.000512=0 +histogram.000000.000512.to.000000.001024=0 +histogram.000000.001024.to.000000.002048=0 +histogram.000000.002048.to.000000.004096=0 +histogram.000000.004096.to.000000.008192=0 +histogram.000000.008192.to.000000.016384=2 +histogram.000000.016384.to.000000.032768=1 +histogram.000000.032768.to.000000.065536=3 +histogram.000000.065536.to.000000.131072=0 +histogram.000000.131072.to.000000.262144=0 +histogram.000000.262144.to.000000.524288=11 +histogram.000000.524288.to.000001.000000=0 +histogram.000001.000000.to.000002.000000=1 +histogram.000002.000000.to.000004.000000=0 +histogram.000004.000000.to.000008.000000=1 +histogram.000008.000000.to.000016.000000=0 +histogram.000016.000000.to.000032.000000=0 +histogram.000032.000000.to.000064.000000=0 +histogram.000064.000000.to.000128.000000=0 +histogram.000128.000000.to.000256.000000=0 +histogram.000256.000000.to.000512.000000=0 +histogram.000512.000000.to.001024.000000=0 +histogram.001024.000000.to.002048.000000=0 +histogram.002048.000000.to.004096.000000=0 +histogram.004096.000000.to.008192.000000=0 +histogram.008192.000000.to.016384.000000=0 +histogram.016384.000000.to.032768.000000=0 +histogram.032768.000000.to.065536.000000=0 +histogram.065536.000000.to.131072.000000=0 +histogram.131072.000000.to.262144.000000=0 +histogram.262144.000000.to.524288.000000=0 +num.query.type.A=60 +num.query.type.PTR=20 +num.query.type.MX=60 +num.query.type.AAAA=60 +num.query.class.IN=200 +num.query.opcode.QUERY=200 +num.query.tcp=0 +num.query.tcpout=0 +num.query.tls=0 +num.query.tls.resume=0 +num.query.ipv6=0 +num.query.flags.QR=0 +num.query.flags.AA=0 +num.query.flags.TC=0 +num.query.flags.RD=200 +num.query.flags.RA=0 +num.query.flags.Z=0 +num.query.flags.AD=0 +num.query.flags.CD=0 +num.query.edns.present=0 +num.query.edns.DO=0 +num.answer.rcode.NOERROR=184 +num.answer.rcode.FORMERR=0 +num.answer.rcode.SERVFAIL=0 +num.answer.rcode.NXDOMAIN=16 +num.answer.rcode.NOTIMPL=0 +num.answer.rcode.REFUSED=0 +num.query.ratelimited=0 +num.answer.secure=0 +num.answer.bogus=0 +num.rrset.bogus=0 +num.query.aggressive.NOERROR=1 +num.query.aggressive.NXDOMAIN=0 +unwanted.queries=0 +unwanted.replies=0 +msg.cache.count=94 +rrset.cache.count=304 +infra.cache.count=192 +key.cache.count=11 +dnscrypt_shared_secret.cache.count=0 +dnscrypt_nonce.cache.count=0 +num.query.dnscrypt.shared_secret.cachemiss=0 +num.query.dnscrypt.replay=0 +num.query.authzone.up=0 +num.query.authzone.down=0 +num.query.subnet=0 +num.query.subnet_cache=0 \ No newline at end of file diff --git a/modules/unbound/testdata/stats/lifecycle/cumulative/extended2.txt b/modules/unbound/testdata/stats/lifecycle/cumulative/extended2.txt new file mode 100644 index 000000000..75f027360 --- /dev/null +++ b/modules/unbound/testdata/stats/lifecycle/cumulative/extended2.txt @@ -0,0 +1,159 @@ +thread0.num.queries=133 +thread0.num.queries_ip_ratelimited=0 +thread0.num.cachehits=123 +thread0.num.cachemiss=10 +thread0.num.prefetch=0 +thread0.num.zero_ttl=0 +thread0.num.recursivereplies=10 +thread0.num.dnscrypt.crypted=0 +thread0.num.dnscrypt.cert=0 +thread0.num.dnscrypt.cleartext=0 +thread0.num.dnscrypt.malformed=0 +thread0.requestlist.avg=0.1 +thread0.requestlist.max=1 +thread0.requestlist.overwritten=0 +thread0.requestlist.exceeded=0 +thread0.requestlist.current.all=0 +thread0.requestlist.current.user=0 +thread0.recursion.time.avg=0.222018 +thread0.recursion.time.median=0.337042 +thread0.tcpusage=0 +thread1.num.queries=157 +thread1.num.queries_ip_ratelimited=0 +thread1.num.cachehits=148 +thread1.num.cachemiss=9 +thread1.num.prefetch=0 +thread1.num.zero_ttl=0 +thread1.num.recursivereplies=9 +thread1.num.dnscrypt.crypted=0 +thread1.num.dnscrypt.cert=0 +thread1.num.dnscrypt.cleartext=0 +thread1.num.dnscrypt.malformed=0 +thread1.requestlist.avg=0.222222 +thread1.requestlist.max=1 +thread1.requestlist.overwritten=0 +thread1.requestlist.exceeded=0 +thread1.requestlist.current.all=0 +thread1.requestlist.current.user=0 +thread1.recursion.time.avg=0.844506 +thread1.recursion.time.median=0.360448 +thread1.tcpusage=0 +total.num.queries=290 +total.num.queries_ip_ratelimited=0 +total.num.cachehits=271 +total.num.cachemiss=19 +total.num.prefetch=0 +total.num.zero_ttl=0 +total.num.recursivereplies=19 +total.num.dnscrypt.crypted=0 +total.num.dnscrypt.cert=0 +total.num.dnscrypt.cleartext=0 +total.num.dnscrypt.malformed=0 +total.requestlist.avg=0.157895 +total.requestlist.max=1 +total.requestlist.overwritten=0 +total.requestlist.exceeded=0 +total.requestlist.current.all=0 +total.requestlist.current.user=0 +total.recursion.time.avg=0.516881 +total.recursion.time.median=0.348745 +total.tcpusage=0 +time.now=1574103461.161540 +time.up=205.565380 +time.elapsed=82.608944 +mem.cache.rrset=175745 +mem.cache.message=93392 +mem.mod.iterator=16588 +mem.mod.validator=81479 +mem.mod.respip=0 +mem.mod.subnet=74504 +mem.cache.dnscrypt_shared_secret=0 +mem.cache.dnscrypt_nonce=0 +mem.streamwait=0 +histogram.000000.000000.to.000000.000001=0 +histogram.000000.000001.to.000000.000002=0 +histogram.000000.000002.to.000000.000004=0 +histogram.000000.000004.to.000000.000008=0 +histogram.000000.000008.to.000000.000016=0 +histogram.000000.000016.to.000000.000032=0 +histogram.000000.000032.to.000000.000064=0 +histogram.000000.000064.to.000000.000128=0 +histogram.000000.000128.to.000000.000256=0 +histogram.000000.000256.to.000000.000512=0 +histogram.000000.000512.to.000000.001024=0 +histogram.000000.001024.to.000000.002048=0 +histogram.000000.002048.to.000000.004096=0 +histogram.000000.004096.to.000000.008192=0 +histogram.000000.008192.to.000000.016384=2 +histogram.000000.016384.to.000000.032768=1 +histogram.000000.032768.to.000000.065536=3 +histogram.000000.065536.to.000000.131072=0 +histogram.000000.131072.to.000000.262144=0 +histogram.000000.262144.to.000000.524288=11 +histogram.000000.524288.to.000001.000000=0 +histogram.000001.000000.to.000002.000000=1 +histogram.000002.000000.to.000004.000000=0 +histogram.000004.000000.to.000008.000000=1 +histogram.000008.000000.to.000016.000000=0 +histogram.000016.000000.to.000032.000000=0 +histogram.000032.000000.to.000064.000000=0 +histogram.000064.000000.to.000128.000000=0 +histogram.000128.000000.to.000256.000000=0 +histogram.000256.000000.to.000512.000000=0 +histogram.000512.000000.to.001024.000000=0 +histogram.001024.000000.to.002048.000000=0 +histogram.002048.000000.to.004096.000000=0 +histogram.004096.000000.to.008192.000000=0 +histogram.008192.000000.to.016384.000000=0 +histogram.016384.000000.to.032768.000000=0 +histogram.032768.000000.to.065536.000000=0 +histogram.065536.000000.to.131072.000000=0 +histogram.131072.000000.to.262144.000000=0 +histogram.262144.000000.to.524288.000000=0 +num.query.type.A=90 +num.query.type.PTR=20 +num.query.type.MX=90 +num.query.type.AAAA=90 +num.query.class.IN=290 +num.query.opcode.QUERY=290 +num.query.tcp=0 +num.query.tcpout=0 +num.query.tls=0 +num.query.tls.resume=0 +num.query.ipv6=0 +num.query.flags.QR=0 +num.query.flags.AA=0 +num.query.flags.TC=0 +num.query.flags.RD=290 +num.query.flags.RA=0 +num.query.flags.Z=0 +num.query.flags.AD=0 +num.query.flags.CD=0 +num.query.edns.present=0 +num.query.edns.DO=0 +num.answer.rcode.NOERROR=274 +num.answer.rcode.FORMERR=0 +num.answer.rcode.SERVFAIL=0 +num.answer.rcode.NXDOMAIN=16 +num.answer.rcode.NOTIMPL=0 +num.answer.rcode.REFUSED=0 +num.query.ratelimited=0 +num.answer.secure=0 +num.answer.bogus=0 +num.rrset.bogus=0 +num.query.aggressive.NOERROR=1 +num.query.aggressive.NXDOMAIN=0 +unwanted.queries=0 +unwanted.replies=0 +msg.cache.count=94 +rrset.cache.count=304 +infra.cache.count=192 +key.cache.count=11 +dnscrypt_shared_secret.cache.count=0 +dnscrypt_nonce.cache.count=0 +num.query.dnscrypt.shared_secret.cachemiss=0 +num.query.dnscrypt.replay=0 +num.query.authzone.up=0 +num.query.authzone.down=0 +num.query.subnet=0 +num.query.subnet_cache=0 \ No newline at end of file diff --git a/modules/unbound/testdata/stats/lifecycle/cumulative/extended3.txt b/modules/unbound/testdata/stats/lifecycle/cumulative/extended3.txt new file mode 100644 index 000000000..f56482624 --- /dev/null +++ b/modules/unbound/testdata/stats/lifecycle/cumulative/extended3.txt @@ -0,0 +1,160 @@ +thread0.num.queries=165 +thread0.num.queries_ip_ratelimited=0 +thread0.num.cachehits=150 +thread0.num.cachemiss=15 +thread0.num.prefetch=0 +thread0.num.zero_ttl=0 +thread0.num.recursivereplies=15 +thread0.num.dnscrypt.crypted=0 +thread0.num.dnscrypt.cert=0 +thread0.num.dnscrypt.cleartext=0 +thread0.num.dnscrypt.malformed=0 +thread0.requestlist.avg=0.0666667 +thread0.requestlist.max=1 +thread0.requestlist.overwritten=0 +thread0.requestlist.exceeded=0 +thread0.requestlist.current.all=0 +thread0.requestlist.current.user=0 +thread0.recursion.time.avg=0.261497 +thread0.recursion.time.median=0.318318 +thread0.tcpusage=0 +thread1.num.queries=195 +thread1.num.queries_ip_ratelimited=0 +thread1.num.cachehits=184 +thread1.num.cachemiss=11 +thread1.num.prefetch=0 +thread1.num.zero_ttl=0 +thread1.num.recursivereplies=11 +thread1.num.dnscrypt.crypted=0 +thread1.num.dnscrypt.cert=0 +thread1.num.dnscrypt.cleartext=0 +thread1.num.dnscrypt.malformed=0 +thread1.requestlist.avg=0.363636 +thread1.requestlist.max=2 +thread1.requestlist.overwritten=0 +thread1.requestlist.exceeded=0 +thread1.requestlist.current.all=0 +thread1.requestlist.current.user=0 +thread1.recursion.time.avg=0.709047 +thread1.recursion.time.median=0.294912 +thread1.tcpusage=0 +total.num.queries=360 +total.num.queries_ip_ratelimited=0 +total.num.cachehits=334 +total.num.cachemiss=26 +total.num.prefetch=0 +total.num.zero_ttl=0 +total.num.recursivereplies=26 +total.num.dnscrypt.crypted=0 +total.num.dnscrypt.cert=0 +total.num.dnscrypt.cleartext=0 +total.num.dnscrypt.malformed=0 +total.requestlist.avg=0.192308 +total.requestlist.max=2 +total.requestlist.overwritten=0 +total.requestlist.exceeded=0 +total.requestlist.current.all=0 +total.requestlist.current.user=0 +total.recursion.time.avg=0.450844 +total.recursion.time.median=0.306615 +total.tcpusage=0 +time.now=1574103543.692653 +time.up=288.096493 +time.elapsed=82.531113 +mem.cache.rrset=208839 +mem.cache.message=101198 +mem.mod.iterator=16588 +mem.mod.validator=85725 +mem.mod.respip=0 +mem.mod.subnet=74504 +mem.cache.dnscrypt_shared_secret=0 +mem.cache.dnscrypt_nonce=0 +mem.streamwait=0 +histogram.000000.000000.to.000000.000001=0 +histogram.000000.000001.to.000000.000002=0 +histogram.000000.000002.to.000000.000004=0 +histogram.000000.000004.to.000000.000008=0 +histogram.000000.000008.to.000000.000016=0 +histogram.000000.000016.to.000000.000032=0 +histogram.000000.000032.to.000000.000064=0 +histogram.000000.000064.to.000000.000128=0 +histogram.000000.000128.to.000000.000256=0 +histogram.000000.000256.to.000000.000512=0 +histogram.000000.000512.to.000000.001024=0 +histogram.000000.001024.to.000000.002048=0 +histogram.000000.002048.to.000000.004096=0 +histogram.000000.004096.to.000000.008192=0 +histogram.000000.008192.to.000000.016384=2 +histogram.000000.016384.to.000000.032768=1 +histogram.000000.032768.to.000000.065536=5 +histogram.000000.065536.to.000000.131072=3 +histogram.000000.131072.to.000000.262144=0 +histogram.000000.262144.to.000000.524288=11 +histogram.000000.524288.to.000001.000000=2 +histogram.000001.000000.to.000002.000000=1 +histogram.000002.000000.to.000004.000000=0 +histogram.000004.000000.to.000008.000000=1 +histogram.000008.000000.to.000016.000000=0 +histogram.000016.000000.to.000032.000000=0 +histogram.000032.000000.to.000064.000000=0 +histogram.000064.000000.to.000128.000000=0 +histogram.000128.000000.to.000256.000000=0 +histogram.000256.000000.to.000512.000000=0 +histogram.000512.000000.to.001024.000000=0 +histogram.001024.000000.to.002048.000000=0 +histogram.002048.000000.to.004096.000000=0 +histogram.004096.000000.to.008192.000000=0 +histogram.008192.000000.to.016384.000000=0 +histogram.016384.000000.to.032768.000000=0 +histogram.032768.000000.to.065536.000000=0 +histogram.065536.000000.to.131072.000000=0 +histogram.131072.000000.to.262144.000000=0 +histogram.262144.000000.to.524288.000000=0 +num.query.type.A=120 +num.query.type.PTR=20 +num.query.type.MX=110 +num.query.type.AAAA=110 +num.query.class.IN=360 +num.query.opcode.QUERY=360 +num.query.tcp=0 +num.query.tcpout=0 +num.query.tls=0 +num.query.tls.resume=0 +num.query.ipv6=0 +num.query.flags.QR=0 +num.query.flags.AA=0 +num.query.flags.TC=0 +num.query.flags.RD=360 +num.query.flags.RA=0 +num.query.flags.Z=0 +num.query.flags.AD=0 +num.query.flags.CD=0 +num.query.edns.present=0 +num.query.edns.DO=0 +num.answer.rcode.NOERROR=334 +num.answer.rcode.FORMERR=0 +num.answer.rcode.SERVFAIL=10 +num.answer.rcode.NXDOMAIN=16 +num.answer.rcode.NOTIMPL=0 +num.answer.rcode.REFUSED=0 +num.answer.rcode.nodata=20 +num.query.ratelimited=0 +num.answer.secure=0 +num.answer.bogus=0 +num.rrset.bogus=0 +num.query.aggressive.NOERROR=1 +num.query.aggressive.NXDOMAIN=0 +unwanted.queries=0 +unwanted.replies=0 +msg.cache.count=119 +rrset.cache.count=401 +infra.cache.count=232 +key.cache.count=14 +dnscrypt_shared_secret.cache.count=0 +dnscrypt_nonce.cache.count=0 +num.query.dnscrypt.shared_secret.cachemiss=0 +num.query.dnscrypt.replay=0 +num.query.authzone.up=0 +num.query.authzone.down=0 +num.query.subnet=0 +num.query.subnet_cache=0 \ No newline at end of file diff --git a/modules/unbound/testdata/stats/lifecycle/reset/extended1.txt b/modules/unbound/testdata/stats/lifecycle/reset/extended1.txt new file mode 100644 index 000000000..0d64201b8 --- /dev/null +++ b/modules/unbound/testdata/stats/lifecycle/reset/extended1.txt @@ -0,0 +1,160 @@ +thread0.num.queries=51 +thread0.num.queries_ip_ratelimited=0 +thread0.num.cachehits=44 +thread0.num.cachemiss=7 +thread0.num.prefetch=0 +thread0.num.zero_ttl=0 +thread0.num.recursivereplies=7 +thread0.num.dnscrypt.crypted=0 +thread0.num.dnscrypt.cert=0 +thread0.num.dnscrypt.cleartext=0 +thread0.num.dnscrypt.malformed=0 +thread0.requestlist.avg=0 +thread0.requestlist.max=0 +thread0.requestlist.overwritten=0 +thread0.requestlist.exceeded=0 +thread0.requestlist.current.all=0 +thread0.requestlist.current.user=0 +thread0.recursion.time.avg=0.365956 +thread0.recursion.time.median=0.057344 +thread0.tcpusage=0 +thread1.num.queries=49 +thread1.num.queries_ip_ratelimited=0 +thread1.num.cachehits=46 +thread1.num.cachemiss=3 +thread1.num.prefetch=0 +thread1.num.zero_ttl=0 +thread1.num.recursivereplies=3 +thread1.num.dnscrypt.crypted=0 +thread1.num.dnscrypt.cert=0 +thread1.num.dnscrypt.cleartext=0 +thread1.num.dnscrypt.malformed=0 +thread1.requestlist.avg=0 +thread1.requestlist.max=0 +thread1.requestlist.overwritten=0 +thread1.requestlist.exceeded=0 +thread1.requestlist.current.all=0 +thread1.requestlist.current.user=0 +thread1.recursion.time.avg=1.582766 +thread1.recursion.time.median=0 +thread1.tcpusage=0 +total.num.queries=100 +total.num.queries_ip_ratelimited=0 +total.num.cachehits=90 +total.num.cachemiss=10 +total.num.prefetch=0 +total.num.zero_ttl=0 +total.num.recursivereplies=10 +total.num.dnscrypt.crypted=0 +total.num.dnscrypt.cert=0 +total.num.dnscrypt.cleartext=0 +total.num.dnscrypt.malformed=0 +total.requestlist.avg=0 +total.requestlist.max=0 +total.requestlist.overwritten=0 +total.requestlist.exceeded=0 +total.requestlist.current.all=0 +total.requestlist.current.user=0 +total.recursion.time.avg=0.730999 +total.recursion.time.median=0.028672 +total.tcpusage=0 +time.now=1574103644.993894 +time.up=45.285130 +time.elapsed=45.285130 +mem.cache.rrset=172757 +mem.cache.message=86064 +mem.mod.iterator=16588 +mem.mod.validator=79979 +mem.mod.respip=0 +mem.mod.subnet=74504 +mem.cache.dnscrypt_shared_secret=0 +mem.cache.dnscrypt_nonce=0 +mem.streamwait=0 +histogram.000000.000000.to.000000.000001=0 +histogram.000000.000001.to.000000.000002=0 +histogram.000000.000002.to.000000.000004=0 +histogram.000000.000004.to.000000.000008=0 +histogram.000000.000008.to.000000.000016=0 +histogram.000000.000016.to.000000.000032=0 +histogram.000000.000032.to.000000.000064=0 +histogram.000000.000064.to.000000.000128=0 +histogram.000000.000128.to.000000.000256=0 +histogram.000000.000256.to.000000.000512=0 +histogram.000000.000512.to.000000.001024=0 +histogram.000000.001024.to.000000.002048=0 +histogram.000000.002048.to.000000.004096=0 +histogram.000000.004096.to.000000.008192=0 +histogram.000000.008192.to.000000.016384=0 +histogram.000000.016384.to.000000.032768=2 +histogram.000000.032768.to.000000.065536=3 +histogram.000000.065536.to.000000.131072=1 +histogram.000000.131072.to.000000.262144=1 +histogram.000000.262144.to.000000.524288=1 +histogram.000000.524288.to.000001.000000=0 +histogram.000001.000000.to.000002.000000=1 +histogram.000002.000000.to.000004.000000=0 +histogram.000004.000000.to.000008.000000=1 +histogram.000008.000000.to.000016.000000=0 +histogram.000016.000000.to.000032.000000=0 +histogram.000032.000000.to.000064.000000=0 +histogram.000064.000000.to.000128.000000=0 +histogram.000128.000000.to.000256.000000=0 +histogram.000256.000000.to.000512.000000=0 +histogram.000512.000000.to.001024.000000=0 +histogram.001024.000000.to.002048.000000=0 +histogram.002048.000000.to.004096.000000=0 +histogram.004096.000000.to.008192.000000=0 +histogram.008192.000000.to.016384.000000=0 +histogram.016384.000000.to.032768.000000=0 +histogram.032768.000000.to.065536.000000=0 +histogram.065536.000000.to.131072.000000=0 +histogram.131072.000000.to.262144.000000=0 +histogram.262144.000000.to.524288.000000=0 +num.query.type.A=30 +num.query.type.PTR=10 +num.query.type.MX=30 +num.query.type.AAAA=30 +num.query.class.IN=100 +num.query.opcode.QUERY=100 +num.query.tcp=0 +num.query.tcpout=1 +num.query.tls=0 +num.query.tls.resume=0 +num.query.ipv6=0 +num.query.flags.QR=0 +num.query.flags.AA=0 +num.query.flags.TC=0 +num.query.flags.RD=100 +num.query.flags.RA=0 +num.query.flags.Z=0 +num.query.flags.AD=0 +num.query.flags.CD=0 +num.query.edns.present=0 +num.query.edns.DO=0 +num.answer.rcode.NOERROR=90 +num.answer.rcode.FORMERR=0 +num.answer.rcode.SERVFAIL=0 +num.answer.rcode.NXDOMAIN=10 +num.answer.rcode.NOTIMPL=0 +num.answer.rcode.REFUSED=0 +num.answer.rcode.nodata=10 +num.query.ratelimited=0 +num.answer.secure=0 +num.answer.bogus=0 +num.rrset.bogus=0 +num.query.aggressive.NOERROR=2 +num.query.aggressive.NXDOMAIN=0 +unwanted.queries=0 +unwanted.replies=0 +msg.cache.count=67 +rrset.cache.count=303 +infra.cache.count=181 +key.cache.count=10 +dnscrypt_shared_secret.cache.count=0 +dnscrypt_nonce.cache.count=0 +num.query.dnscrypt.shared_secret.cachemiss=0 +num.query.dnscrypt.replay=0 +num.query.authzone.up=0 +num.query.authzone.down=0 +num.query.subnet=0 +num.query.subnet_cache=0 \ No newline at end of file diff --git a/modules/unbound/testdata/stats/lifecycle/reset/extended2.txt b/modules/unbound/testdata/stats/lifecycle/reset/extended2.txt new file mode 100644 index 000000000..1cab37313 --- /dev/null +++ b/modules/unbound/testdata/stats/lifecycle/reset/extended2.txt @@ -0,0 +1,153 @@ +thread0.num.queries=0 +thread0.num.queries_ip_ratelimited=0 +thread0.num.cachehits=0 +thread0.num.cachemiss=0 +thread0.num.prefetch=0 +thread0.num.zero_ttl=0 +thread0.num.recursivereplies=0 +thread0.num.dnscrypt.crypted=0 +thread0.num.dnscrypt.cert=0 +thread0.num.dnscrypt.cleartext=0 +thread0.num.dnscrypt.malformed=0 +thread0.requestlist.avg=0 +thread0.requestlist.max=0 +thread0.requestlist.overwritten=0 +thread0.requestlist.exceeded=0 +thread0.requestlist.current.all=0 +thread0.requestlist.current.user=0 +thread0.recursion.time.avg=0.000000 +thread0.recursion.time.median=0 +thread0.tcpusage=0 +thread1.num.queries=0 +thread1.num.queries_ip_ratelimited=0 +thread1.num.cachehits=0 +thread1.num.cachemiss=0 +thread1.num.prefetch=0 +thread1.num.zero_ttl=0 +thread1.num.recursivereplies=0 +thread1.num.dnscrypt.crypted=0 +thread1.num.dnscrypt.cert=0 +thread1.num.dnscrypt.cleartext=0 +thread1.num.dnscrypt.malformed=0 +thread1.requestlist.avg=0 +thread1.requestlist.max=0 +thread1.requestlist.overwritten=0 +thread1.requestlist.exceeded=0 +thread1.requestlist.current.all=0 +thread1.requestlist.current.user=0 +thread1.recursion.time.avg=0.000000 +thread1.recursion.time.median=0 +thread1.tcpusage=0 +total.num.queries=0 +total.num.queries_ip_ratelimited=0 +total.num.cachehits=0 +total.num.cachemiss=0 +total.num.prefetch=0 +total.num.zero_ttl=0 +total.num.recursivereplies=0 +total.num.dnscrypt.crypted=0 +total.num.dnscrypt.cert=0 +total.num.dnscrypt.cleartext=0 +total.num.dnscrypt.malformed=0 +total.requestlist.avg=0 +total.requestlist.max=0 +total.requestlist.overwritten=0 +total.requestlist.exceeded=0 +total.requestlist.current.all=0 +total.requestlist.current.user=0 +total.recursion.time.avg=0.000000 +total.recursion.time.median=0 +total.tcpusage=0 +time.now=1574103671.543847 +time.up=71.835083 +time.elapsed=26.549953 +mem.cache.rrset=172757 +mem.cache.message=86064 +mem.mod.iterator=16588 +mem.mod.validator=79979 +mem.mod.respip=0 +mem.mod.subnet=74504 +mem.cache.dnscrypt_shared_secret=0 +mem.cache.dnscrypt_nonce=0 +mem.streamwait=0 +histogram.000000.000000.to.000000.000001=0 +histogram.000000.000001.to.000000.000002=0 +histogram.000000.000002.to.000000.000004=0 +histogram.000000.000004.to.000000.000008=0 +histogram.000000.000008.to.000000.000016=0 +histogram.000000.000016.to.000000.000032=0 +histogram.000000.000032.to.000000.000064=0 +histogram.000000.000064.to.000000.000128=0 +histogram.000000.000128.to.000000.000256=0 +histogram.000000.000256.to.000000.000512=0 +histogram.000000.000512.to.000000.001024=0 +histogram.000000.001024.to.000000.002048=0 +histogram.000000.002048.to.000000.004096=0 +histogram.000000.004096.to.000000.008192=0 +histogram.000000.008192.to.000000.016384=0 +histogram.000000.016384.to.000000.032768=0 +histogram.000000.032768.to.000000.065536=0 +histogram.000000.065536.to.000000.131072=0 +histogram.000000.131072.to.000000.262144=0 +histogram.000000.262144.to.000000.524288=0 +histogram.000000.524288.to.000001.000000=0 +histogram.000001.000000.to.000002.000000=0 +histogram.000002.000000.to.000004.000000=0 +histogram.000004.000000.to.000008.000000=0 +histogram.000008.000000.to.000016.000000=0 +histogram.000016.000000.to.000032.000000=0 +histogram.000032.000000.to.000064.000000=0 +histogram.000064.000000.to.000128.000000=0 +histogram.000128.000000.to.000256.000000=0 +histogram.000256.000000.to.000512.000000=0 +histogram.000512.000000.to.001024.000000=0 +histogram.001024.000000.to.002048.000000=0 +histogram.002048.000000.to.004096.000000=0 +histogram.004096.000000.to.008192.000000=0 +histogram.008192.000000.to.016384.000000=0 +histogram.016384.000000.to.032768.000000=0 +histogram.032768.000000.to.065536.000000=0 +histogram.065536.000000.to.131072.000000=0 +histogram.131072.000000.to.262144.000000=0 +histogram.262144.000000.to.524288.000000=0 +num.query.tcp=0 +num.query.tcpout=0 +num.query.tls=0 +num.query.tls.resume=0 +num.query.ipv6=0 +num.query.flags.QR=0 +num.query.flags.AA=0 +num.query.flags.TC=0 +num.query.flags.RD=0 +num.query.flags.RA=0 +num.query.flags.Z=0 +num.query.flags.AD=0 +num.query.flags.CD=0 +num.query.edns.present=0 +num.query.edns.DO=0 +num.answer.rcode.NOERROR=0 +num.answer.rcode.FORMERR=0 +num.answer.rcode.SERVFAIL=0 +num.answer.rcode.NXDOMAIN=0 +num.answer.rcode.NOTIMPL=0 +num.answer.rcode.REFUSED=0 +num.query.ratelimited=0 +num.answer.secure=0 +num.answer.bogus=0 +num.rrset.bogus=0 +num.query.aggressive.NOERROR=0 +num.query.aggressive.NXDOMAIN=0 +unwanted.queries=0 +unwanted.replies=0 +msg.cache.count=67 +rrset.cache.count=303 +infra.cache.count=181 +key.cache.count=10 +dnscrypt_shared_secret.cache.count=0 +dnscrypt_nonce.cache.count=0 +num.query.dnscrypt.shared_secret.cachemiss=0 +num.query.dnscrypt.replay=0 +num.query.authzone.up=0 +num.query.authzone.down=0 +num.query.subnet=0 +num.query.subnet_cache=0 \ No newline at end of file diff --git a/modules/unbound/testdata/stats/lifecycle/reset/extended3.txt b/modules/unbound/testdata/stats/lifecycle/reset/extended3.txt new file mode 100644 index 000000000..136e6b8b1 --- /dev/null +++ b/modules/unbound/testdata/stats/lifecycle/reset/extended3.txt @@ -0,0 +1,160 @@ +thread0.num.queries=34 +thread0.num.queries_ip_ratelimited=0 +thread0.num.cachehits=30 +thread0.num.cachemiss=4 +thread0.num.prefetch=0 +thread0.num.zero_ttl=0 +thread0.num.recursivereplies=4 +thread0.num.dnscrypt.crypted=0 +thread0.num.dnscrypt.cert=0 +thread0.num.dnscrypt.cleartext=0 +thread0.num.dnscrypt.malformed=0 +thread0.requestlist.avg=0 +thread0.requestlist.max=0 +thread0.requestlist.overwritten=0 +thread0.requestlist.exceeded=0 +thread0.requestlist.current.all=0 +thread0.requestlist.current.user=0 +thread0.recursion.time.avg=0.541654 +thread0.recursion.time.median=0.098304 +thread0.tcpusage=0 +thread1.num.queries=36 +thread1.num.queries_ip_ratelimited=0 +thread1.num.cachehits=33 +thread1.num.cachemiss=3 +thread1.num.prefetch=0 +thread1.num.zero_ttl=0 +thread1.num.recursivereplies=3 +thread1.num.dnscrypt.crypted=0 +thread1.num.dnscrypt.cert=0 +thread1.num.dnscrypt.cleartext=0 +thread1.num.dnscrypt.malformed=0 +thread1.requestlist.avg=1.66667 +thread1.requestlist.max=5 +thread1.requestlist.overwritten=0 +thread1.requestlist.exceeded=0 +thread1.requestlist.current.all=0 +thread1.requestlist.current.user=0 +thread1.recursion.time.avg=0.062328 +thread1.recursion.time.median=0 +thread1.tcpusage=0 +total.num.queries=70 +total.num.queries_ip_ratelimited=0 +total.num.cachehits=63 +total.num.cachemiss=7 +total.num.prefetch=0 +total.num.zero_ttl=0 +total.num.recursivereplies=7 +total.num.dnscrypt.crypted=0 +total.num.dnscrypt.cert=0 +total.num.dnscrypt.cleartext=0 +total.num.dnscrypt.malformed=0 +total.requestlist.avg=0.714286 +total.requestlist.max=5 +total.requestlist.overwritten=0 +total.requestlist.exceeded=0 +total.requestlist.current.all=0 +total.requestlist.current.user=0 +total.recursion.time.avg=0.336228 +total.recursion.time.median=0.049152 +total.tcpusage=0 +time.now=1574103731.371896 +time.up=131.663132 +time.elapsed=59.828049 +mem.cache.rrset=235917 +mem.cache.message=105471 +mem.mod.iterator=16588 +mem.mod.validator=87270 +mem.mod.respip=0 +mem.mod.subnet=74504 +mem.cache.dnscrypt_shared_secret=0 +mem.cache.dnscrypt_nonce=0 +mem.streamwait=0 +histogram.000000.000000.to.000000.000001=0 +histogram.000000.000001.to.000000.000002=0 +histogram.000000.000002.to.000000.000004=0 +histogram.000000.000004.to.000000.000008=0 +histogram.000000.000008.to.000000.000016=0 +histogram.000000.000016.to.000000.000032=0 +histogram.000000.000032.to.000000.000064=0 +histogram.000000.000064.to.000000.000128=0 +histogram.000000.000128.to.000000.000256=0 +histogram.000000.000256.to.000000.000512=0 +histogram.000000.000512.to.000000.001024=0 +histogram.000000.001024.to.000000.002048=0 +histogram.000000.002048.to.000000.004096=0 +histogram.000000.004096.to.000000.008192=0 +histogram.000000.008192.to.000000.016384=0 +histogram.000000.016384.to.000000.032768=2 +histogram.000000.032768.to.000000.065536=1 +histogram.000000.065536.to.000000.131072=3 +histogram.000000.131072.to.000000.262144=0 +histogram.000000.262144.to.000000.524288=0 +histogram.000000.524288.to.000001.000000=0 +histogram.000001.000000.to.000002.000000=1 +histogram.000002.000000.to.000004.000000=0 +histogram.000004.000000.to.000008.000000=0 +histogram.000008.000000.to.000016.000000=0 +histogram.000016.000000.to.000032.000000=0 +histogram.000032.000000.to.000064.000000=0 +histogram.000064.000000.to.000128.000000=0 +histogram.000128.000000.to.000256.000000=0 +histogram.000256.000000.to.000512.000000=0 +histogram.000512.000000.to.001024.000000=0 +histogram.001024.000000.to.002048.000000=0 +histogram.002048.000000.to.004096.000000=0 +histogram.004096.000000.to.008192.000000=0 +histogram.008192.000000.to.016384.000000=0 +histogram.016384.000000.to.032768.000000=0 +histogram.032768.000000.to.065536.000000=0 +histogram.065536.000000.to.131072.000000=0 +histogram.131072.000000.to.262144.000000=0 +histogram.262144.000000.to.524288.000000=0 +num.query.type.A=20 +num.query.type.PTR=10 +num.query.type.MX=20 +num.query.type.AAAA=20 +num.query.class.IN=70 +num.query.opcode.QUERY=70 +num.query.tcp=0 +num.query.tcpout=0 +num.query.tls=0 +num.query.tls.resume=0 +num.query.ipv6=0 +num.query.flags.QR=0 +num.query.flags.AA=0 +num.query.flags.TC=0 +num.query.flags.RD=70 +num.query.flags.RA=0 +num.query.flags.Z=0 +num.query.flags.AD=0 +num.query.flags.CD=0 +num.query.edns.present=0 +num.query.edns.DO=0 +num.answer.rcode.NOERROR=60 +num.answer.rcode.FORMERR=0 +num.answer.rcode.SERVFAIL=0 +num.answer.rcode.NXDOMAIN=10 +num.answer.rcode.NOTIMPL=0 +num.answer.rcode.REFUSED=0 +num.answer.rcode.nodata=10 +num.query.ratelimited=0 +num.answer.secure=0 +num.answer.bogus=0 +num.rrset.bogus=0 +num.query.aggressive.NOERROR=2 +num.query.aggressive.NXDOMAIN=0 +unwanted.queries=0 +unwanted.replies=0 +msg.cache.count=127 +rrset.cache.count=501 +infra.cache.count=303 +key.cache.count=15 +dnscrypt_shared_secret.cache.count=0 +dnscrypt_nonce.cache.count=0 +num.query.dnscrypt.shared_secret.cachemiss=0 +num.query.dnscrypt.replay=0 +num.query.authzone.up=0 +num.query.authzone.down=0 +num.query.subnet=0 +num.query.subnet_cache=0 \ No newline at end of file diff --git a/modules/unbound/testdata/unbound.conf b/modules/unbound/testdata/unbound.conf new file mode 100644 index 000000000..a061a3476 --- /dev/null +++ b/modules/unbound/testdata/unbound.conf @@ -0,0 +1,85 @@ +# +# Example configuration file. +# +# See unbound.conf(5) man page, version 1.9.4. +# +# this is a comment. + +#Use this to include other text into the file. +#include: "otherfile.conf" + +# The server clause sets the main parameters. +server: + # whitespace is not necessary, but looks cleaner. + + # verbosity number, 0 is least verbose. 1 is default. + # verbosity: 1 + + # print statistics to the log (for every thread) every N seconds. + # Set to "" or 0 to disable. Default is disabled. + # statistics-interval: 0 + + # enable shm for stats, default no. if you enable also enable + # statistics-interval, every time it also writes stats to the + # shared memory segment keyed with shm-key. + # shm-enable: no + + # shm for stats uses this key, and key+1 for the shared mem segment. + # shm-key: 11777 + + # enable cumulative statistics, without clearing them after printing. + # statistics-cumulative: no + statistics-cumulative: yes + + # enable extended statistics (query types, answer codes, status) + # printed from unbound-control. default off, because of speed. + # extended-statistics: no + # extended-statistics: yes + + # number of threads to create. 1 disables threading. + # num-threads: 2 + +# Python config section. To enable: +# o use --with-pythonmodule to configure before compiling. +# o list python in the module-config string (above) to enable. +# It can be at the start, it gets validated results, or just before +# the iterator and process before DNSSEC validation. +# o and give a python-script to run. +python: + # Script file to load + # python-script: "/etc/unbound/ubmodule-tst.py" + +# Remote control config section. +remote-control: + # Enable remote control with unbound-control(8) here. + # set up the keys and certificates with unbound-control-setup. + control-enable: yes + + # what interfaces are listened to for remote control. + # give 0.0.0.0 and ::0 to listen to all interfaces. + # set to an absolute path to use a unix local name pipe, certificates + # are not used for that, so key and cert files need not be present. + # control-interface: 127.0.0.1 + control-interface: 10.0.0.1 + # control-interface: ::1 + # control-interface: /var/run/test.sock + + # port number for remote control operations. + control-port: 8954 + + # for localhost, you can disable use of TLS by setting this to "no" + # For local sockets this option is ignored, and TLS is not used. + # control-use-cert: "yes" + control-use-cert: "no" + + # unbound server key file. + # server-key-file: "/etc/unbound/unbound_server.key" + + # unbound server certificate file. + # server-cert-file: "/etc/unbound/unbound_server.pem" + + # unbound-control key file. + control-key-file: "/etc/unbound/unbound_control_other.key" + + # unbound-control certificate file. + control-cert-file: "/etc/unbound/unbound_control_other.pem" diff --git a/modules/unbound/testdata/unbound_disabled.conf b/modules/unbound/testdata/unbound_disabled.conf new file mode 100644 index 000000000..1cef549f8 --- /dev/null +++ b/modules/unbound/testdata/unbound_disabled.conf @@ -0,0 +1,85 @@ +# +# Example configuration file. +# +# See unbound.conf(5) man page, version 1.9.4. +# +# this is a comment. + +#Use this to include other text into the file. +#include: "otherfile.conf" + +# The server clause sets the main parameters. +server: + # whitespace is not necessary, but looks cleaner. + + # verbosity number, 0 is least verbose. 1 is default. + # verbosity: 1 + + # print statistics to the log (for every thread) every N seconds. + # Set to "" or 0 to disable. Default is disabled. + # statistics-interval: 0 + + # enable shm for stats, default no. if you enable also enable + # statistics-interval, every time it also writes stats to the + # shared memory segment keyed with shm-key. + # shm-enable: no + + # shm for stats uses this key, and key+1 for the shared mem segment. + # shm-key: 11777 + + # enable cumulative statistics, without clearing them after printing. + # statistics-cumulative: no + statistics-cumulative: yes + + # enable extended statistics (query types, answer codes, status) + # printed from unbound-control. default off, because of speed. + # extended-statistics: no + # extended-statistics: yes + + # number of threads to create. 1 disables threading. + # num-threads: 2 + +# Python config section. To enable: +# o use --with-pythonmodule to configure before compiling. +# o list python in the module-config string (above) to enable. +# It can be at the start, it gets validated results, or just before +# the iterator and process before DNSSEC validation. +# o and give a python-script to run. +python: + # Script file to load + # python-script: "/etc/unbound/ubmodule-tst.py" + +# Remote control config section. +remote-control: + # Enable remote control with unbound-control(8) here. + # set up the keys and certificates with unbound-control-setup. + control-enable: no + + # what interfaces are listened to for remote control. + # give 0.0.0.0 and ::0 to listen to all interfaces. + # set to an absolute path to use a unix local name pipe, certificates + # are not used for that, so key and cert files need not be present. + # control-interface: 127.0.0.1 + control-interface: 0.0.0.0 + # control-interface: ::1 + # control-interface: /var/run/test.sock + + # port number for remote control operations. + control-port: 8953 + + # for localhost, you can disable use of TLS by setting this to "no" + # For local sockets this option is ignored, and TLS is not used. + # control-use-cert: "yes" + control-use-cert: "yes" + + # unbound server key file. + # server-key-file: "/etc/unbound/unbound_server.key" + + # unbound server certificate file. + # server-cert-file: "/etc/unbound/unbound_server.pem" + + # unbound-control key file. + control-key-file: "/etc/unbound/unbound_control.key" + + # unbound-control certificate file. + control-cert-file: "/etc/unbound/unbound_control.pem" diff --git a/modules/unbound/testdata/unbound_empty.conf b/modules/unbound/testdata/unbound_empty.conf new file mode 100644 index 000000000..a2d158376 --- /dev/null +++ b/modules/unbound/testdata/unbound_empty.conf @@ -0,0 +1,85 @@ +# +# Example configuration file. +# +# See unbound.conf(5) man page, version 1.9.4. +# +# this is a comment. + +#Use this to include other text into the file. +#include: "otherfile.conf" + +# The server clause sets the main parameters. +server: + # whitespace is not necessary, but looks cleaner. + + # verbosity number, 0 is least verbose. 1 is default. + # verbosity: 1 + + # print statistics to the log (for every thread) every N seconds. + # Set to "" or 0 to disable. Default is disabled. + # statistics-interval: 0 + + # enable shm for stats, default no. if you enable also enable + # statistics-interval, every time it also writes stats to the + # shared memory segment keyed with shm-key. + # shm-enable: no + + # shm for stats uses this key, and key+1 for the shared mem segment. + # shm-key: 11777 + + # enable cumulative statistics, without clearing them after printing. + # statistics-cumulative: no + # statistics-cumulative: yes + + # enable extended statistics (query types, answer codes, status) + # printed from unbound-control. default off, because of speed. + # extended-statistics: no + # extended-statistics: yes + + # number of threads to create. 1 disables threading. + # num-threads: 2 + +# Python config section. To enable: +# o use --with-pythonmodule to configure before compiling. +# o list python in the module-config string (above) to enable. +# It can be at the start, it gets validated results, or just before +# the iterator and process before DNSSEC validation. +# o and give a python-script to run. +python: + # Script file to load + # python-script: "/etc/unbound/ubmodule-tst.py" + +# Remote control config section. +remote-control: + # Enable remote control with unbound-control(8) here. + # set up the keys and certificates with unbound-control-setup. + # control-enable: no + + # what interfaces are listened to for remote control. + # give 0.0.0.0 and ::0 to listen to all interfaces. + # set to an absolute path to use a unix local name pipe, certificates + # are not used for that, so key and cert files need not be present. + # control-interface: 127.0.0.1 + # control-interface: 0.0.0.0 + # control-interface: ::1 + # control-interface: /var/run/test.sock + + # port number for remote control operations. + # control-port: 8953 + + # for localhost, you can disable use of TLS by setting this to "no" + # For local sockets this option is ignored, and TLS is not used. + # control-use-cert: "yes" + # control-use-cert: "yes" + + # unbound server key file. + # server-key-file: "/etc/unbound/unbound_server.key" + + # unbound server certificate file. + # server-cert-file: "/etc/unbound/unbound_server.pem" + + # unbound-control key file. + # control-key-file: "/etc/unbound/unbound_control.key" + + # unbound-control certificate file. + # control-cert-file: "/etc/unbound/unbound_control.pem" diff --git a/modules/unbound/unbound.go b/modules/unbound/unbound.go new file mode 100644 index 000000000..b1f791736 --- /dev/null +++ b/modules/unbound/unbound.go @@ -0,0 +1,107 @@ +package unbound + +import ( + "time" + + "github.com/netdata/go.d.plugin/pkg/web" + + "github.com/netdata/go-orchestrator/module" +) + +func init() { + creator := module.Creator{ + Create: func() module.Module { return New() }, + } + + module.Register("unbound", creator) +} + +func New() *Unbound { + config := Config{ + Address: "127.0.0.1:8953", + ConfPath: "/etc/unbound/unbound.conf", + Timeout: web.Duration{Duration: time.Second}, + Cumulative: false, + UseTLS: true, + ClientTLSConfig: web.ClientTLSConfig{ + TLSCert: "/etc/unbound/unbound_control.pem", + TLSKey: "/etc/unbound/unbound_control.key", + InsecureSkipVerify: true, + }, + } + + return &Unbound{ + Config: config, + curCache: newCollectCache(), + cache: newCollectCache(), + } +} + +type unboundClient interface { + send(command string) ([]string, error) +} + +type ( + Config struct { + Address string `yaml:"address"` + ConfPath string `yaml:"conf_path"` + Timeout web.Duration `yaml:"timeout"` + Cumulative bool `yaml:"cumulative_stats"` + UseTLS bool `yaml:"use_tls"` + web.ClientTLSConfig `yaml:",inline"` + } + Unbound struct { + module.Base + Config `yaml:",inline"` + + client unboundClient + cache collectCache + curCache collectCache + + prevCacheMiss float64 // needed for cumulative mode + extChartsCreated bool + + charts *module.Charts + } +) + +func (Unbound) Cleanup() {} + +func (u *Unbound) Init() bool { + if enabled := u.initConfig(); !enabled { + return false + } + + if err := u.initClient(); err != nil { + u.Errorf("creating client: %v", err) + return false + } + + u.charts = charts(u.Cumulative) + + u.Debugf("using address: %s, cumulative: %v, use_tls: %v, timeout: %s", u.Address, u.Cumulative, u.UseTLS, u.Timeout) + if u.UseTLS { + u.Debugf("using tls_skip_verify: %v, tls_key: %s, tls_cert: %s", u.InsecureSkipVerify, u.TLSKey, u.TLSCert) + } + return true +} + +func (u *Unbound) Check() bool { + return len(u.Collect()) > 0 +} + +func (u Unbound) Charts() *module.Charts { + return u.charts +} + +func (u *Unbound) Collect() map[string]int64 { + mx, err := u.collect() + if err != nil { + u.Error(err) + } + + if len(mx) == 0 { + return nil + } + return mx +} diff --git a/modules/unbound/unbound_test.go b/modules/unbound/unbound_test.go new file mode 100644 index 000000000..fb92c8a9b --- /dev/null +++ b/modules/unbound/unbound_test.go @@ -0,0 +1,1217 @@ +package unbound + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "io/ioutil" + "strings" + "testing" + + "github.com/netdata/go.d.plugin/pkg/web" + + "github.com/netdata/go-orchestrator/module" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + commonStatsData, _ = ioutil.ReadFile("testdata/stats/common.txt") + extStatsData, _ = ioutil.ReadFile("testdata/stats/extended.txt") + lifeCycleCumulativeData1, _ = ioutil.ReadFile("testdata/stats/lifecycle/cumulative/extended1.txt") + lifeCycleCumulativeData2, _ = ioutil.ReadFile("testdata/stats/lifecycle/cumulative/extended2.txt") + lifeCycleCumulativeData3, _ = ioutil.ReadFile("testdata/stats/lifecycle/cumulative/extended3.txt") + lifeCycleResetData1, _ = ioutil.ReadFile("testdata/stats/lifecycle/reset/extended1.txt") + lifeCycleResetData2, _ = ioutil.ReadFile("testdata/stats/lifecycle/reset/extended2.txt") + lifeCycleResetData3, _ = ioutil.ReadFile("testdata/stats/lifecycle/reset/extended3.txt") +) + +func Test_readTestData(t *testing.T) { + assert.NotNil(t, commonStatsData) + assert.NotNil(t, extStatsData) + assert.NotNil(t, lifeCycleCumulativeData1) + assert.NotNil(t, lifeCycleCumulativeData2) + assert.NotNil(t, lifeCycleCumulativeData3) + assert.NotNil(t, lifeCycleResetData1) + assert.NotNil(t, lifeCycleResetData2) + assert.NotNil(t, lifeCycleResetData3) +} + +func nonTLSUnbound() *Unbound { unbound := New(); unbound.UseTLS = false; return unbound } + +func TestNew(t *testing.T) { + assert.Implements(t, (*module.Module)(nil), New()) +} + +func TestUnbound_Init(t *testing.T) { + unbound := nonTLSUnbound() + unbound.ConfPath = "" + + assert.True(t, unbound.Init()) +} + +func TestUnbound_Init_SetEverythingFromUnboundConf(t *testing.T) { + unbound := New() + unbound.ConfPath = "testdata/unbound.conf" + expectedConfig := Config{ + Address: "10.0.0.1:8954", + ConfPath: unbound.ConfPath, + Timeout: unbound.Timeout, + Cumulative: true, + UseTLS: false, + ClientTLSConfig: web.ClientTLSConfig{ + TLSCert: "/etc/unbound/unbound_control_other.pem", + TLSKey: "/etc/unbound/unbound_control_other.key", + InsecureSkipVerify: unbound.InsecureSkipVerify, + }, + } + + assert.True(t, unbound.Init()) + assert.Equal(t, expectedConfig, unbound.Config) +} + +func TestUnbound_Init_DisabledInUnboundConf(t *testing.T) { + unbound := nonTLSUnbound() + unbound.ConfPath = "testdata/unbound_disabled.conf" + + assert.False(t, unbound.Init()) +} + +func TestUnbound_Init_HandleEmptyConfig(t *testing.T) { + unbound := nonTLSUnbound() + unbound.ConfPath = "testdata/unbound_empty.conf" + + assert.True(t, unbound.Init()) +} + +func TestUnbound_Init_HandleNonExistentConfig(t *testing.T) { + unbound := nonTLSUnbound() + unbound.ConfPath = "testdata/unbound_non_existent.conf" + + assert.True(t, unbound.Init()) +} + +func TestUnbound_Check(t *testing.T) { + unbound := nonTLSUnbound() + require.True(t, unbound.Init()) + unbound.client = mockUnboundClient{data: commonStatsData, err: false} + + assert.True(t, unbound.Check()) +} + +func TestUnbound_Check_ErrorDuringScrapingUnbound(t *testing.T) { + unbound := nonTLSUnbound() + require.True(t, unbound.Init()) + unbound.client = mockUnboundClient{err: true} + + assert.False(t, unbound.Check()) +} + +func TestUnbound_Cleanup(t *testing.T) { + New().Cleanup() +} + +func TestUnbound_Charts(t *testing.T) { + unbound := nonTLSUnbound() + require.True(t, unbound.Init()) + + assert.NotNil(t, unbound.Charts()) +} + +func TestUnbound_Collect(t *testing.T) { + unbound := nonTLSUnbound() + require.True(t, unbound.Init()) + unbound.client = mockUnboundClient{data: commonStatsData, err: false} + + assert.Equal(t, expectedCommon, unbound.Collect()) + testCharts(t, unbound) +} + +func TestUnbound_Collect_ExtendedStats(t *testing.T) { + unbound := nonTLSUnbound() + require.True(t, unbound.Init()) + unbound.client = mockUnboundClient{data: extStatsData, err: false} + + assert.Equal(t, expectedExtended, unbound.Collect()) + testCharts(t, unbound) +} + +func TestUnbound_Collect_LifeCycleCumulativeExtendedStats(t *testing.T) { + tests := []struct { + input []byte + expected map[string]int64 + }{ + {input: lifeCycleCumulativeData1, expected: expectedCumulative1}, + {input: lifeCycleCumulativeData2, expected: expectedCumulative2}, + {input: lifeCycleCumulativeData3, expected: expectedCumulative3}, + } + + unbound := nonTLSUnbound() + unbound.Cumulative = true + require.True(t, unbound.Init()) + ubClient := &mockUnboundClient{err: false} + unbound.client = ubClient + + for i, test := range tests { + t.Run(fmt.Sprintf("run %d", i+1), func(t *testing.T) { + ubClient.data = test.input + assert.Equal(t, test.expected, unbound.Collect()) + }) + } + + testCharts(t, unbound) +} + +func TestUnbound_Collect_LifeCycleResetExtendedStats(t *testing.T) { + tests := []struct { + input []byte + expected map[string]int64 + }{ + {input: lifeCycleResetData1, expected: expectedReset1}, + {input: lifeCycleResetData2, expected: expectedReset2}, + {input: lifeCycleResetData3, expected: expectedReset3}, + } + + unbound := nonTLSUnbound() + unbound.Cumulative = false + require.True(t, unbound.Init()) + ubClient := &mockUnboundClient{err: false} + unbound.client = ubClient + + for i, test := range tests { + t.Run(fmt.Sprintf("run %d", i+1), func(t *testing.T) { + ubClient.data = test.input + assert.Equal(t, test.expected, unbound.Collect()) + }) + } + + testCharts(t, unbound) +} + +func TestUnbound_Collect_EmptyResponse(t *testing.T) { + unbound := nonTLSUnbound() + require.True(t, unbound.Init()) + unbound.client = mockUnboundClient{data: []byte{}, err: false} + + assert.Nil(t, unbound.Collect()) +} + +func TestUnbound_Collect_ErrorResponse(t *testing.T) { + unbound := nonTLSUnbound() + require.True(t, unbound.Init()) + unbound.client = mockUnboundClient{data: []byte("error unknown command 'unknown'"), err: false} + + assert.Nil(t, unbound.Collect()) +} + +func TestUnbound_Collect_ErrorOnSend(t *testing.T) { + unbound := nonTLSUnbound() + require.True(t, unbound.Init()) + unbound.client = mockUnboundClient{err: true} + + assert.Nil(t, unbound.Collect()) +} + +func TestUnbound_Collect_ErrorOnParseBadSyntax(t *testing.T) { + unbound := nonTLSUnbound() + require.True(t, unbound.Init()) + data := strings.Repeat("zk_avg_latency 0\nzk_min_latency 0\nzk_mix_latency 0\n", 10) + unbound.client = mockUnboundClient{data: []byte(data), err: false} + + assert.Nil(t, unbound.Collect()) +} + +type mockUnboundClient struct { + data []byte + err bool +} + +func (m mockUnboundClient) send(command string) ([]string, error) { + if m.err { + return nil, errors.New("mock send error") + } + rv := make([]string, 0, 160) + s := bufio.NewScanner(bytes.NewReader(m.data)) + for s.Scan() { + rv = append(rv, s.Text()) + } + return rv, nil +} + +func testCharts(t *testing.T, u *Unbound) { + t.Helper() + testThreadCharts(t, u) + testExtendedCharts(t, u) +} + +func testThreadCharts(t *testing.T, u *Unbound) { + for thread := range u.cache.threads { + for _, chart := range *threadCharts(thread, u.Cumulative) { + assert.Truef(t, u.Charts().Has(chart.ID), "chart '%s' is not created for '%s' thread", chart.ID, thread) + } + } +} + +func testExtendedCharts(t *testing.T, u *Unbound) { + if len(u.cache.answerRCode) == 0 { + return + } + for _, chart := range *extendedCharts(u.Cumulative) { + assert.Truef(t, u.Charts().Has(chart.ID), "chart '%s' is not added", chart.ID) + } + + if chart := u.Charts().Get(queryTypeChart.ID); chart != nil { + for typ := range u.cache.queryType { + dimID := "num.query.type." + typ + assert.Truef(t, chart.HasDim(dimID), "chart '%s' has no dim for '%s' type, expected '%s'", chart.ID, typ, dimID) + } + } + if chart := u.Charts().Get(queryClassChart.ID); chart != nil { + for class := range u.cache.queryClass { + dimID := "num.query.class." + class + assert.Truef(t, chart.HasDim(dimID), "chart '%s' has no dim for '%s' class, expected '%s'", chart.ID, class, dimID) + } + } + if chart := u.Charts().Get(queryOpCodeChart.ID); chart != nil { + for opcode := range u.cache.queryOpCode { + dimID := "num.query.opcode." + opcode + assert.Truef(t, chart.HasDim(dimID), "chart '%s' has no dim for '%s' opcode, expected '%s'", chart.ID, opcode, dimID) + } + } + if chart := u.Charts().Get(answerRCodeChart.ID); chart != nil { + for rcode := range u.cache.answerRCode { + dimID := "num.answer.rcode." + rcode + assert.Truef(t, chart.HasDim(dimID), "chart '%s' has no dim for '%s' rcode, expected '%s'", chart.ID, rcode, dimID) + } + } +} + +var ( + expectedCommon = map[string]int64{ + "thread0.num.cachehits": 21, + "thread0.num.cachemiss": 7, + "thread0.num.dnscrypt.cert": 0, + "thread0.num.dnscrypt.cleartext": 0, + "thread0.num.dnscrypt.crypted": 0, + "thread0.num.dnscrypt.malformed": 0, + "thread0.num.prefetch": 0, + "thread0.num.queries": 28, + "thread0.num.queries_ip_ratelimited": 0, + "thread0.num.recursivereplies": 7, + "thread0.num.zero_ttl": 0, + "thread0.recursion.time.avg": 1255, + "thread0.recursion.time.median": 480, + "thread0.requestlist.avg": 857, + "thread0.requestlist.current.all": 0, + "thread0.requestlist.current.user": 0, + "thread0.requestlist.exceeded": 0, + "thread0.requestlist.max": 6, + "thread0.requestlist.overwritten": 0, + "thread0.tcpusage": 0, + "thread1.num.cachehits": 13, + "thread1.num.cachemiss": 3, + "thread1.num.dnscrypt.cert": 0, + "thread1.num.dnscrypt.cleartext": 0, + "thread1.num.dnscrypt.crypted": 0, + "thread1.num.dnscrypt.malformed": 0, + "thread1.num.prefetch": 0, + "thread1.num.queries": 16, + "thread1.num.queries_ip_ratelimited": 0, + "thread1.num.recursivereplies": 3, + "thread1.num.zero_ttl": 0, + "thread1.recursion.time.avg": 93, + "thread1.recursion.time.median": 0, + "thread1.requestlist.avg": 0, + "thread1.requestlist.current.all": 0, + "thread1.requestlist.current.user": 0, + "thread1.requestlist.exceeded": 0, + "thread1.requestlist.max": 0, + "thread1.requestlist.overwritten": 0, + "thread1.tcpusage": 0, + "time.elapsed": 88, + "time.now": 1574094836, + "time.up": 88, + "total.num.cachehits": 34, + "total.num.cachemiss": 10, + "total.num.dnscrypt.cert": 0, + "total.num.dnscrypt.cleartext": 0, + "total.num.dnscrypt.crypted": 0, + "total.num.dnscrypt.malformed": 0, + "total.num.prefetch": 0, + "total.num.queries": 44, + "total.num.queries_ip_ratelimited": 0, + "total.num.recursivereplies": 10, + "total.num.zero_ttl": 0, + "total.recursion.time.avg": 907, + "total.recursion.time.median": 240, + "total.requestlist.avg": 600, + "total.requestlist.current.all": 0, + "total.requestlist.current.user": 0, + "total.requestlist.exceeded": 0, + "total.requestlist.max": 6, + "total.requestlist.overwritten": 0, + "total.tcpusage": 0, + } + + expectedExtended = map[string]int64{ + "dnscrypt_nonce.cache.count": 0, + "dnscrypt_shared_secret.cache.count": 0, + "infra.cache.count": 205, + "key.cache.count": 9, + "mem.cache.dnscrypt_nonce": 0, + "mem.cache.dnscrypt_shared_secret": 0, + "mem.cache.message": 90357, + "mem.cache.rrset": 178642, + "mem.mod.iterator": 16588, + "mem.mod.respip": 0, + "mem.mod.subnet": 74504, + "mem.mod.validator": 81059, + "mem.streamwait": 0, + "msg.cache.count": 81, + "num.answer.bogus": 0, + "num.answer.rcode.FORMERR": 0, + "num.answer.rcode.NOERROR": 40, + "num.answer.rcode.NOTIMPL": 0, + "num.answer.rcode.NXDOMAIN": 4, + "num.answer.rcode.REFUSED": 0, + "num.answer.rcode.SERVFAIL": 0, + "num.answer.secure": 0, + "num.query.aggressive.NOERROR": 2, + "num.query.aggressive.NXDOMAIN": 0, + "num.query.authzone.down": 0, + "num.query.authzone.up": 0, + "num.query.class.IN": 44, + "num.query.dnscrypt.replay": 0, + "num.query.dnscrypt.shared_secret.cachemiss": 0, + "num.query.edns.DO": 0, + "num.query.edns.present": 0, + "num.query.flags.AA": 0, + "num.query.flags.AD": 0, + "num.query.flags.CD": 0, + "num.query.flags.QR": 0, + "num.query.flags.RA": 0, + "num.query.flags.RD": 44, + "num.query.flags.TC": 0, + "num.query.flags.Z": 0, + "num.query.ipv6": 39, + "num.query.opcode.QUERY": 44, + "num.query.ratelimited": 0, + "num.query.subnet": 0, + "num.query.subnet_cache": 0, + "num.query.tcp": 0, + "num.query.tcpout": 1, + "num.query.tls": 0, + "num.query.tls.resume": 0, + "num.query.type.A": 13, + "num.query.type.AAAA": 13, + "num.query.type.MX": 13, + "num.query.type.PTR": 5, + "num.rrset.bogus": 0, + "rrset.cache.count": 314, + "thread0.num.cachehits": 21, + "thread0.num.cachemiss": 7, + "thread0.num.dnscrypt.cert": 0, + "thread0.num.dnscrypt.cleartext": 0, + "thread0.num.dnscrypt.crypted": 0, + "thread0.num.dnscrypt.malformed": 0, + "thread0.num.prefetch": 0, + "thread0.num.queries": 28, + "thread0.num.queries_ip_ratelimited": 0, + "thread0.num.recursivereplies": 7, + "thread0.num.zero_ttl": 0, + "thread0.recursion.time.avg": 1255, + "thread0.recursion.time.median": 480, + "thread0.requestlist.avg": 857, + "thread0.requestlist.current.all": 0, + "thread0.requestlist.current.user": 0, + "thread0.requestlist.exceeded": 0, + "thread0.requestlist.max": 6, + "thread0.requestlist.overwritten": 0, + "thread0.tcpusage": 0, + "thread1.num.cachehits": 13, + "thread1.num.cachemiss": 3, + "thread1.num.dnscrypt.cert": 0, + "thread1.num.dnscrypt.cleartext": 0, + "thread1.num.dnscrypt.crypted": 0, + "thread1.num.dnscrypt.malformed": 0, + "thread1.num.prefetch": 0, + "thread1.num.queries": 16, + "thread1.num.queries_ip_ratelimited": 0, + "thread1.num.recursivereplies": 3, + "thread1.num.zero_ttl": 0, + "thread1.recursion.time.avg": 93, + "thread1.recursion.time.median": 0, + "thread1.requestlist.avg": 0, + "thread1.requestlist.current.all": 0, + "thread1.requestlist.current.user": 0, + "thread1.requestlist.exceeded": 0, + "thread1.requestlist.max": 0, + "thread1.requestlist.overwritten": 0, + "thread1.tcpusage": 0, + "time.elapsed": 88, + "time.now": 1574094836, + "time.up": 88, + "total.num.cachehits": 34, + "total.num.cachemiss": 10, + "total.num.dnscrypt.cert": 0, + "total.num.dnscrypt.cleartext": 0, + "total.num.dnscrypt.crypted": 0, + "total.num.dnscrypt.malformed": 0, + "total.num.prefetch": 0, + "total.num.queries": 44, + "total.num.queries_ip_ratelimited": 0, + "total.num.recursivereplies": 10, + "total.num.zero_ttl": 0, + "total.recursion.time.avg": 907, + "total.recursion.time.median": 240, + "total.requestlist.avg": 600, + "total.requestlist.current.all": 0, + "total.requestlist.current.user": 0, + "total.requestlist.exceeded": 0, + "total.requestlist.max": 6, + "total.requestlist.overwritten": 0, + "total.tcpusage": 0, + "unwanted.queries": 0, + "unwanted.replies": 0, + } +) + +var ( + expectedCumulative1 = map[string]int64{ + "dnscrypt_nonce.cache.count": 0, + "dnscrypt_shared_secret.cache.count": 0, + "infra.cache.count": 192, + "key.cache.count": 11, + "mem.cache.dnscrypt_nonce": 0, + "mem.cache.dnscrypt_shared_secret": 0, + "mem.cache.message": 93392, + "mem.cache.rrset": 175745, + "mem.mod.iterator": 16588, + "mem.mod.respip": 0, + "mem.mod.subnet": 74504, + "mem.mod.validator": 81479, + "mem.streamwait": 0, + "msg.cache.count": 94, + "num.answer.bogus": 0, + "num.answer.rcode.FORMERR": 0, + "num.answer.rcode.NOERROR": 184, + "num.answer.rcode.NOTIMPL": 0, + "num.answer.rcode.NXDOMAIN": 16, + "num.answer.rcode.REFUSED": 0, + "num.answer.rcode.SERVFAIL": 0, + "num.answer.secure": 0, + "num.query.aggressive.NOERROR": 1, + "num.query.aggressive.NXDOMAIN": 0, + "num.query.authzone.down": 0, + "num.query.authzone.up": 0, + "num.query.class.IN": 200, + "num.query.dnscrypt.replay": 0, + "num.query.dnscrypt.shared_secret.cachemiss": 0, + "num.query.edns.DO": 0, + "num.query.edns.present": 0, + "num.query.flags.AA": 0, + "num.query.flags.AD": 0, + "num.query.flags.CD": 0, + "num.query.flags.QR": 0, + "num.query.flags.RA": 0, + "num.query.flags.RD": 200, + "num.query.flags.TC": 0, + "num.query.flags.Z": 0, + "num.query.ipv6": 0, + "num.query.opcode.QUERY": 200, + "num.query.ratelimited": 0, + "num.query.subnet": 0, + "num.query.subnet_cache": 0, + "num.query.tcp": 0, + "num.query.tcpout": 0, + "num.query.tls": 0, + "num.query.tls.resume": 0, + "num.query.type.A": 60, + "num.query.type.AAAA": 60, + "num.query.type.MX": 60, + "num.query.type.PTR": 20, + "num.rrset.bogus": 0, + "rrset.cache.count": 304, + "thread0.num.cachehits": 80, + "thread0.num.cachemiss": 10, + "thread0.num.dnscrypt.cert": 0, + "thread0.num.dnscrypt.cleartext": 0, + "thread0.num.dnscrypt.crypted": 0, + "thread0.num.dnscrypt.malformed": 0, + "thread0.num.prefetch": 0, + "thread0.num.queries": 90, + "thread0.num.queries_ip_ratelimited": 0, + "thread0.num.recursivereplies": 10, + "thread0.num.zero_ttl": 0, + "thread0.recursion.time.avg": 222, + "thread0.recursion.time.median": 337, + "thread0.requestlist.avg": 100, + "thread0.requestlist.current.all": 0, + "thread0.requestlist.current.user": 0, + "thread0.requestlist.exceeded": 0, + "thread0.requestlist.max": 1, + "thread0.requestlist.overwritten": 0, + "thread0.tcpusage": 0, + "thread1.num.cachehits": 101, + "thread1.num.cachemiss": 9, + "thread1.num.dnscrypt.cert": 0, + "thread1.num.dnscrypt.cleartext": 0, + "thread1.num.dnscrypt.crypted": 0, + "thread1.num.dnscrypt.malformed": 0, + "thread1.num.prefetch": 0, + "thread1.num.queries": 110, + "thread1.num.queries_ip_ratelimited": 0, + "thread1.num.recursivereplies": 9, + "thread1.num.zero_ttl": 0, + "thread1.recursion.time.avg": 844, + "thread1.recursion.time.median": 360, + "thread1.requestlist.avg": 222, + "thread1.requestlist.current.all": 0, + "thread1.requestlist.current.user": 0, + "thread1.requestlist.exceeded": 0, + "thread1.requestlist.max": 1, + "thread1.requestlist.overwritten": 0, + "thread1.tcpusage": 0, + "time.elapsed": 122, + "time.now": 1574103378, + "time.up": 122, + "total.num.cachehits": 181, + "total.num.cachemiss": 19, + "total.num.dnscrypt.cert": 0, + "total.num.dnscrypt.cleartext": 0, + "total.num.dnscrypt.crypted": 0, + "total.num.dnscrypt.malformed": 0, + "total.num.prefetch": 0, + "total.num.queries": 200, + "total.num.queries_ip_ratelimited": 0, + "total.num.recursivereplies": 19, + "total.num.zero_ttl": 0, + "total.recursion.time.avg": 516, + "total.recursion.time.median": 348, + "total.requestlist.avg": 157, + "total.requestlist.current.all": 0, + "total.requestlist.current.user": 0, + "total.requestlist.exceeded": 0, + "total.requestlist.max": 1, + "total.requestlist.overwritten": 0, + "total.tcpusage": 0, + "unwanted.queries": 0, + "unwanted.replies": 0, + } + + expectedCumulative2 = map[string]int64{ + "dnscrypt_nonce.cache.count": 0, + "dnscrypt_shared_secret.cache.count": 0, + "infra.cache.count": 192, + "key.cache.count": 11, + "mem.cache.dnscrypt_nonce": 0, + "mem.cache.dnscrypt_shared_secret": 0, + "mem.cache.message": 93392, + "mem.cache.rrset": 175745, + "mem.mod.iterator": 16588, + "mem.mod.respip": 0, + "mem.mod.subnet": 74504, + "mem.mod.validator": 81479, + "mem.streamwait": 0, + "msg.cache.count": 94, + "num.answer.bogus": 0, + "num.answer.rcode.FORMERR": 0, + "num.answer.rcode.NOERROR": 274, + "num.answer.rcode.NOTIMPL": 0, + "num.answer.rcode.NXDOMAIN": 16, + "num.answer.rcode.REFUSED": 0, + "num.answer.rcode.SERVFAIL": 0, + "num.answer.secure": 0, + "num.query.aggressive.NOERROR": 1, + "num.query.aggressive.NXDOMAIN": 0, + "num.query.authzone.down": 0, + "num.query.authzone.up": 0, + "num.query.class.IN": 290, + "num.query.dnscrypt.replay": 0, + "num.query.dnscrypt.shared_secret.cachemiss": 0, + "num.query.edns.DO": 0, + "num.query.edns.present": 0, + "num.query.flags.AA": 0, + "num.query.flags.AD": 0, + "num.query.flags.CD": 0, + "num.query.flags.QR": 0, + "num.query.flags.RA": 0, + "num.query.flags.RD": 290, + "num.query.flags.TC": 0, + "num.query.flags.Z": 0, + "num.query.ipv6": 0, + "num.query.opcode.QUERY": 290, + "num.query.ratelimited": 0, + "num.query.subnet": 0, + "num.query.subnet_cache": 0, + "num.query.tcp": 0, + "num.query.tcpout": 0, + "num.query.tls": 0, + "num.query.tls.resume": 0, + "num.query.type.A": 90, + "num.query.type.AAAA": 90, + "num.query.type.MX": 90, + "num.query.type.PTR": 20, + "num.rrset.bogus": 0, + "rrset.cache.count": 304, + "thread0.num.cachehits": 123, + "thread0.num.cachemiss": 10, + "thread0.num.dnscrypt.cert": 0, + "thread0.num.dnscrypt.cleartext": 0, + "thread0.num.dnscrypt.crypted": 0, + "thread0.num.dnscrypt.malformed": 0, + "thread0.num.prefetch": 0, + "thread0.num.queries": 133, + "thread0.num.queries_ip_ratelimited": 0, + "thread0.num.recursivereplies": 10, + "thread0.num.zero_ttl": 0, + "thread0.recursion.time.avg": 0, + "thread0.recursion.time.median": 0, + "thread0.requestlist.avg": 0, + "thread0.requestlist.current.all": 0, + "thread0.requestlist.current.user": 0, + "thread0.requestlist.exceeded": 0, + "thread0.requestlist.max": 1, + "thread0.requestlist.overwritten": 0, + "thread0.tcpusage": 0, + "thread1.num.cachehits": 148, + "thread1.num.cachemiss": 9, + "thread1.num.dnscrypt.cert": 0, + "thread1.num.dnscrypt.cleartext": 0, + "thread1.num.dnscrypt.crypted": 0, + "thread1.num.dnscrypt.malformed": 0, + "thread1.num.prefetch": 0, + "thread1.num.queries": 157, + "thread1.num.queries_ip_ratelimited": 0, + "thread1.num.recursivereplies": 9, + "thread1.num.zero_ttl": 0, + "thread1.recursion.time.avg": 0, + "thread1.recursion.time.median": 0, + "thread1.requestlist.avg": 0, + "thread1.requestlist.current.all": 0, + "thread1.requestlist.current.user": 0, + "thread1.requestlist.exceeded": 0, + "thread1.requestlist.max": 1, + "thread1.requestlist.overwritten": 0, + "thread1.tcpusage": 0, + "time.elapsed": 82, + "time.now": 1574103461, + "time.up": 205, + "total.num.cachehits": 271, + "total.num.cachemiss": 19, + "total.num.dnscrypt.cert": 0, + "total.num.dnscrypt.cleartext": 0, + "total.num.dnscrypt.crypted": 0, + "total.num.dnscrypt.malformed": 0, + "total.num.prefetch": 0, + "total.num.queries": 290, + "total.num.queries_ip_ratelimited": 0, + "total.num.recursivereplies": 19, + "total.num.zero_ttl": 0, + "total.recursion.time.avg": 0, + "total.recursion.time.median": 0, + "total.requestlist.avg": 0, + "total.requestlist.current.all": 0, + "total.requestlist.current.user": 0, + "total.requestlist.exceeded": 0, + "total.requestlist.max": 1, + "total.requestlist.overwritten": 0, + "total.tcpusage": 0, + "unwanted.queries": 0, + "unwanted.replies": 0, + } + + expectedCumulative3 = map[string]int64{ + "dnscrypt_nonce.cache.count": 0, + "dnscrypt_shared_secret.cache.count": 0, + "infra.cache.count": 232, + "key.cache.count": 14, + "mem.cache.dnscrypt_nonce": 0, + "mem.cache.dnscrypt_shared_secret": 0, + "mem.cache.message": 101198, + "mem.cache.rrset": 208839, + "mem.mod.iterator": 16588, + "mem.mod.respip": 0, + "mem.mod.subnet": 74504, + "mem.mod.validator": 85725, + "mem.streamwait": 0, + "msg.cache.count": 119, + "num.answer.bogus": 0, + "num.answer.rcode.FORMERR": 0, + "num.answer.rcode.NOERROR": 334, + "num.answer.rcode.NOTIMPL": 0, + "num.answer.rcode.NXDOMAIN": 16, + "num.answer.rcode.REFUSED": 0, + "num.answer.rcode.SERVFAIL": 10, + "num.answer.rcode.nodata": 20, + "num.answer.secure": 0, + "num.query.aggressive.NOERROR": 1, + "num.query.aggressive.NXDOMAIN": 0, + "num.query.authzone.down": 0, + "num.query.authzone.up": 0, + "num.query.class.IN": 360, + "num.query.dnscrypt.replay": 0, + "num.query.dnscrypt.shared_secret.cachemiss": 0, + "num.query.edns.DO": 0, + "num.query.edns.present": 0, + "num.query.flags.AA": 0, + "num.query.flags.AD": 0, + "num.query.flags.CD": 0, + "num.query.flags.QR": 0, + "num.query.flags.RA": 0, + "num.query.flags.RD": 360, + "num.query.flags.TC": 0, + "num.query.flags.Z": 0, + "num.query.ipv6": 0, + "num.query.opcode.QUERY": 360, + "num.query.ratelimited": 0, + "num.query.subnet": 0, + "num.query.subnet_cache": 0, + "num.query.tcp": 0, + "num.query.tcpout": 0, + "num.query.tls": 0, + "num.query.tls.resume": 0, + "num.query.type.A": 120, + "num.query.type.AAAA": 110, + "num.query.type.MX": 110, + "num.query.type.PTR": 20, + "num.rrset.bogus": 0, + "rrset.cache.count": 401, + "thread0.num.cachehits": 150, + "thread0.num.cachemiss": 15, + "thread0.num.dnscrypt.cert": 0, + "thread0.num.dnscrypt.cleartext": 0, + "thread0.num.dnscrypt.crypted": 0, + "thread0.num.dnscrypt.malformed": 0, + "thread0.num.prefetch": 0, + "thread0.num.queries": 165, + "thread0.num.queries_ip_ratelimited": 0, + "thread0.num.recursivereplies": 15, + "thread0.num.zero_ttl": 0, + "thread0.recursion.time.avg": 261, + "thread0.recursion.time.median": 318, + "thread0.requestlist.avg": 66, + "thread0.requestlist.current.all": 0, + "thread0.requestlist.current.user": 0, + "thread0.requestlist.exceeded": 0, + "thread0.requestlist.max": 1, + "thread0.requestlist.overwritten": 0, + "thread0.tcpusage": 0, + "thread1.num.cachehits": 184, + "thread1.num.cachemiss": 11, + "thread1.num.dnscrypt.cert": 0, + "thread1.num.dnscrypt.cleartext": 0, + "thread1.num.dnscrypt.crypted": 0, + "thread1.num.dnscrypt.malformed": 0, + "thread1.num.prefetch": 0, + "thread1.num.queries": 195, + "thread1.num.queries_ip_ratelimited": 0, + "thread1.num.recursivereplies": 11, + "thread1.num.zero_ttl": 0, + "thread1.recursion.time.avg": 709, + "thread1.recursion.time.median": 294, + "thread1.requestlist.avg": 363, + "thread1.requestlist.current.all": 0, + "thread1.requestlist.current.user": 0, + "thread1.requestlist.exceeded": 0, + "thread1.requestlist.max": 2, + "thread1.requestlist.overwritten": 0, + "thread1.tcpusage": 0, + "time.elapsed": 82, + "time.now": 1574103543, + "time.up": 288, + "total.num.cachehits": 334, + "total.num.cachemiss": 26, + "total.num.dnscrypt.cert": 0, + "total.num.dnscrypt.cleartext": 0, + "total.num.dnscrypt.crypted": 0, + "total.num.dnscrypt.malformed": 0, + "total.num.prefetch": 0, + "total.num.queries": 360, + "total.num.queries_ip_ratelimited": 0, + "total.num.recursivereplies": 26, + "total.num.zero_ttl": 0, + "total.recursion.time.avg": 450, + "total.recursion.time.median": 306, + "total.requestlist.avg": 192, + "total.requestlist.current.all": 0, + "total.requestlist.current.user": 0, + "total.requestlist.exceeded": 0, + "total.requestlist.max": 2, + "total.requestlist.overwritten": 0, + "total.tcpusage": 0, + "unwanted.queries": 0, + "unwanted.replies": 0, + } +) + +var ( + expectedReset1 = map[string]int64{ + "dnscrypt_nonce.cache.count": 0, + "dnscrypt_shared_secret.cache.count": 0, + "infra.cache.count": 181, + "key.cache.count": 10, + "mem.cache.dnscrypt_nonce": 0, + "mem.cache.dnscrypt_shared_secret": 0, + "mem.cache.message": 86064, + "mem.cache.rrset": 172757, + "mem.mod.iterator": 16588, + "mem.mod.respip": 0, + "mem.mod.subnet": 74504, + "mem.mod.validator": 79979, + "mem.streamwait": 0, + "msg.cache.count": 67, + "num.answer.bogus": 0, + "num.answer.rcode.FORMERR": 0, + "num.answer.rcode.NOERROR": 90, + "num.answer.rcode.NOTIMPL": 0, + "num.answer.rcode.NXDOMAIN": 10, + "num.answer.rcode.REFUSED": 0, + "num.answer.rcode.SERVFAIL": 0, + "num.answer.rcode.nodata": 10, + "num.answer.secure": 0, + "num.query.aggressive.NOERROR": 2, + "num.query.aggressive.NXDOMAIN": 0, + "num.query.authzone.down": 0, + "num.query.authzone.up": 0, + "num.query.class.IN": 100, + "num.query.dnscrypt.replay": 0, + "num.query.dnscrypt.shared_secret.cachemiss": 0, + "num.query.edns.DO": 0, + "num.query.edns.present": 0, + "num.query.flags.AA": 0, + "num.query.flags.AD": 0, + "num.query.flags.CD": 0, + "num.query.flags.QR": 0, + "num.query.flags.RA": 0, + "num.query.flags.RD": 100, + "num.query.flags.TC": 0, + "num.query.flags.Z": 0, + "num.query.ipv6": 0, + "num.query.opcode.QUERY": 100, + "num.query.ratelimited": 0, + "num.query.subnet": 0, + "num.query.subnet_cache": 0, + "num.query.tcp": 0, + "num.query.tcpout": 1, + "num.query.tls": 0, + "num.query.tls.resume": 0, + "num.query.type.A": 30, + "num.query.type.AAAA": 30, + "num.query.type.MX": 30, + "num.query.type.PTR": 10, + "num.rrset.bogus": 0, + "rrset.cache.count": 303, + "thread0.num.cachehits": 44, + "thread0.num.cachemiss": 7, + "thread0.num.dnscrypt.cert": 0, + "thread0.num.dnscrypt.cleartext": 0, + "thread0.num.dnscrypt.crypted": 0, + "thread0.num.dnscrypt.malformed": 0, + "thread0.num.prefetch": 0, + "thread0.num.queries": 51, + "thread0.num.queries_ip_ratelimited": 0, + "thread0.num.recursivereplies": 7, + "thread0.num.zero_ttl": 0, + "thread0.recursion.time.avg": 365, + "thread0.recursion.time.median": 57, + "thread0.requestlist.avg": 0, + "thread0.requestlist.current.all": 0, + "thread0.requestlist.current.user": 0, + "thread0.requestlist.exceeded": 0, + "thread0.requestlist.max": 0, + "thread0.requestlist.overwritten": 0, + "thread0.tcpusage": 0, + "thread1.num.cachehits": 46, + "thread1.num.cachemiss": 3, + "thread1.num.dnscrypt.cert": 0, + "thread1.num.dnscrypt.cleartext": 0, + "thread1.num.dnscrypt.crypted": 0, + "thread1.num.dnscrypt.malformed": 0, + "thread1.num.prefetch": 0, + "thread1.num.queries": 49, + "thread1.num.queries_ip_ratelimited": 0, + "thread1.num.recursivereplies": 3, + "thread1.num.zero_ttl": 0, + "thread1.recursion.time.avg": 1582, + "thread1.recursion.time.median": 0, + "thread1.requestlist.avg": 0, + "thread1.requestlist.current.all": 0, + "thread1.requestlist.current.user": 0, + "thread1.requestlist.exceeded": 0, + "thread1.requestlist.max": 0, + "thread1.requestlist.overwritten": 0, + "thread1.tcpusage": 0, + "time.elapsed": 45, + "time.now": 1574103644, + "time.up": 45, + "total.num.cachehits": 90, + "total.num.cachemiss": 10, + "total.num.dnscrypt.cert": 0, + "total.num.dnscrypt.cleartext": 0, + "total.num.dnscrypt.crypted": 0, + "total.num.dnscrypt.malformed": 0, + "total.num.prefetch": 0, + "total.num.queries": 100, + "total.num.queries_ip_ratelimited": 0, + "total.num.recursivereplies": 10, + "total.num.zero_ttl": 0, + "total.recursion.time.avg": 730, + "total.recursion.time.median": 28, + "total.requestlist.avg": 0, + "total.requestlist.current.all": 0, + "total.requestlist.current.user": 0, + "total.requestlist.exceeded": 0, + "total.requestlist.max": 0, + "total.requestlist.overwritten": 0, + "total.tcpusage": 0, + "unwanted.queries": 0, + "unwanted.replies": 0, + } + expectedReset2 = map[string]int64{ + "dnscrypt_nonce.cache.count": 0, + "dnscrypt_shared_secret.cache.count": 0, + "infra.cache.count": 181, + "key.cache.count": 10, + "mem.cache.dnscrypt_nonce": 0, + "mem.cache.dnscrypt_shared_secret": 0, + "mem.cache.message": 86064, + "mem.cache.rrset": 172757, + "mem.mod.iterator": 16588, + "mem.mod.respip": 0, + "mem.mod.subnet": 74504, + "mem.mod.validator": 79979, + "mem.streamwait": 0, + "msg.cache.count": 67, + "num.answer.bogus": 0, + "num.answer.rcode.FORMERR": 0, + "num.answer.rcode.NOERROR": 0, + "num.answer.rcode.NOTIMPL": 0, + "num.answer.rcode.NXDOMAIN": 0, + "num.answer.rcode.REFUSED": 0, + "num.answer.rcode.SERVFAIL": 0, + "num.answer.rcode.nodata": 0, + "num.answer.secure": 0, + "num.query.aggressive.NOERROR": 0, + "num.query.aggressive.NXDOMAIN": 0, + "num.query.authzone.down": 0, + "num.query.authzone.up": 0, + "num.query.class.IN": 0, + "num.query.dnscrypt.replay": 0, + "num.query.dnscrypt.shared_secret.cachemiss": 0, + "num.query.edns.DO": 0, + "num.query.edns.present": 0, + "num.query.flags.AA": 0, + "num.query.flags.AD": 0, + "num.query.flags.CD": 0, + "num.query.flags.QR": 0, + "num.query.flags.RA": 0, + "num.query.flags.RD": 0, + "num.query.flags.TC": 0, + "num.query.flags.Z": 0, + "num.query.ipv6": 0, + "num.query.opcode.QUERY": 0, + "num.query.ratelimited": 0, + "num.query.subnet": 0, + "num.query.subnet_cache": 0, + "num.query.tcp": 0, + "num.query.tcpout": 0, + "num.query.tls": 0, + "num.query.tls.resume": 0, + "num.query.type.A": 0, + "num.query.type.AAAA": 0, + "num.query.type.MX": 0, + "num.query.type.PTR": 0, + "num.rrset.bogus": 0, + "rrset.cache.count": 303, + "thread0.num.cachehits": 0, + "thread0.num.cachemiss": 0, + "thread0.num.dnscrypt.cert": 0, + "thread0.num.dnscrypt.cleartext": 0, + "thread0.num.dnscrypt.crypted": 0, + "thread0.num.dnscrypt.malformed": 0, + "thread0.num.prefetch": 0, + "thread0.num.queries": 0, + "thread0.num.queries_ip_ratelimited": 0, + "thread0.num.recursivereplies": 0, + "thread0.num.zero_ttl": 0, + "thread0.recursion.time.avg": 0, + "thread0.recursion.time.median": 0, + "thread0.requestlist.avg": 0, + "thread0.requestlist.current.all": 0, + "thread0.requestlist.current.user": 0, + "thread0.requestlist.exceeded": 0, + "thread0.requestlist.max": 0, + "thread0.requestlist.overwritten": 0, + "thread0.tcpusage": 0, + "thread1.num.cachehits": 0, + "thread1.num.cachemiss": 0, + "thread1.num.dnscrypt.cert": 0, + "thread1.num.dnscrypt.cleartext": 0, + "thread1.num.dnscrypt.crypted": 0, + "thread1.num.dnscrypt.malformed": 0, + "thread1.num.prefetch": 0, + "thread1.num.queries": 0, + "thread1.num.queries_ip_ratelimited": 0, + "thread1.num.recursivereplies": 0, + "thread1.num.zero_ttl": 0, + "thread1.recursion.time.avg": 0, + "thread1.recursion.time.median": 0, + "thread1.requestlist.avg": 0, + "thread1.requestlist.current.all": 0, + "thread1.requestlist.current.user": 0, + "thread1.requestlist.exceeded": 0, + "thread1.requestlist.max": 0, + "thread1.requestlist.overwritten": 0, + "thread1.tcpusage": 0, + "time.elapsed": 26, + "time.now": 1574103671, + "time.up": 71, + "total.num.cachehits": 0, + "total.num.cachemiss": 0, + "total.num.dnscrypt.cert": 0, + "total.num.dnscrypt.cleartext": 0, + "total.num.dnscrypt.crypted": 0, + "total.num.dnscrypt.malformed": 0, + "total.num.prefetch": 0, + "total.num.queries": 0, + "total.num.queries_ip_ratelimited": 0, + "total.num.recursivereplies": 0, + "total.num.zero_ttl": 0, + "total.recursion.time.avg": 0, + "total.recursion.time.median": 0, + "total.requestlist.avg": 0, + "total.requestlist.current.all": 0, + "total.requestlist.current.user": 0, + "total.requestlist.exceeded": 0, + "total.requestlist.max": 0, + "total.requestlist.overwritten": 0, + "total.tcpusage": 0, + "unwanted.queries": 0, + "unwanted.replies": 0, + } + + expectedReset3 = map[string]int64{ + "dnscrypt_nonce.cache.count": 0, + "dnscrypt_shared_secret.cache.count": 0, + "infra.cache.count": 303, + "key.cache.count": 15, + "mem.cache.dnscrypt_nonce": 0, + "mem.cache.dnscrypt_shared_secret": 0, + "mem.cache.message": 105471, + "mem.cache.rrset": 235917, + "mem.mod.iterator": 16588, + "mem.mod.respip": 0, + "mem.mod.subnet": 74504, + "mem.mod.validator": 87270, + "mem.streamwait": 0, + "msg.cache.count": 127, + "num.answer.bogus": 0, + "num.answer.rcode.FORMERR": 0, + "num.answer.rcode.NOERROR": 60, + "num.answer.rcode.NOTIMPL": 0, + "num.answer.rcode.NXDOMAIN": 10, + "num.answer.rcode.REFUSED": 0, + "num.answer.rcode.SERVFAIL": 0, + "num.answer.rcode.nodata": 10, + "num.answer.secure": 0, + "num.query.aggressive.NOERROR": 2, + "num.query.aggressive.NXDOMAIN": 0, + "num.query.authzone.down": 0, + "num.query.authzone.up": 0, + "num.query.class.IN": 70, + "num.query.dnscrypt.replay": 0, + "num.query.dnscrypt.shared_secret.cachemiss": 0, + "num.query.edns.DO": 0, + "num.query.edns.present": 0, + "num.query.flags.AA": 0, + "num.query.flags.AD": 0, + "num.query.flags.CD": 0, + "num.query.flags.QR": 0, + "num.query.flags.RA": 0, + "num.query.flags.RD": 70, + "num.query.flags.TC": 0, + "num.query.flags.Z": 0, + "num.query.ipv6": 0, + "num.query.opcode.QUERY": 70, + "num.query.ratelimited": 0, + "num.query.subnet": 0, + "num.query.subnet_cache": 0, + "num.query.tcp": 0, + "num.query.tcpout": 0, + "num.query.tls": 0, + "num.query.tls.resume": 0, + "num.query.type.A": 20, + "num.query.type.AAAA": 20, + "num.query.type.MX": 20, + "num.query.type.PTR": 10, + "num.rrset.bogus": 0, + "rrset.cache.count": 501, + "thread0.num.cachehits": 30, + "thread0.num.cachemiss": 4, + "thread0.num.dnscrypt.cert": 0, + "thread0.num.dnscrypt.cleartext": 0, + "thread0.num.dnscrypt.crypted": 0, + "thread0.num.dnscrypt.malformed": 0, + "thread0.num.prefetch": 0, + "thread0.num.queries": 34, + "thread0.num.queries_ip_ratelimited": 0, + "thread0.num.recursivereplies": 4, + "thread0.num.zero_ttl": 0, + "thread0.recursion.time.avg": 541, + "thread0.recursion.time.median": 98, + "thread0.requestlist.avg": 0, + "thread0.requestlist.current.all": 0, + "thread0.requestlist.current.user": 0, + "thread0.requestlist.exceeded": 0, + "thread0.requestlist.max": 0, + "thread0.requestlist.overwritten": 0, + "thread0.tcpusage": 0, + "thread1.num.cachehits": 33, + "thread1.num.cachemiss": 3, + "thread1.num.dnscrypt.cert": 0, + "thread1.num.dnscrypt.cleartext": 0, + "thread1.num.dnscrypt.crypted": 0, + "thread1.num.dnscrypt.malformed": 0, + "thread1.num.prefetch": 0, + "thread1.num.queries": 36, + "thread1.num.queries_ip_ratelimited": 0, + "thread1.num.recursivereplies": 3, + "thread1.num.zero_ttl": 0, + "thread1.recursion.time.avg": 62, + "thread1.recursion.time.median": 0, + "thread1.requestlist.avg": 1666, + "thread1.requestlist.current.all": 0, + "thread1.requestlist.current.user": 0, + "thread1.requestlist.exceeded": 0, + "thread1.requestlist.max": 5, + "thread1.requestlist.overwritten": 0, + "thread1.tcpusage": 0, + "time.elapsed": 59, + "time.now": 1574103731, + "time.up": 131, + "total.num.cachehits": 63, + "total.num.cachemiss": 7, + "total.num.dnscrypt.cert": 0, + "total.num.dnscrypt.cleartext": 0, + "total.num.dnscrypt.crypted": 0, + "total.num.dnscrypt.malformed": 0, + "total.num.prefetch": 0, + "total.num.queries": 70, + "total.num.queries_ip_ratelimited": 0, + "total.num.recursivereplies": 7, + "total.num.zero_ttl": 0, + "total.recursion.time.avg": 336, + "total.recursion.time.median": 49, + "total.requestlist.avg": 714, + "total.requestlist.current.all": 0, + "total.requestlist.current.user": 0, + "total.requestlist.exceeded": 0, + "total.requestlist.max": 5, + "total.requestlist.overwritten": 0, + "total.tcpusage": 0, + "unwanted.queries": 0, + "unwanted.replies": 0, + } +)