| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | package bind |
| 4 | |
| 5 | import ( |
| 6 | "fmt" |
| 7 | "strings" |
| 8 | |
| 9 | "github.com/netdata/netdata/go/plugins/plugin/framework/collectorapi" |
| 10 | ) |
| 11 | |
| 12 | func (c *Collector) collect() (map[string]int64, error) { |
| 13 | mx := make(map[string]int64) |
| 14 | |
| 15 | s, err := c.serverStats() |
| 16 | if err != nil { |
| 17 | return nil, err |
| 18 | } |
| 19 | c.collectServerStats(mx, s) |
| 20 | |
| 21 | return mx, nil |
| 22 | } |
| 23 | |
| 24 | func (c *Collector) collectServerStats(metrics map[string]int64, stats *serverStats) { |
| 25 | var chart *Chart |
| 26 | |
| 27 | for k, v := range stats.NSStats { |
| 28 | var ( |
| 29 | algo = collectorapi.Incremental |
| 30 | dimName = k |
| 31 | chartID string |
| 32 | ) |
| 33 | switch { |
| 34 | default: |
| 35 | continue |
| 36 | case k == "RecursClients": |
| 37 | dimName = "clients" |
| 38 | chartID = keyRecursiveClients |
| 39 | algo = collectorapi.Absolute |
| 40 | case k == "Requestv4": |
| 41 | dimName = "IPv4" |
| 42 | chartID = keyReceivedRequests |
| 43 | case k == "Requestv6": |
| 44 | dimName = "IPv6" |
| 45 | chartID = keyReceivedRequests |
| 46 | case k == "QryFailure": |
| 47 | dimName = "failures" |
| 48 | chartID = keyQueryFailures |
| 49 | case k == "QryUDP": |
| 50 | dimName = "UDP" |
| 51 | chartID = keyProtocolsQueries |
| 52 | case k == "QryTCP": |
| 53 | dimName = "TCP" |
| 54 | chartID = keyProtocolsQueries |
| 55 | case k == "QrySuccess": |
| 56 | dimName = "queries" |
| 57 | chartID = keyQueriesSuccess |
| 58 | case strings.HasSuffix(k, "QryRej"): |
| 59 | chartID = keyQueryFailuresDetail |
| 60 | case strings.HasPrefix(k, "Qry"): |
| 61 | chartID = keyQueriesAnalysis |
| 62 | case strings.HasPrefix(k, "Update"): |
| 63 | chartID = keyReceivedUpdates |
| 64 | } |
| 65 | |
| 66 | if !c.charts.Has(chartID) { |
| 67 | _ = c.charts.Add(charts[chartID].Copy()) |
| 68 | } |
| 69 | |
| 70 | chart = c.charts.Get(chartID) |
| 71 | |
| 72 | if !chart.HasDim(k) { |
| 73 | _ = chart.AddDim(&Dim{ID: k, Name: dimName, Algo: algo}) |
| 74 | chart.MarkNotCreated() |
| 75 | } |
| 76 | |
| 77 | delete(stats.NSStats, k) |
| 78 | metrics[k] = v |
| 79 | } |
| 80 | |
| 81 | for _, v := range []struct { |
| 82 | item map[string]int64 |
| 83 | chartID string |
| 84 | }{ |
| 85 | {item: stats.NSStats, chartID: keyNSStats}, |
| 86 | {item: stats.OpCodes, chartID: keyInOpCodes}, |
| 87 | {item: stats.QTypes, chartID: keyInQTypes}, |
| 88 | {item: stats.SockStats, chartID: keyInSockStats}, |
| 89 | } { |
| 90 | if len(v.item) == 0 { |
| 91 | continue |
| 92 | } |
| 93 | |
| 94 | if !c.charts.Has(v.chartID) { |
| 95 | _ = c.charts.Add(charts[v.chartID].Copy()) |
| 96 | } |
| 97 | |
| 98 | chart = c.charts.Get(v.chartID) |
| 99 | |
| 100 | for key, val := range v.item { |
| 101 | if !chart.HasDim(key) { |
| 102 | _ = chart.AddDim(&Dim{ID: key, Algo: collectorapi.Incremental}) |
| 103 | chart.MarkNotCreated() |
| 104 | } |
| 105 | |
| 106 | metrics[key] = val |
| 107 | } |
| 108 | } |
| 109 | |
| 110 | if c.permitView == nil || len(stats.Views) == 0 { |
| 111 | return |
| 112 | } |
| 113 | |
| 114 | for name, view := range stats.Views { |
| 115 | if !c.permitView.MatchString(name) { |
| 116 | continue |
| 117 | } |
| 118 | r := view.Resolver |
| 119 | |
| 120 | delete(r.Stats, "BucketSize") |
| 121 | |
| 122 | for key, val := range r.Stats { |
| 123 | var ( |
| 124 | algo = collectorapi.Incremental |
| 125 | dimName = key |
| 126 | chartKey string |
| 127 | ) |
| 128 | |
| 129 | switch { |
| 130 | default: |
| 131 | chartKey = keyResolverStats |
| 132 | case key == "NumFetch": |
| 133 | chartKey = keyResolverNumFetch |
| 134 | dimName = "queries" |
| 135 | algo = collectorapi.Absolute |
| 136 | case strings.HasPrefix(key, "QryRTT"): |
| 137 | // TODO: not ordered |
| 138 | chartKey = keyResolverRTT |
| 139 | } |
| 140 | |
| 141 | chartID := fmt.Sprintf(chartKey, name) |
| 142 | |
| 143 | if !c.charts.Has(chartID) { |
| 144 | chart = charts[chartKey].Copy() |
| 145 | chart.ID = chartID |
| 146 | chart.Fam = fmt.Sprintf(chart.Fam, name) |
| 147 | _ = c.charts.Add(chart) |
| 148 | } |
| 149 | |
| 150 | chart = c.charts.Get(chartID) |
| 151 | dimID := fmt.Sprintf("%s_%s", name, key) |
| 152 | |
| 153 | if !chart.HasDim(dimID) { |
| 154 | _ = chart.AddDim(&Dim{ID: dimID, Name: dimName, Algo: algo}) |
| 155 | chart.MarkNotCreated() |
| 156 | } |
| 157 | |
| 158 | metrics[dimID] = val |
| 159 | } |
| 160 | |
| 161 | if len(r.QTypes) > 0 { |
| 162 | chartID := fmt.Sprintf(keyResolverInQTypes, name) |
| 163 | |
| 164 | if !c.charts.Has(chartID) { |
| 165 | chart = charts[keyResolverInQTypes].Copy() |
| 166 | chart.ID = chartID |
| 167 | chart.Fam = fmt.Sprintf(chart.Fam, name) |
| 168 | _ = c.charts.Add(chart) |
| 169 | } |
| 170 | |
| 171 | chart = c.charts.Get(chartID) |
| 172 | |
| 173 | for key, val := range r.QTypes { |
| 174 | dimID := fmt.Sprintf("%s_%s", name, key) |
| 175 | if !chart.HasDim(dimID) { |
| 176 | _ = chart.AddDim(&Dim{ID: dimID, Name: key, Algo: collectorapi.Incremental}) |
| 177 | chart.MarkNotCreated() |
| 178 | } |
| 179 | metrics[dimID] = val |
| 180 | } |
| 181 | } |
| 182 | |
| 183 | if len(r.CacheStats) > 0 { |
| 184 | chartID := fmt.Sprintf(keyResolverCacheHits, name) |
| 185 | |
| 186 | if !c.charts.Has(chartID) { |
| 187 | chart = charts[keyResolverCacheHits].Copy() |
| 188 | chart.ID = chartID |
| 189 | chart.Fam = fmt.Sprintf(chart.Fam, name) |
| 190 | _ = c.charts.Add(chart) |
| 191 | for _, dim := range chart.Dims { |
| 192 | dim.ID = fmt.Sprintf(dim.ID, name) |
| 193 | } |
| 194 | } |
| 195 | |
| 196 | metrics[name+"_CacheHits"] = r.CacheStats["CacheHits"] |
| 197 | metrics[name+"_CacheMisses"] = r.CacheStats["CacheMisses"] |
| 198 | } |
| 199 | } |
| 200 | } |