diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 11:19:16 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-07-24 09:53:24 +0000 |
commit | b5f8ee61a7f7e9bd291dd26b0585d03eb686c941 (patch) | |
tree | d4d31289c39fc00da064a825df13a0b98ce95b10 /src/go/collectors/go.d.plugin/modules/unbound/charts.go | |
parent | Adding upstream version 1.44.3. (diff) | |
download | netdata-b5f8ee61a7f7e9bd291dd26b0585d03eb686c941.tar.xz netdata-b5f8ee61a7f7e9bd291dd26b0585d03eb686c941.zip |
Adding upstream version 1.46.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | src/go/collectors/go.d.plugin/modules/unbound/charts.go | 527 |
1 files changed, 527 insertions, 0 deletions
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 +} |