diff options
Diffstat (limited to '')
38 files changed, 6039 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/unbound/README.md b/src/go/collectors/go.d.plugin/modules/unbound/README.md new file mode 120000 index 000000000..5b0f42b04 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/README.md @@ -0,0 +1 @@ +integrations/unbound.md
\ No newline at end of file diff --git a/src/go/collectors/go.d.plugin/modules/unbound/charts.go b/src/go/collectors/go.d.plugin/modules/unbound/charts.go new file mode 100644 index 000000000..0f0607664 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/charts.go @@ -0,0 +1,527 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package unbound + +import ( + "fmt" + "strings" + + "github.com/netdata/netdata/go/go.d.plugin/agent/module" + + "golang.org/x/text/cases" + "golang.org/x/text/language" +) + +type ( + // Charts is an alias for module.Charts + Charts = module.Charts + // Chart 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 = module.Priority + iota + prioIPRateLimitedQueries + prioQueryType + prioQueryClass + prioQueryOpCode + prioQueryFlag + prioDNSCryptQueries + + prioRecurReplies + prioReplyRCode + + prioRecurTime + + prioCache + prioCachePercentage + prioCachePrefetch + prioCacheExpired + 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(expiredChart.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", + cases.Title(language.English, cases.Compact).String(thread), + chart.Title, + ) + chart.Fam = thread + "_stats" + chart.Ctx = "thread_" + chart.Ctx + chart.Priority = priority + for _, dim := range chart.Dims { + dim.ID = strings.Replace(dim.ID, "total", thread, 1) + } +} + +// Common stats charts +// see https://nlnetlabs.nl/documentation/unbound/unbound-control for the stats provided by unbound-control +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"}, + }, + } + expiredChart = Chart{ + ID: "cache_expired", + Title: "Replies Served From Expired Cache", + Units: "replies", + Fam: "cache", + Ctx: "unbound.expired", + Priority: prioCacheExpired, + Dims: Dims{ + {ID: "total.num.expired", Name: "expired"}, + }, + } + 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/src/go/collectors/go.d.plugin/modules/unbound/collect.go b/src/go/collectors/go.d.plugin/modules/unbound/collect.go new file mode 100644 index 000000000..125f206ae --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/collect.go @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +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 output []string + var command = "UBCT1 stats" + if u.Cumulative { + command = "UBCT1 stats_noreset" + } + + if err := u.client.Connect(); err != nil { + return nil, fmt.Errorf("failed to connect: %v", err) + } + defer func() { _ = u.client.Disconnect() }() + + err := u.client.Command(command+"\n", func(bytes []byte) bool { + output = append(output, string(bytes)) + return true + }) + 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 <descriptive text possible> \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], 64) + 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/src/go/collectors/go.d.plugin/modules/unbound/config/config.go b/src/go/collectors/go.d.plugin/modules/unbound/config/config.go new file mode 100644 index 000000000..69dc5c219 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/config/config.go @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package config + +import ( + "fmt" + "strings" +) + +// UnboundConfig represents Unbound configuration file. +type UnboundConfig struct { + cumulative string // statistics-cumulative + enable string // control-enable + iface string // control-interface + port string // control-port + useCert string // control-use-cert + keyFile string // control-key-file + certFile string // control-cert-file +} + +func (c UnboundConfig) String() string { + format := strings.Join([]string{ + "[", + `"statistics-cumulative": '%s', `, + `"control-enable": '%s', `, + `"control-interface": '%s', `, + `"control-port": '%s', `, + `"control-user-cert": '%s', `, + `"control-key-file": '%s', `, + `"control-cert-file": '%s'`, + "]", + }, "") + return fmt.Sprintf(format, c.cumulative, c.enable, c.iface, c.port, c.useCert, c.keyFile, c.certFile) +} + +func (c UnboundConfig) Empty() bool { return c == UnboundConfig{} } +func (c UnboundConfig) Cumulative() (bool, bool) { return c.cumulative == "yes", c.cumulative != "" } +func (c UnboundConfig) ControlEnabled() (bool, bool) { return c.enable == "yes", c.enable != "" } +func (c UnboundConfig) ControlInterface() (string, bool) { return c.iface, c.iface != "" } +func (c UnboundConfig) ControlPort() (string, bool) { return c.port, c.port != "" } +func (c UnboundConfig) ControlUseCert() (bool, bool) { return c.useCert == "yes", c.useCert != "" } +func (c UnboundConfig) ControlKeyFile() (string, bool) { return c.keyFile, c.keyFile != "" } +func (c UnboundConfig) ControlCertFile() (string, bool) { return c.certFile, c.certFile != "" } + +func fromOptions(options []option) *UnboundConfig { + cfg := &UnboundConfig{} + for _, opt := range options { + switch opt.name { + default: + case optInterface: + applyControlInterface(cfg, opt.value) + case optCumulative: + cfg.cumulative = opt.value + case optEnable: + cfg.enable = opt.value + case optPort: + cfg.port = opt.value + case optUseCert: + cfg.useCert = opt.value + case optKeyFile: + cfg.keyFile = opt.value + case optCertFile: + cfg.certFile = opt.value + } + } + return cfg +} + +// Unbound doesn't allow to query stats from unix socket when control-interface is enabled on ip interface. +func applyControlInterface(cfg *UnboundConfig, value string) { + if cfg.iface == "" || !isUnixSocket(value) || isUnixSocket(cfg.iface) { + cfg.iface = value + } +} + +func isUnixSocket(address string) bool { + return strings.HasPrefix(address, "/") +} diff --git a/src/go/collectors/go.d.plugin/modules/unbound/config/config_test.go b/src/go/collectors/go.d.plugin/modules/unbound/config/config_test.go new file mode 100644 index 000000000..0375c1368 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/config/config_test.go @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package config + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestUnboundConfig_Empty(t *testing.T) { + assert.True(t, UnboundConfig{}.Empty()) + assert.False(t, UnboundConfig{enable: "yes"}.Empty()) +} + +func TestUnboundConfig_Cumulative(t *testing.T) { + tests := []struct { + input string + wantValue bool + wantOK bool + }{ + {input: "yes", wantValue: true, wantOK: true}, + {input: "no", wantValue: false, wantOK: true}, + {input: "", wantValue: false, wantOK: false}, + {input: "some value", wantValue: false, wantOK: true}, + } + + for _, test := range tests { + t.Run(test.input, func(t *testing.T) { + cfg := UnboundConfig{cumulative: test.input} + + v, ok := cfg.Cumulative() + assert.Equal(t, test.wantValue, v) + assert.Equal(t, test.wantOK, ok) + }) + } +} + +func TestUnboundConfig_ControlEnabled(t *testing.T) { + tests := []struct { + input string + wantValue bool + wantOK bool + }{ + {input: "yes", wantValue: true, wantOK: true}, + {input: "no", wantValue: false, wantOK: true}, + {input: "", wantValue: false, wantOK: false}, + {input: "some value", wantValue: false, wantOK: true}, + } + + for _, test := range tests { + t.Run(test.input, func(t *testing.T) { + cfg := UnboundConfig{enable: test.input} + + v, ok := cfg.ControlEnabled() + assert.Equal(t, test.wantValue, v) + assert.Equal(t, test.wantOK, ok) + }) + } +} + +func TestUnboundConfig_ControlInterface(t *testing.T) { + tests := []struct { + input string + wantValue string + wantOK bool + }{ + {input: "127.0.0.1", wantValue: "127.0.0.1", wantOK: true}, + {input: "/var/run/unbound.sock", wantValue: "/var/run/unbound.sock", wantOK: true}, + {input: "", wantValue: "", wantOK: false}, + {input: "some value", wantValue: "some value", wantOK: true}, + } + + for _, test := range tests { + t.Run(test.input, func(t *testing.T) { + cfg := UnboundConfig{iface: test.input} + + v, ok := cfg.ControlInterface() + assert.Equal(t, test.wantValue, v) + assert.Equal(t, test.wantOK, ok) + }) + } +} + +func TestUnboundConfig_ControlPort(t *testing.T) { + tests := []struct { + input string + wantValue string + wantOK bool + }{ + {input: "8953", wantValue: "8953", wantOK: true}, + {input: "", wantValue: "", wantOK: false}, + {input: "some value", wantValue: "some value", wantOK: true}, + } + + for _, test := range tests { + t.Run(test.input, func(t *testing.T) { + cfg := UnboundConfig{port: test.input} + + v, ok := cfg.ControlPort() + assert.Equal(t, test.wantValue, v) + assert.Equal(t, test.wantOK, ok) + }) + } +} + +func TestUnboundConfig_ControlUseCert(t *testing.T) { + tests := []struct { + input string + wantValue bool + wantOK bool + }{ + {input: "yes", wantValue: true, wantOK: true}, + {input: "no", wantValue: false, wantOK: true}, + {input: "", wantValue: false, wantOK: false}, + {input: "some value", wantValue: false, wantOK: true}, + } + + for _, test := range tests { + t.Run(test.input, func(t *testing.T) { + cfg := UnboundConfig{useCert: test.input} + + v, ok := cfg.ControlUseCert() + assert.Equal(t, test.wantValue, v) + assert.Equal(t, test.wantOK, ok) + }) + } +} + +func TestUnboundConfig_ControlKeyFile(t *testing.T) { + tests := []struct { + input string + wantValue string + wantOK bool + }{ + {input: "/etc/unbound/unbound_control.key", wantValue: "/etc/unbound/unbound_control.key", wantOK: true}, + {input: "", wantValue: "", wantOK: false}, + {input: "some value", wantValue: "some value", wantOK: true}, + } + + for _, test := range tests { + t.Run(test.input, func(t *testing.T) { + cfg := UnboundConfig{keyFile: test.input} + + v, ok := cfg.ControlKeyFile() + assert.Equal(t, test.wantValue, v) + assert.Equal(t, test.wantOK, ok) + }) + } +} + +func TestUnboundConfig_ControlCertFile(t *testing.T) { + tests := []struct { + input string + wantValue string + wantOK bool + }{ + {input: "/etc/unbound/unbound_control.pem", wantValue: "/etc/unbound/unbound_control.pem", wantOK: true}, + {input: "", wantValue: "", wantOK: false}, + {input: "some value", wantValue: "some value", wantOK: true}, + } + + for _, test := range tests { + t.Run(test.input, func(t *testing.T) { + cfg := UnboundConfig{certFile: test.input} + + v, ok := cfg.ControlCertFile() + assert.Equal(t, test.wantValue, v) + assert.Equal(t, test.wantOK, ok) + }) + } +} diff --git a/src/go/collectors/go.d.plugin/modules/unbound/config/parse.go b/src/go/collectors/go.d.plugin/modules/unbound/config/parse.go new file mode 100644 index 000000000..99a632d50 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/config/parse.go @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package config + +import ( + "bufio" + "errors" + "fmt" + "os" + "path/filepath" + "runtime" + "strings" +) + +type option struct{ name, value string } + +const ( + optInclude = "include" + optIncludeToplevel = "include-toplevel" + optCumulative = "statistics-cumulative" + optEnable = "control-enable" + optInterface = "control-interface" + optPort = "control-port" + optUseCert = "control-use-cert" + optKeyFile = "control-key-file" + optCertFile = "control-cert-file" +) + +func isOptionUsed(opt option) bool { + switch opt.name { + case optInclude, + optIncludeToplevel, + optCumulative, + optEnable, + optInterface, + optPort, + optUseCert, + optKeyFile, + optCertFile: + return true + } + return false +} + +// TODO: +// If also using chroot, using full path names for the included files works, relative pathnames for the included names +// work if the directory where the daemon is started equals its chroot/working directory or is specified before +// the include statement with directory: dir. + +// Parse parses Unbound configuration files into UnboundConfig. +// It follows logic described in the 'man unbound.conf': +// - Files can be included using the 'include:' directive. It can appear anywhere, it accepts a single file name as argument. +// - Processing continues as if the text from the included file was copied into the config file at that point. +// - Wildcards can be used to include multiple files. +// +// It stops processing on any error: syntax error, recursive include, glob matches directory etc. +func Parse(entryPath string) (*UnboundConfig, error) { + options, err := parse(entryPath, nil) + if err != nil { + return nil, err + } + return fromOptions(options), nil +} + +func parse(filename string, visited map[string]bool) ([]option, error) { + if visited == nil { + visited = make(map[string]bool) + } + if visited[filename] { + return nil, fmt.Errorf("'%s' already visited", filename) + } + visited[filename] = true + + f, err := open(filename) + if err != nil { + return nil, err + } + defer func() { _ = f.Close() }() + + var options []option + sc := bufio.NewScanner(f) + + for sc.Scan() { + line := strings.TrimSpace(sc.Text()) + if line == "" || strings.HasPrefix(line, "#") { + continue + } + + opt, err := parseLine(line) + if err != nil { + return nil, fmt.Errorf("file '%s', error on parsing line '%s': %v", filename, line, err) + } + + if !isOptionUsed(opt) { + continue + } + + if opt.name != optInclude && opt.name != optIncludeToplevel { + options = append(options, opt) + continue + } + + filenames, err := globInclude(opt.value) + if err != nil { + return nil, err + } + + for _, name := range filenames { + opts, err := parse(name, visited) + if err != nil { + return nil, err + } + options = append(options, opts...) + } + } + return options, nil +} + +func globInclude(include string) ([]string, error) { + if isGlobPattern(include) { + return filepath.Glob(include) + } + return []string{include}, nil +} + +func parseLine(line string) (option, error) { + parts := strings.Split(line, ":") + if len(parts) < 2 { + return option{}, errors.New("bad syntax") + } + key, value := cleanKeyValue(parts[0], parts[1]) + return option{name: key, value: value}, nil +} + +func cleanKeyValue(key, value string) (string, string) { + if i := strings.IndexByte(value, '#'); i > 0 { + value = value[:i-1] + } + key = strings.TrimSpace(key) + value = strings.Trim(strings.TrimSpace(value), "\"'") + return key, value +} + +func isGlobPattern(value string) bool { + magicChars := `*?[` + if runtime.GOOS != "windows" { + magicChars = `*?[\` + } + return strings.ContainsAny(value, magicChars) +} + +func open(filename string) (*os.File, error) { + f, err := os.Open(filename) + if err != nil { + return nil, err + } + fi, err := f.Stat() + if err != nil { + return nil, err + } + if !fi.Mode().IsRegular() { + return nil, fmt.Errorf("'%s' is not a regular file", filename) + } + return f, nil +} diff --git a/src/go/collectors/go.d.plugin/modules/unbound/config/parse_test.go b/src/go/collectors/go.d.plugin/modules/unbound/config/parse_test.go new file mode 100644 index 000000000..72542a861 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/config/parse_test.go @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package config + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestParse(t *testing.T) { + tests := map[string]struct { + path string + wantCfg UnboundConfig + wantErr bool + }{ + "valid include": { + path: "testdata/valid_include.conf", + wantCfg: UnboundConfig{ + cumulative: "yes", + enable: "yes", + iface: "10.0.0.1", + port: "8955", + useCert: "yes", + keyFile: "/etc/unbound/unbound_control_2.key", + certFile: "/etc/unbound/unbound_control_2.pem", + }, + }, + "valid include-toplevel": { + path: "testdata/valid_include_toplevel.conf", + wantCfg: UnboundConfig{ + cumulative: "yes", + enable: "yes", + iface: "10.0.0.1", + port: "8955", + useCert: "yes", + keyFile: "/etc/unbound/unbound_control_2.key", + certFile: "/etc/unbound/unbound_control_2.pem", + }, + }, + "valid glob include": { + path: "testdata/valid_glob.conf", + wantCfg: UnboundConfig{ + cumulative: "yes", + enable: "yes", + iface: "10.0.0.1", + port: "8955", + useCert: "yes", + keyFile: "/etc/unbound/unbound_control_2.key", + certFile: "/etc/unbound/unbound_control_2.pem", + }, + }, + "non existent glob include": { + path: "testdata/non_existent_glob_include.conf", + wantCfg: UnboundConfig{ + cumulative: "yes", + enable: "yes", + iface: "10.0.0.1", + port: "8953", + useCert: "yes", + keyFile: "/etc/unbound/unbound_control.key", + certFile: "/etc/unbound/unbound_control.pem", + }, + }, + "infinite recursion include": { + path: "testdata/infinite_rec.conf", + wantErr: true, + }, + "non existent include": { + path: "testdata/non_existent_include.conf", + wantErr: true, + }, + "non existent path": { + path: "testdata/non_existent_path.conf", + wantErr: true, + }, + } + + for name, test := range tests { + name = fmt.Sprintf("%s (%s)", name, test.path) + t.Run(name, func(t *testing.T) { + cfg, err := Parse(test.path) + + if test.wantErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, test.wantCfg, *cfg) + } + }) + } +} diff --git a/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/infinite_rec.conf b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/infinite_rec.conf new file mode 100644 index 000000000..904f75b30 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/infinite_rec.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: "testdata/infinite_rec.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: 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/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/non_existent_glob_include.conf b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/non_existent_glob_include.conf new file mode 100644 index 000000000..21620f7d5 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/non_existent_glob_include.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: "testdata/__non_existent_glob__*.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: 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/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/non_existent_include.conf b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/non_existent_include.conf new file mode 100644 index 000000000..e493e35bb --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/non_existent_include.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: "testdata/__non_existent_include__.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: 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/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_glob.conf b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_glob.conf new file mode 100644 index 000000000..f020c580a --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_glob.conf @@ -0,0 +1,82 @@ +# +# 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: "testdata/valid_glob[2-3].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: yes + + # enable extended statistics (query types, answer codes, status) + # printed from unbound-control. default off, because of speed. + # extended-statistics: no + + # 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: 8955 + + # 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" + + # 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_2.key" + + # unbound-control certificate file. + # control-cert-file: "/etc/unbound/unbound_control_2.pem" diff --git a/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_glob2.conf b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_glob2.conf new file mode 100644 index 000000000..85bd80e0d --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_glob2.conf @@ -0,0 +1,80 @@ +# +# 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. + +# 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 + + # enable extended statistics (query types, answer codes, status) + # printed from unbound-control. default off, because of speed. + # extended-statistics: no + + # 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: ::1 + control-interface: /var/run/test.sock + + # port number for remote control operations. + # control-port: 8955 + + # 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" + + # 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_2.key" + + # unbound-control certificate file. + control-cert-file: "/etc/unbound/unbound_control_2.pem" diff --git a/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_glob3.conf b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_glob3.conf new file mode 100644 index 000000000..f20eacf1a --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_glob3.conf @@ -0,0 +1,81 @@ +# +# 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. + +# 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 + + # enable extended statistics (query types, answer codes, status) + # printed from unbound-control. default off, because of speed. + # extended-statistics: no + + # 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: 10.0.0.3 + # control-interface: ::1 + # control-interface: /var/run/test.sock + + # port number for remote control operations. + control-port: 8955 + + # 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" + + # 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/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_include.conf b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_include.conf new file mode 100644 index 000000000..1974f6178 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_include.conf @@ -0,0 +1,82 @@ +# +# 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: "testdata/valid_include2.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: yes + + # enable extended statistics (query types, answer codes, status) + # printed from unbound-control. default off, because of speed. + # extended-statistics: no + + # 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: 8955 + + # 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" + + # 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_2.key" + + # unbound-control certificate file. + # control-cert-file: "/etc/unbound/unbound_control_2.pem" diff --git a/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_include2.conf b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_include2.conf new file mode 100644 index 000000000..c956d44d5 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_include2.conf @@ -0,0 +1,81 @@ +# +# 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: "testdata/valid_include3.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 + + # enable extended statistics (query types, answer codes, status) + # printed from unbound-control. default off, because of speed. + # extended-statistics: no + + # 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: ::1 + control-interface: /var/run/test.sock + + # port number for remote control operations. + # control-port: 8955 + + # 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" + + # 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_2.key" + + # unbound-control certificate file. + control-cert-file: "/etc/unbound/unbound_control_2.pem" diff --git a/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_include3.conf b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_include3.conf new file mode 100644 index 000000000..f20eacf1a --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_include3.conf @@ -0,0 +1,81 @@ +# +# 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. + +# 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 + + # enable extended statistics (query types, answer codes, status) + # printed from unbound-control. default off, because of speed. + # extended-statistics: no + + # 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: 10.0.0.3 + # control-interface: ::1 + # control-interface: /var/run/test.sock + + # port number for remote control operations. + control-port: 8955 + + # 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" + + # 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/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_include_toplevel.conf b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_include_toplevel.conf new file mode 100644 index 000000000..9e5675e10 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_include_toplevel.conf @@ -0,0 +1,82 @@ +# +# 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-toplevel: "testdata/valid_include_toplevel2.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: yes + + # enable extended statistics (query types, answer codes, status) + # printed from unbound-control. default off, because of speed. + # extended-statistics: no + + # 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: 8955 + + # 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" + + # 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_2.key" + + # unbound-control certificate file. + # control-cert-file: "/etc/unbound/unbound_control_2.pem" diff --git a/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_include_toplevel2.conf b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_include_toplevel2.conf new file mode 100644 index 000000000..f3f69470d --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_include_toplevel2.conf @@ -0,0 +1,81 @@ +# +# 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-toplevel: "testdata/valid_include_toplevel3.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 + +# enable extended statistics (query types, answer codes, status) +# printed from unbound-control. default off, because of speed. +# extended-statistics: no + +# 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: ::1 + control-interface: /var/run/test.sock + + # port number for remote control operations. + # control-port: 8955 + + # 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" + + # 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_2.key" + + # unbound-control certificate file. + control-cert-file: "/etc/unbound/unbound_control_2.pem" diff --git a/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_include_toplevel3.conf b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_include_toplevel3.conf new file mode 100644 index 000000000..d30778c01 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/config/testdata/valid_include_toplevel3.conf @@ -0,0 +1,81 @@ +# +# 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. + +# 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 + +# enable extended statistics (query types, answer codes, status) +# printed from unbound-control. default off, because of speed. +# extended-statistics: no + +# 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: 10.0.0.3 + # control-interface: ::1 + # control-interface: /var/run/test.sock + + # port number for remote control operations. + control-port: 8955 + + # 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" + + # 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/src/go/collectors/go.d.plugin/modules/unbound/config_schema.json b/src/go/collectors/go.d.plugin/modules/unbound/config_schema.json new file mode 100644 index 000000000..500b60169 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/config_schema.json @@ -0,0 +1,113 @@ +{ + "jsonSchema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Unbound collector configuration.", + "type": "object", + "properties": { + "update_every": { + "title": "Update every", + "description": "Data collection interval, measured in seconds.", + "type": "integer", + "minimum": 1, + "default": 1 + }, + "address": { + "title": "Address", + "description": "The IP address and port where the Unbound server listens for connections.", + "type": "string", + "default": "127.0.0.1:8953" + }, + "timeout": { + "title": "Timeout", + "description": "The timeout duration, in seconds, for connection, read, write, and SSL handshake operations.", + "type": "number", + "minimum": 0.5, + "default": 1 + }, + "conf_path": { + "title": "Path to unbound.conf", + "description": "The absolute path to the Unbound configuration file. Providing this path enables the tool to make adjustments based on the 'remote-control' section.", + "type": "string", + "default": "/etc/unbound/unbound.conf" + }, + "cumulative_stats": { + "title": "Cumulative stats", + "description": "Specifies whether statistics collection mode is enabled. Should match the 'statistics-cumulative' parameter in unbound.conf.", + "type": "boolean", + "default": false + }, + "use_tls": { + "title": "Use TLS", + "description": "Indicates whether TLS should be used for secure communication.", + "type": "boolean", + "default": true + }, + "tls_skip_verify": { + "title": "Skip TLS verification", + "description": "If set, TLS certificate verification will be skipped.", + "type": "boolean", + "default": true + }, + "tls_ca": { + "title": "TLS CA", + "description": "The path to the CA certificate file for TLS verification.", + "type": "string", + "pattern": "^$|^/" + }, + "tls_cert": { + "title": "TLS certificate", + "description": "The path to the client certificate file for TLS authentication.", + "type": "string", + "default": "/etc/unbound/unbound_control.pem", + "pattern": "^$|^/" + }, + "tls_key": { + "title": "TLS key", + "description": "The path to the client key file for TLS authentication.", + "type": "string", + "default": "/etc/unbound/unbound_control.key", + "pattern": "^$|^/" + } + }, + "required": [ + "address" + ], + "additionalProperties": false, + "patternProperties": { + "^name$": {} + } + }, + "uiSchema": { + "uiOptions": { + "fullPage": true + }, + "timeout": { + "ui:help": "Accepts decimals for precise control (e.g., type 1.5 for 1.5 seconds)." + }, + "ui:flavour": "tabs", + "ui:options": { + "tabs": [ + { + "title": "Base", + "fields": [ + "update_every", + "address", + "timeout", + "conf_path", + "cumulative_stats" + ] + }, + { + "title": "TLS", + "fields": [ + "use_tls", + "tls_skip_verify", + "tls_ca", + "tls_cert", + "tls_key" + ] + } + ] + } + } +} diff --git a/src/go/collectors/go.d.plugin/modules/unbound/init.go b/src/go/collectors/go.d.plugin/modules/unbound/init.go new file mode 100644 index 000000000..066315400 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/init.go @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package unbound + +import ( + "crypto/tls" + "errors" + "net" + + "github.com/netdata/netdata/go/go.d.plugin/modules/unbound/config" + "github.com/netdata/netdata/go/go.d.plugin/pkg/socket" + "github.com/netdata/netdata/go/go.d.plugin/pkg/tlscfg" +) + +func (u *Unbound) initConfig() (enabled bool) { + if u.ConfPath == "" { + u.Info("'conf_path' not set, skipping parameters auto detection") + return true + } + + u.Infof("reading '%s'", u.ConfPath) + cfg, err := config.Parse(u.ConfPath) + if err != nil { + u.Warningf("%v, skipping parameters auto detection", err) + return true + } + + if cfg.Empty() { + u.Debug("empty configuration") + return true + } + + if enabled, ok := cfg.ControlEnabled(); ok && !enabled { + u.Info("remote control is disabled in the configuration file") + return false + } + + u.applyConfig(cfg) + return true +} + +func (u *Unbound) applyConfig(cfg *config.UnboundConfig) { + u.Infof("applying configuration: %s", cfg) + if cumulative, ok := cfg.Cumulative(); ok && cumulative != u.Cumulative { + u.Debugf("changing 'cumulative_stats': %v => %v", u.Cumulative, cumulative) + u.Cumulative = cumulative + } + if useCert, ok := cfg.ControlUseCert(); ok && useCert != u.UseTLS { + u.Debugf("changing 'use_tls': %v => %v", u.UseTLS, useCert) + u.UseTLS = useCert + } + if keyFile, ok := cfg.ControlKeyFile(); ok && keyFile != u.TLSKey { + u.Debugf("changing 'tls_key': '%s' => '%s'", u.TLSKey, keyFile) + u.TLSKey = keyFile + } + if certFile, ok := cfg.ControlCertFile(); ok && certFile != u.TLSCert { + u.Debugf("changing 'tls_cert': '%s' => '%s'", u.TLSCert, certFile) + u.TLSCert = certFile + } + if iface, ok := cfg.ControlInterface(); ok && adjustControlInterface(iface) != u.Address { + address := adjustControlInterface(iface) + u.Debugf("changing 'address': '%s' => '%s'", u.Address, address) + u.Address = address + } + if port, ok := cfg.ControlPort(); ok && !socket.IsUnixSocket(u.Address) { + if host, curPort, err := net.SplitHostPort(u.Address); err == nil && curPort != port { + address := net.JoinHostPort(host, port) + u.Debugf("changing 'address': '%s' => '%s'", u.Address, address) + u.Address = address + } + } +} + +func (u *Unbound) initClient() (err error) { + var tlsCfg *tls.Config + useTLS := !socket.IsUnixSocket(u.Address) && u.UseTLS + + if useTLS && (u.TLSConfig.TLSCert == "" || u.TLSConfig.TLSKey == "") { + return errors.New("'tls_cert' or 'tls_key' is missing") + } + + if useTLS { + if tlsCfg, err = tlscfg.NewTLSConfig(u.TLSConfig); err != nil { + return err + } + } + + u.client = socket.New(socket.Config{ + Address: u.Address, + ConnectTimeout: u.Timeout.Duration(), + ReadTimeout: u.Timeout.Duration(), + WriteTimeout: u.Timeout.Duration(), + TLSConf: tlsCfg, + }) + return nil +} + +func adjustControlInterface(value string) string { + if socket.IsUnixSocket(value) { + return value + } + if value == "0.0.0.0" { + value = "127.0.0.1" + } + return net.JoinHostPort(value, "8953") +} diff --git a/src/go/collectors/go.d.plugin/modules/unbound/integrations/unbound.md b/src/go/collectors/go.d.plugin/modules/unbound/integrations/unbound.md new file mode 100644 index 000000000..f934e6660 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/integrations/unbound.md @@ -0,0 +1,270 @@ +<!--startmeta +custom_edit_url: "https://github.com/netdata/netdata/edit/master/src/go/collectors/go.d.plugin/modules/unbound/README.md" +meta_yaml: "https://github.com/netdata/netdata/edit/master/src/go/collectors/go.d.plugin/modules/unbound/metadata.yaml" +sidebar_label: "Unbound" +learn_status: "Published" +learn_rel_path: "Collecting Metrics/DNS and DHCP Servers" +most_popular: False +message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE COLLECTOR'S metadata.yaml FILE" +endmeta--> + +# Unbound + + +<img src="https://netdata.cloud/img/unbound.png" width="150"/> + + +Plugin: go.d.plugin +Module: unbound + +<img src="https://img.shields.io/badge/maintained%20by-Netdata-%2300ab44" /> + +## Overview + +This collector monitors Unbound servers. + + + + +This collector is supported on all platforms. + +This collector supports collecting metrics from multiple instances of this integration, including remote instances. + + +### Default Behavior + +#### Auto-Detection + +This integration doesn't support auto-detection. + +#### Limits + +The default configuration for this integration does not impose any limits on data collection. + +#### Performance Impact + +The default configuration for this integration is not expected to impose a significant performance impact on the system. + + +## Metrics + +Metrics grouped by *scope*. + +The scope defines the instance that the metric belongs to. An instance is uniquely identified by a set of labels. + + + +### Per Unbound instance + +These metrics refer to the entire monitored application. + +This scope has no labels. + +Metrics: + +| Metric | Dimensions | Unit | +|:------|:----------|:----| +| unbound.queries | queries | queries | +| unbound.queries_ip_ratelimited | ratelimited | queries | +| unbound.dnscrypt_queries | crypted, cert, cleartext, malformed | queries | +| unbound.cache | hits, miss | events | +| unbound.cache_percentage | hits, miss | percentage | +| unbound.prefetch | prefetches | prefetches | +| unbound.expired | expired | replies | +| unbound.zero_ttl_replies | zero_ttl | replies | +| unbound.recursive_replies | recursive | replies | +| unbound.recursion_time | avg, median | milliseconds | +| unbound.request_list_usage | avg, max | queries | +| unbound.current_request_list_usage | all, users | queries | +| unbound.request_list_jostle_list | overwritten, dropped | queries | +| unbound.tcpusage | usage | buffers | +| unbound.uptime | time | seconds | +| unbound.cache_memory | message, rrset, dnscrypt_nonce, dnscrypt_shared_secret | KB | +| unbound.mod_memory | iterator, respip, validator, subnet, ipsec | KB | +| unbound.mem_streamwait | streamwait | KB | +| unbound.cache_count | infra, key, msg, rrset, dnscrypt_nonce, shared_secret | items | +| unbound.type_queries | a dimension per query type | queries | +| unbound.class_queries | a dimension per query class | queries | +| unbound.opcode_queries | a dimension per query opcode | queries | +| unbound.flag_queries | qr, aa, tc, rd, ra, z, ad, cd | queries | +| unbound.rcode_answers | a dimension per reply rcode | replies | + +### Per thread + +These metrics refer to threads. + +This scope has no labels. + +Metrics: + +| Metric | Dimensions | Unit | +|:------|:----------|:----| +| unbound.thread_queries | queries | queries | +| unbound.thread_queries_ip_ratelimited | ratelimited | queries | +| unbound.thread_dnscrypt_queries | crypted, cert, cleartext, malformed | queries | +| unbound.thread_cache | hits, miss | events | +| unbound.thread_cache_percentage | hits, miss | percentage | +| unbound.thread_prefetch | prefetches | prefetches | +| unbound.thread_expired | expired | replies | +| unbound.thread_zero_ttl_replies | zero_ttl | replies | +| unbound.thread_recursive_replies | recursive | replies | +| unbound.thread_recursion_time | avg, median | milliseconds | +| unbound.thread_request_list_usage | avg, max | queries | +| unbound.thread_current_request_list_usage | all, users | queries | +| unbound.thread_request_list_jostle_list | overwritten, dropped | queries | +| unbound.thread_tcpusage | usage | buffers | + + + +## Alerts + +There are no alerts configured by default for this integration. + + +## Setup + +### Prerequisites + +#### Enable remote control interface + +Set `control-enable` to yes in [unbound.conf](https://nlnetlabs.nl/documentation/unbound/unbound.conf). + + +#### Check permissions and adjust if necessary + +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 +- if you have several configuration files (include feature) all of them should be readable by `netdata` user + + + +### Configuration + +#### File + +The configuration file name for this integration is `go.d/unbound.conf`. + + +You can edit the configuration file using the `edit-config` script from the +Netdata [config directory](/docs/netdata-agent/configuration/README.md#the-netdata-config-directory). + +```bash +cd /etc/netdata 2>/dev/null || cd /opt/netdata/etc/netdata +sudo ./edit-config go.d/unbound.conf +``` +#### Options + +The following options can be defined globally: update_every, autodetection_retry. + + +<details open><summary>Config options</summary> + +| Name | Description | Default | Required | +|:----|:-----------|:-------|:--------:| +| update_every | Data collection frequency. | 5 | no | +| autodetection_retry | Recheck interval in seconds. Zero means no recheck will be scheduled. | 0 | no | +| address | Server address in IP:PORT format. | 127.0.0.1:8953 | yes | +| timeout | Connection/read/write/ssl handshake timeout. | 1 | no | +| conf_path | Absolute path to the unbound configuration file. | /etc/unbound/unbound.conf | no | +| cumulative_stats | Statistics collection mode. Should have the same value as the `statistics-cumulative` parameter in the unbound configuration file. | no | no | +| use_tls | Whether to use TLS or not. | yes | no | +| tls_skip_verify | Server certificate chain and hostname validation policy. Controls whether the client performs this check. | yes | no | +| tls_ca | Certificate authority that client use when verifying server certificates. | | no | +| tls_cert | Client tls certificate. | /etc/unbound/unbound_control.pem | no | +| tls_key | Client tls key. | /etc/unbound/unbound_control.key | no | + +</details> + +#### Examples + +##### Basic + +An example configuration. + +<details open><summary>Config</summary> + +```yaml +jobs: + - name: local + address: 127.0.0.1:8953 + +``` +</details> + +##### Unix socket + +Connecting through Unix socket. + +<details open><summary>Config</summary> + +```yaml +jobs: + - name: socket + address: /var/run/unbound.sock + +``` +</details> + +##### Multi-instance + +> **Note**: When you define multiple jobs, their names must be unique. + +Local and remote instances. + + +<details open><summary>Config</summary> + +```yaml +jobs: + - name: local + address: 127.0.0.1:8953 + + - name: remote + address: 203.0.113.11:8953 + +``` +</details> + + + +## Troubleshooting + +### Debug Mode + +To troubleshoot issues with the `unbound` collector, run the `go.d.plugin` with the debug option enabled. The output +should give you clues as to why the collector isn't working. + +- Navigate to the `plugins.d` directory, usually at `/usr/libexec/netdata/plugins.d/`. If that's not the case on + your system, open `netdata.conf` and look for the `plugins` setting under `[directories]`. + + ```bash + cd /usr/libexec/netdata/plugins.d/ + ``` + +- Switch to the `netdata` user. + + ```bash + sudo -u netdata -s + ``` + +- Run the `go.d.plugin` to debug the collector: + + ```bash + ./go.d.plugin -d -m unbound + ``` + + diff --git a/src/go/collectors/go.d.plugin/modules/unbound/metadata.yaml b/src/go/collectors/go.d.plugin/modules/unbound/metadata.yaml new file mode 100644 index 000000000..ec6e6538d --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/metadata.yaml @@ -0,0 +1,431 @@ +plugin_name: go.d.plugin +modules: + - meta: + id: collector-go.d.plugin-unbound + plugin_name: go.d.plugin + module_name: unbound + monitored_instance: + name: Unbound + link: https://nlnetlabs.nl/projects/unbound/about/ + icon_filename: unbound.png + categories: + - data-collection.dns-and-dhcp-servers + keywords: + - unbound + - dns + related_resources: + integrations: + list: [] + info_provided_to_referring_integrations: + description: "" + most_popular: false + overview: + data_collection: + metrics_description: | + This collector monitors Unbound servers. + method_description: "" + supported_platforms: + include: [] + exclude: [] + multi_instance: true + additional_permissions: + description: "" + default_behavior: + auto_detection: + description: "" + limits: + description: "" + performance_impact: + description: "" + setup: + prerequisites: + list: + - title: Enable remote control interface + description: | + Set `control-enable` to yes in [unbound.conf](https://nlnetlabs.nl/documentation/unbound/unbound.conf). + - title: Check permissions and adjust if necessary + description: | + 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 + - if you have several configuration files (include feature) all of them should be readable by `netdata` user + configuration: + file: + name: go.d/unbound.conf + options: + description: | + The following options can be defined globally: update_every, autodetection_retry. + folding: + title: Config options + enabled: true + list: + - name: update_every + description: Data collection frequency. + default_value: 5 + required: false + - name: autodetection_retry + description: Recheck interval in seconds. Zero means no recheck will be scheduled. + default_value: 0 + required: false + - name: address + description: Server address in IP:PORT format. + default_value: 127.0.0.1:8953 + required: true + - name: timeout + description: Connection/read/write/ssl handshake timeout. + default_value: 1 + required: false + - name: conf_path + description: Absolute path to the unbound configuration file. + default_value: /etc/unbound/unbound.conf + required: false + - name: cumulative_stats + description: Statistics collection mode. Should have the same value as the `statistics-cumulative` parameter in the unbound configuration file. + default_value: false + required: false + - name: use_tls + description: Whether to use TLS or not. + default_value: true + required: false + - name: tls_skip_verify + description: Server certificate chain and hostname validation policy. Controls whether the client performs this check. + default_value: true + required: false + - name: tls_ca + description: Certificate authority that client use when verifying server certificates. + default_value: "" + required: false + - name: tls_cert + description: Client tls certificate. + default_value: /etc/unbound/unbound_control.pem + required: false + - name: tls_key + description: Client tls key. + default_value: /etc/unbound/unbound_control.key + required: false + examples: + folding: + title: Config + enabled: true + list: + - name: Basic + description: An example configuration. + config: | + jobs: + - name: local + address: 127.0.0.1:8953 + - name: Unix socket + description: Connecting through Unix socket. + config: | + jobs: + - name: socket + address: /var/run/unbound.sock + - name: Multi-instance + description: | + > **Note**: When you define multiple jobs, their names must be unique. + + Local and remote instances. + config: | + jobs: + - name: local + address: 127.0.0.1:8953 + + - name: remote + address: 203.0.113.11:8953 + troubleshooting: + problems: + list: [] + alerts: [] + metrics: + folding: + title: Metrics + enabled: false + description: "" + availability: [] + scopes: + - name: global + description: These metrics refer to the entire monitored application. + labels: [] + metrics: + - name: unbound.queries + description: Received Queries + unit: queries + chart_type: line + dimensions: + - name: queries + - name: unbound.queries_ip_ratelimited + description: Rate Limited Queries + unit: queries + chart_type: line + dimensions: + - name: ratelimited + - name: unbound.dnscrypt_queries + description: DNSCrypt Queries + unit: queries + chart_type: line + dimensions: + - name: crypted + - name: cert + - name: cleartext + - name: malformed + - name: unbound.cache + description: Cache Statistics + unit: events + chart_type: stacked + dimensions: + - name: hits + - name: miss + - name: unbound.cache_percentage + description: Cache Statistics Percentage + unit: percentage + chart_type: stacked + dimensions: + - name: hits + - name: miss + - name: unbound.prefetch + description: Cache Prefetches + unit: prefetches + chart_type: line + dimensions: + - name: prefetches + - name: unbound.expired + description: Replies Served From Expired Cache + unit: replies + chart_type: line + dimensions: + - name: expired + - name: unbound.zero_ttl_replies + description: Replies Served From Expired Cache + unit: replies + chart_type: line + dimensions: + - name: zero_ttl + - name: unbound.recursive_replies + description: Replies That Needed Recursive Processing + unit: replies + chart_type: line + dimensions: + - name: recursive + - name: unbound.recursion_time + description: Time Spent On Recursive Processing + unit: milliseconds + chart_type: line + dimensions: + - name: avg + - name: median + - name: unbound.request_list_usage + description: Request List Usage + unit: queries + chart_type: line + dimensions: + - name: avg + - name: max + - name: unbound.current_request_list_usage + description: Current Request List Usage + unit: queries + chart_type: area + dimensions: + - name: all + - name: users + - name: unbound.request_list_jostle_list + description: Request List Jostle List Events + unit: queries + chart_type: line + dimensions: + - name: overwritten + - name: dropped + - name: unbound.tcpusage + description: TCP Handler Buffers + unit: buffers + chart_type: line + dimensions: + - name: usage + - name: unbound.uptime + description: Uptime + unit: seconds + chart_type: line + dimensions: + - name: time + - name: unbound.cache_memory + description: Cache Memory + unit: KB + chart_type: stacked + dimensions: + - name: message + - name: rrset + - name: dnscrypt_nonce + - name: dnscrypt_shared_secret + - name: unbound.mod_memory + description: Module Memory + unit: KB + chart_type: stacked + dimensions: + - name: iterator + - name: respip + - name: validator + - name: subnet + - name: ipsec + - name: unbound.mem_streamwait + description: TCP and TLS Stream Waif Buffer Memory + unit: KB + chart_type: line + dimensions: + - name: streamwait + - name: unbound.cache_count + description: Cache Items Count + unit: items + chart_type: stacked + dimensions: + - name: infra + - name: key + - name: msg + - name: rrset + - name: dnscrypt_nonce + - name: shared_secret + - name: unbound.type_queries + description: Queries By Type + unit: queries + chart_type: stacked + dimensions: + - name: a dimension per query type + - name: unbound.class_queries + description: Queries By Class + unit: queries + chart_type: stacked + dimensions: + - name: a dimension per query class + - name: unbound.opcode_queries + description: Queries By OpCode + unit: queries + chart_type: stacked + dimensions: + - name: a dimension per query opcode + - name: unbound.flag_queries + description: Queries By Flag + unit: queries + chart_type: stacked + dimensions: + - name: qr + - name: aa + - name: tc + - name: rd + - name: ra + - name: z + - name: ad + - name: cd + - name: unbound.rcode_answers + description: Replies By RCode + unit: replies + chart_type: stacked + dimensions: + - name: a dimension per reply rcode + - name: thread + description: These metrics refer to threads. + labels: [] + metrics: + - name: unbound.thread_queries + description: Thread Received Queries + unit: queries + chart_type: line + dimensions: + - name: queries + - name: unbound.thread_queries_ip_ratelimited + description: Thread Rate Limited Queries + unit: queries + chart_type: line + dimensions: + - name: ratelimited + - name: unbound.thread_dnscrypt_queries + description: Thread DNSCrypt Queries + unit: queries + chart_type: line + dimensions: + - name: crypted + - name: cert + - name: cleartext + - name: malformed + - name: unbound.thread_cache + description: Cache Statistics + unit: events + chart_type: line + dimensions: + - name: hits + - name: miss + - name: unbound.thread_cache_percentage + description: Cache Statistics Percentage + unit: percentage + chart_type: line + dimensions: + - name: hits + - name: miss + - name: unbound.thread_prefetch + description: Cache Prefetches + unit: prefetches + chart_type: line + dimensions: + - name: prefetches + - name: unbound.thread_expired + description: Replies Served From Expired Cache + unit: replies + chart_type: line + dimensions: + - name: expired + - name: unbound.thread_zero_ttl_replies + description: Replies Served From Expired Cache + unit: replies + chart_type: line + dimensions: + - name: zero_ttl + - name: unbound.thread_recursive_replies + description: Replies That Needed Recursive Processing + unit: replies + chart_type: line + dimensions: + - name: recursive + - name: unbound.thread_recursion_time + description: Time Spent On Recursive Processing + unit: milliseconds + chart_type: line + dimensions: + - name: avg + - name: median + - name: unbound.thread_request_list_usage + description: Time Spent On Recursive Processing + unit: queries + chart_type: line + dimensions: + - name: avg + - name: max + - name: unbound.thread_current_request_list_usage + description: Current Request List Usage + unit: queries + chart_type: line + dimensions: + - name: all + - name: users + - name: unbound.thread_request_list_jostle_list + description: Request List Jostle List Events + unit: queries + chart_type: line + dimensions: + - name: overwritten + - name: dropped + - name: unbound.thread_tcpusage + description: TCP Handler Buffers + unit: buffers + chart_type: line + dimensions: + - name: usage diff --git a/src/go/collectors/go.d.plugin/modules/unbound/testdata/config.json b/src/go/collectors/go.d.plugin/modules/unbound/testdata/config.json new file mode 100644 index 000000000..9874de180 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/testdata/config.json @@ -0,0 +1,12 @@ +{ + "update_every": 123, + "address": "ok", + "conf_path": "ok", + "timeout": 123.123, + "cumulative_stats": true, + "use_tls": true, + "tls_ca": "ok", + "tls_cert": "ok", + "tls_key": "ok", + "tls_skip_verify": true +} diff --git a/src/go/collectors/go.d.plugin/modules/unbound/testdata/config.yaml b/src/go/collectors/go.d.plugin/modules/unbound/testdata/config.yaml new file mode 100644 index 000000000..68326cabc --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/testdata/config.yaml @@ -0,0 +1,10 @@ +update_every: 123 +address: "ok" +conf_path: "ok" +timeout: 123.123 +cumulative_stats: yes +use_tls: yes +tls_ca: "ok" +tls_cert: "ok" +tls_key: "ok" +tls_skip_verify: yes diff --git a/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/common.txt b/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/common.txt new file mode 100644 index 000000000..7a1f91a31 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/common.txt @@ -0,0 +1,66 @@ +thread0.num.queries=28 +thread0.num.queries_ip_ratelimited=0 +thread0.num.cachehits=21 +thread0.num.cachemiss=7 +thread0.num.prefetch=0 +thread0.num.expired=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.expired=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.expired=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/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/extended.txt b/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/extended.txt new file mode 100644 index 000000000..578794fad --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/extended.txt @@ -0,0 +1,162 @@ +thread0.num.queries=28 +thread0.num.queries_ip_ratelimited=0 +thread0.num.cachehits=21 +thread0.num.cachemiss=7 +thread0.num.prefetch=0 +thread0.num.expired=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.expired=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.expired=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/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/lifecycle/cumulative/extended1.txt b/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/lifecycle/cumulative/extended1.txt new file mode 100644 index 000000000..53bd7f955 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/lifecycle/cumulative/extended1.txt @@ -0,0 +1,162 @@ +thread0.num.queries=90 +thread0.num.queries_ip_ratelimited=0 +thread0.num.cachehits=80 +thread0.num.cachemiss=10 +thread0.num.prefetch=0 +thread0.num.expired=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.expired=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.expired=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/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/lifecycle/cumulative/extended2.txt b/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/lifecycle/cumulative/extended2.txt new file mode 100644 index 000000000..939ba75de --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/lifecycle/cumulative/extended2.txt @@ -0,0 +1,162 @@ +thread0.num.queries=133 +thread0.num.queries_ip_ratelimited=0 +thread0.num.cachehits=123 +thread0.num.cachemiss=10 +thread0.num.prefetch=0 +thread0.num.expired=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.expired=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.expired=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/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/lifecycle/cumulative/extended3.txt b/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/lifecycle/cumulative/extended3.txt new file mode 100644 index 000000000..e9448f7d7 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/lifecycle/cumulative/extended3.txt @@ -0,0 +1,163 @@ +thread0.num.queries=165 +thread0.num.queries_ip_ratelimited=0 +thread0.num.cachehits=150 +thread0.num.cachemiss=15 +thread0.num.prefetch=0 +thread0.num.expired=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.expired=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.expired=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/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/lifecycle/reset/extended1.txt b/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/lifecycle/reset/extended1.txt new file mode 100644 index 000000000..8be40ecb2 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/lifecycle/reset/extended1.txt @@ -0,0 +1,163 @@ +thread0.num.queries=51 +thread0.num.queries_ip_ratelimited=0 +thread0.num.cachehits=44 +thread0.num.cachemiss=7 +thread0.num.prefetch=0 +thread0.num.expired=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.expired=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.expired=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/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/lifecycle/reset/extended2.txt b/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/lifecycle/reset/extended2.txt new file mode 100644 index 000000000..08ff128b3 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/lifecycle/reset/extended2.txt @@ -0,0 +1,156 @@ +thread0.num.queries=0 +thread0.num.queries_ip_ratelimited=0 +thread0.num.cachehits=0 +thread0.num.cachemiss=0 +thread0.num.prefetch=0 +thread0.num.expired=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.expired=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.expired=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/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/lifecycle/reset/extended3.txt b/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/lifecycle/reset/extended3.txt new file mode 100644 index 000000000..45324bef9 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/testdata/stats/lifecycle/reset/extended3.txt @@ -0,0 +1,163 @@ +thread0.num.queries=34 +thread0.num.queries_ip_ratelimited=0 +thread0.num.cachehits=30 +thread0.num.cachemiss=4 +thread0.num.prefetch=0 +thread0.num.expired=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.expired=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.expired=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/src/go/collectors/go.d.plugin/modules/unbound/testdata/unbound.conf b/src/go/collectors/go.d.plugin/modules/unbound/testdata/unbound.conf new file mode 100644 index 000000000..a061a3476 --- /dev/null +++ b/src/go/collectors/go.d.plugin/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/src/go/collectors/go.d.plugin/modules/unbound/testdata/unbound_disabled.conf b/src/go/collectors/go.d.plugin/modules/unbound/testdata/unbound_disabled.conf new file mode 100644 index 000000000..1cef549f8 --- /dev/null +++ b/src/go/collectors/go.d.plugin/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/src/go/collectors/go.d.plugin/modules/unbound/testdata/unbound_empty.conf b/src/go/collectors/go.d.plugin/modules/unbound/testdata/unbound_empty.conf new file mode 100644 index 000000000..a2d158376 --- /dev/null +++ b/src/go/collectors/go.d.plugin/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/src/go/collectors/go.d.plugin/modules/unbound/unbound.go b/src/go/collectors/go.d.plugin/modules/unbound/unbound.go new file mode 100644 index 000000000..7536aed3c --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/unbound.go @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package unbound + +import ( + _ "embed" + "errors" + "time" + + "github.com/netdata/netdata/go/go.d.plugin/agent/module" + "github.com/netdata/netdata/go/go.d.plugin/pkg/socket" + "github.com/netdata/netdata/go/go.d.plugin/pkg/tlscfg" + "github.com/netdata/netdata/go/go.d.plugin/pkg/web" +) + +//go:embed "config_schema.json" +var configSchema string + +func init() { + module.Register("unbound", module.Creator{ + JobConfigSchema: configSchema, + Create: func() module.Module { return New() }, + Config: func() any { return &Config{} }, + }) +} + +func New() *Unbound { + return &Unbound{ + Config: Config{ + Address: "127.0.0.1:8953", + ConfPath: "/etc/unbound/unbound.conf", + Timeout: web.Duration(time.Second), + Cumulative: false, + UseTLS: true, + TLSConfig: tlscfg.TLSConfig{ + TLSCert: "/etc/unbound/unbound_control.pem", + TLSKey: "/etc/unbound/unbound_control.key", + InsecureSkipVerify: true, + }, + }, + curCache: newCollectCache(), + cache: newCollectCache(), + } +} + +type Config struct { + UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"` + Address string `yaml:"address" json:"address"` + ConfPath string `yaml:"conf_path,omitempty" json:"conf_path"` + Timeout web.Duration `yaml:"timeout,omitempty" json:"timeout"` + Cumulative bool `yaml:"cumulative_stats" json:"cumulative_stats"` + UseTLS bool `yaml:"use_tls,omitempty" json:"use_tls"` + tlscfg.TLSConfig `yaml:",inline" json:""` +} + +type Unbound struct { + module.Base + Config `yaml:",inline" json:""` + + charts *module.Charts + + client socket.Client + + cache collectCache + curCache collectCache + prevCacheMiss float64 // needed for cumulative mode + extChartsCreated bool +} + +func (u *Unbound) Configuration() any { + return u.Config +} + +func (u *Unbound) Init() error { + if enabled := u.initConfig(); !enabled { + return errors.New("remote control is disabled in the configuration file") + } + + if err := u.initClient(); err != nil { + u.Errorf("creating client: %v", err) + return err + } + + 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 nil +} + +func (u *Unbound) Check() error { + mx, err := u.collect() + if err != nil { + u.Error(err) + return err + } + if len(mx) == 0 { + return errors.New("no metrics collected") + } + return nil +} + +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 +} + +func (u *Unbound) Cleanup() { + if u.client != nil { + _ = u.client.Disconnect() + } +} diff --git a/src/go/collectors/go.d.plugin/modules/unbound/unbound_test.go b/src/go/collectors/go.d.plugin/modules/unbound/unbound_test.go new file mode 100644 index 000000000..2d24b67b1 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/unbound/unbound_test.go @@ -0,0 +1,1288 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package unbound + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "os" + "strings" + "testing" + + "github.com/netdata/netdata/go/go.d.plugin/agent/module" + "github.com/netdata/netdata/go/go.d.plugin/pkg/socket" + "github.com/netdata/netdata/go/go.d.plugin/pkg/tlscfg" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + dataConfigJSON, _ = os.ReadFile("testdata/config.json") + dataConfigYAML, _ = os.ReadFile("testdata/config.yaml") + + dataCommonStats, _ = os.ReadFile("testdata/stats/common.txt") + dataExtendedStats, _ = os.ReadFile("testdata/stats/extended.txt") + dataLifeCycleCumulative1, _ = os.ReadFile("testdata/stats/lifecycle/cumulative/extended1.txt") + dataLifeCycleCumulative2, _ = os.ReadFile("testdata/stats/lifecycle/cumulative/extended2.txt") + dataLifeCycleCumulative3, _ = os.ReadFile("testdata/stats/lifecycle/cumulative/extended3.txt") + dataLifeCycleReset1, _ = os.ReadFile("testdata/stats/lifecycle/reset/extended1.txt") + dataLifeCycleReset2, _ = os.ReadFile("testdata/stats/lifecycle/reset/extended2.txt") + dataLifeCycleReset3, _ = os.ReadFile("testdata/stats/lifecycle/reset/extended3.txt") +) + +func Test_testDataIsValid(t *testing.T) { + for name, data := range map[string][]byte{ + "dataConfigJSON": dataConfigJSON, + "dataConfigYAML": dataConfigYAML, + "dataCommonStats": dataCommonStats, + "dataExtendedStats": dataExtendedStats, + "dataLifeCycleCumulative1": dataLifeCycleCumulative1, + "dataLifeCycleCumulative2": dataLifeCycleCumulative2, + "dataLifeCycleCumulative3": dataLifeCycleCumulative3, + "dataLifeCycleReset1": dataLifeCycleReset1, + "dataLifeCycleReset2": dataLifeCycleReset2, + "dataLifeCycleReset3": dataLifeCycleReset3, + } { + require.NotNil(t, data, name) + } +} + +func TestUnbound_ConfigurationSerialize(t *testing.T) { + module.TestConfigurationSerialize(t, &Unbound{}, dataConfigJSON, dataConfigYAML) +} + +func TestUnbound_Init(t *testing.T) { + unbound := prepareNonTLSUnbound() + + assert.NoError(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, + TLSConfig: tlscfg.TLSConfig{ + TLSCert: "/etc/unbound/unbound_control_other.pem", + TLSKey: "/etc/unbound/unbound_control_other.key", + InsecureSkipVerify: unbound.TLSConfig.InsecureSkipVerify, + }, + } + + assert.NoError(t, unbound.Init()) + assert.Equal(t, expectedConfig, unbound.Config) +} + +func TestUnbound_Init_DisabledInUnboundConf(t *testing.T) { + unbound := prepareNonTLSUnbound() + unbound.ConfPath = "testdata/unbound_disabled.conf" + + assert.Error(t, unbound.Init()) +} + +func TestUnbound_Init_HandleEmptyConfig(t *testing.T) { + unbound := prepareNonTLSUnbound() + unbound.ConfPath = "testdata/unbound_empty.conf" + + assert.NoError(t, unbound.Init()) +} + +func TestUnbound_Init_HandleNonExistentConfig(t *testing.T) { + unbound := prepareNonTLSUnbound() + unbound.ConfPath = "testdata/unbound_non_existent.conf" + + assert.NoError(t, unbound.Init()) +} + +func TestUnbound_Check(t *testing.T) { + unbound := prepareNonTLSUnbound() + require.NoError(t, unbound.Init()) + unbound.client = mockUnboundClient{data: dataCommonStats, err: false} + + assert.NoError(t, unbound.Check()) +} + +func TestUnbound_Check_ErrorDuringScrapingUnbound(t *testing.T) { + unbound := prepareNonTLSUnbound() + require.NoError(t, unbound.Init()) + unbound.client = mockUnboundClient{err: true} + + assert.Error(t, unbound.Check()) +} + +func TestUnbound_Cleanup(t *testing.T) { + New().Cleanup() +} + +func TestUnbound_Charts(t *testing.T) { + unbound := prepareNonTLSUnbound() + require.NoError(t, unbound.Init()) + + assert.NotNil(t, unbound.Charts()) +} + +func TestUnbound_Collect(t *testing.T) { + unbound := prepareNonTLSUnbound() + require.NoError(t, unbound.Init()) + unbound.client = mockUnboundClient{data: dataCommonStats, err: false} + + collected := unbound.Collect() + assert.Equal(t, expectedCommon, collected) + testCharts(t, unbound, collected) +} + +func TestUnbound_Collect_ExtendedStats(t *testing.T) { + unbound := prepareNonTLSUnbound() + require.NoError(t, unbound.Init()) + unbound.client = mockUnboundClient{data: dataExtendedStats, err: false} + + collected := unbound.Collect() + assert.Equal(t, expectedExtended, collected) + testCharts(t, unbound, collected) +} + +func TestUnbound_Collect_LifeCycleCumulativeExtendedStats(t *testing.T) { + tests := []struct { + input []byte + expected map[string]int64 + }{ + {input: dataLifeCycleCumulative1, expected: expectedCumulative1}, + {input: dataLifeCycleCumulative2, expected: expectedCumulative2}, + {input: dataLifeCycleCumulative3, expected: expectedCumulative3}, + } + + unbound := prepareNonTLSUnbound() + unbound.Cumulative = true + require.NoError(t, unbound.Init()) + ubClient := &mockUnboundClient{err: false} + unbound.client = ubClient + + var collected map[string]int64 + for i, test := range tests { + t.Run(fmt.Sprintf("run %d", i+1), func(t *testing.T) { + ubClient.data = test.input + collected = unbound.Collect() + assert.Equal(t, test.expected, collected) + }) + } + + testCharts(t, unbound, collected) +} + +func TestUnbound_Collect_LifeCycleResetExtendedStats(t *testing.T) { + tests := []struct { + input []byte + expected map[string]int64 + }{ + {input: dataLifeCycleReset1, expected: expectedReset1}, + {input: dataLifeCycleReset2, expected: expectedReset2}, + {input: dataLifeCycleReset3, expected: expectedReset3}, + } + + unbound := prepareNonTLSUnbound() + unbound.Cumulative = false + require.NoError(t, unbound.Init()) + ubClient := &mockUnboundClient{err: false} + unbound.client = ubClient + + var collected map[string]int64 + for i, test := range tests { + t.Run(fmt.Sprintf("run %d", i+1), func(t *testing.T) { + ubClient.data = test.input + collected = unbound.Collect() + assert.Equal(t, test.expected, collected) + }) + } + + testCharts(t, unbound, collected) +} + +func TestUnbound_Collect_EmptyResponse(t *testing.T) { + unbound := prepareNonTLSUnbound() + require.NoError(t, unbound.Init()) + unbound.client = mockUnboundClient{data: []byte{}, err: false} + + assert.Nil(t, unbound.Collect()) +} + +func TestUnbound_Collect_ErrorResponse(t *testing.T) { + unbound := prepareNonTLSUnbound() + require.NoError(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 := prepareNonTLSUnbound() + require.NoError(t, unbound.Init()) + unbound.client = mockUnboundClient{err: true} + + assert.Nil(t, unbound.Collect()) +} + +func TestUnbound_Collect_ErrorOnParseBadSyntax(t *testing.T) { + unbound := prepareNonTLSUnbound() + require.NoError(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()) +} + +func prepareNonTLSUnbound() *Unbound { + unbound := New() + unbound.ConfPath = "" + unbound.UseTLS = false + + return unbound +} + +type mockUnboundClient struct { + data []byte + err bool +} + +func (m mockUnboundClient) Connect() error { + return nil +} + +func (m mockUnboundClient) Disconnect() error { + return nil +} + +func (m mockUnboundClient) Command(_ string, process socket.Processor) error { + if m.err { + return errors.New("mock send error") + } + s := bufio.NewScanner(bytes.NewReader(m.data)) + for s.Scan() { + process(s.Bytes()) + } + return nil +} + +func testCharts(t *testing.T, unbound *Unbound, collected map[string]int64) { + t.Helper() + ensureChartsCreatedForEveryThread(t, unbound) + ensureExtendedChartsCreated(t, unbound) + ensureCollectedHasAllChartsDimsVarsIDs(t, unbound, collected) +} + +func ensureChartsCreatedForEveryThread(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 ensureExtendedChartsCreated(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) + } + } +} + +func ensureCollectedHasAllChartsDimsVarsIDs(t *testing.T, u *Unbound, collected map[string]int64) { + for _, chart := range *u.Charts() { + for _, dim := range chart.Dims { + if dim.ID == "mem.mod.ipsecmod" { + continue + } + _, ok := collected[dim.ID] + assert.Truef(t, ok, "collected metrics has no data for dim '%s' chart '%s'", dim.ID, chart.ID) + } + for _, v := range chart.Vars { + _, ok := collected[v.ID] + assert.Truef(t, ok, "collected metrics has no data for var '%s' chart '%s'", v.ID, chart.ID) + } + } +} + +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.expired": 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.expired": 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.expired": 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.expired": 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.expired": 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.expired": 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.expired": 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.expired": 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.expired": 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.expired": 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.expired": 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.expired": 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.expired": 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.expired": 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.expired": 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.expired": 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.expired": 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.expired": 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.expired": 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.expired": 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.expired": 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.expired": 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.expired": 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.expired": 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, + } +) |