@cryptotaxi247 / netdata-1 / commits / c6a9bbaaf

varnish collector Go implementation (#18491)

Co-authored-by: ilyam8 <ilya@netdata.cloud>

Fotis Voutsas committed Sep 10, 2024 at 14:39 UTC c6a9bbaaf84184b143013b30c016d94b02a38d87
18 files changed +1658 -15
src/collectors/python.d.plugin/python.d.conf
+1
@@ -78,4 +78,5 @@ tomcat: no # Removed (replaced with go.d/tomcat)
78 tor: no # Removed (replaced with go.d/tor).
79 puppet: no # Removed (replaced with go.d/puppet).
80 uwsgi: no # Removed (replaced with go.d/uwsgi).
81 +varnish: no # Removed (replaced with go.d/varnish).
82 w1sensor: no # Removed (replaced with go.d/w1sensor)
src/go/plugin/go.d/README.md
+3 -1
@@ -147,8 +147,10 @@ see the appropriate collector readme.
147 | [tomcat](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/tomcat) | Tomcat |
148 | [tor](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/tor) | Tor |
149 | [traefik](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/traefik) | Traefik |
150 -| [upsd](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/upsd) | UPSd (Nut) |
150 | [unbound](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/unbound) | Unbound |
151 +| [upsd](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/upsd) | UPSd (Nut) |
152 +| [uwsgi](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/uwsgi) | uWSGI |
153 +| [varnish](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/varnish) | Varnish |
154 | [vcsa](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/vcsa) | vCenter Server Appliance |
155 | [vernemq](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/vernemq) | VerneMQ |
156 | [vsphere](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/vsphere) | VMware vCenter Server |
src/go/plugin/go.d/agent/module/charts.go
+1 -13
@@ -465,19 +465,7 @@ func checkID(id string) int {
465 }
466
467 func TestMetricsHasAllChartsDims(t *testing.T, charts *Charts, mx map[string]int64) {
468 - for _, chart := range *charts {
469 - if chart.Obsolete {
470 - continue
471 - }
472 - for _, dim := range chart.Dims {
473 - _, ok := mx[dim.ID]
474 - assert.Truef(t, ok, "missing data for dimension '%s' in chart '%s'", dim.ID, chart.ID)
475 - }
476 - for _, v := range chart.Vars {
477 - _, ok := mx[v.ID]
478 - assert.Truef(t, ok, "missing data for variable '%s' in chart '%s'", v.ID, chart.ID)
479 - }
480 - }
468 + TestMetricsHasAllChartsDimsSkip(t, charts, mx, nil)
469 }
470
471 func TestMetricsHasAllChartsDimsSkip(t *testing.T, charts *Charts, mx map[string]int64, skip func(chart *Chart) bool) {
src/go/plugin/go.d/config/go.d.conf
+1
@@ -114,6 +114,7 @@ modules:
114 # upsd: yes
115 # unbound: yes
116 # uwsgi: yes
117 +# varnish: yes
118 # vernemq: yes
119 # vcsa: yes
120 # vsphere: yes
src/go/plugin/go.d/config/go.d/varnish.conf new
+5
@@ -0,0 +1,5 @@
1 +## All available configuration options, their descriptions and default values:
2 +## https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/varnish#readme
3 +
4 +jobs:
5 + - name: local
src/go/plugin/go.d/modules/ap/ap_test.go
+1 -1
@@ -193,7 +193,7 @@ func TestAP_Collect(t *testing.T) {
193 prepareMock: prepareMockErrOnDevices,
194 wantMetrics: nil,
195 },
196 - "error on statis stats call": {
196 + "error on station stats call": {
197 prepareMock: prepareMockErrOnStationStats,
198 wantMetrics: nil,
199 },
src/go/plugin/go.d/modules/init.go
+1
@@ -106,6 +106,7 @@ import (
106 _ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/unbound"
107 _ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/upsd"
108 _ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/uwsgi"
109 + _ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/varnish"
110 _ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/vcsa"
111 _ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/vernemq"
112 _ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/vsphere"
src/go/plugin/go.d/modules/varnish/charts.go new
+387
@@ -0,0 +1,387 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package varnish
4 +
5 +import (
6 + "fmt"
7 + "strings"
8 +
9 + "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module"
10 +)
11 +
12 +const (
13 + prioClientSessionConnections = module.Priority + iota
14 + prioClientRequests
15 +
16 + prioBackendsConnections
17 + prioBackendsRequests
18 + prioBackendDataTransfer
19 +
20 + prioCacheHitRatioTotal
21 + prioCacheHitRatioDelta
22 +
23 + prioCacheExpiredObjects
24 + prioCacheLRUActivity
25 +
26 + prioThreadsTotal
27 + prioThreadManagementActivity
28 + prioThreadQueueLen
29 +
30 + prioEsiStatistics
31 +
32 + prioStorageSpaceUsage
33 + prioStorageAllocatedObjects
34 +
35 + prioMgmtProcessUptime
36 + prioChildProcessUptime
37 +)
38 +
39 +var varnishCharts = module.Charts{
40 + clientSessionConnectionsChart.Copy(),
41 + clientRequestsChart.Copy(),
42 +
43 + backendConnectionsChart.Copy(),
44 + backendRequestsChart.Copy(),
45 +
46 + cacheHitRatioTotalChart.Copy(),
47 + cacheHitRatioDeltaChart.Copy(),
48 + cachedObjectsExpiredChart.Copy(),
49 + cacheLRUActivityChart.Copy(),
50 +
51 + threadsTotalChart.Copy(),
52 + threadManagementActivityChart.Copy(),
53 + threadQueueLenChart.Copy(),
54 +
55 + esiParsingIssuesChart.Copy(),
56 +
57 + mgmtProcessUptimeChart.Copy(),
58 + childProcessUptimeChart.Copy(),
59 +}
60 +
61 +var backendChartsTmpl = module.Charts{
62 + backendDataTransferChartTmpl.Copy(),
63 +}
64 +
65 +var storageChartsTmpl = module.Charts{
66 + storageSpaceUsageChartTmpl.Copy(),
67 + storageAllocatedObjectsChartTmpl.Copy(),
68 +}
69 +
70 +// Client metrics
71 +var (
72 + clientSessionConnectionsChart = module.Chart{
73 + ID: "client_session_connections",
74 + Title: "Client Session Connections",
75 + Fam: "client connections",
76 + Units: "connections/s",
77 + Ctx: "varnish.client_session_connections",
78 + Type: module.Line,
79 + Priority: prioClientSessionConnections,
80 + Dims: module.Dims{
81 + {ID: "MAIN.sess_conn", Name: "accepted", Algo: module.Incremental},
82 + {ID: "MAIN.sess_dropped", Name: "dropped", Algo: module.Incremental},
83 + },
84 + }
85 +
86 + clientRequestsChart = module.Chart{
87 + ID: "client_requests",
88 + Title: "Client Requests",
89 + Fam: "client requests",
90 + Units: "requests/s",
91 + Ctx: "varnish.client_requests",
92 + Type: module.Line,
93 + Priority: prioClientRequests,
94 + Dims: module.Dims{
95 + {ID: "MAIN.client_req", Name: "received", Algo: module.Incremental},
96 + },
97 + }
98 +)
99 +
100 +// Cache activity
101 +var (
102 + cacheHitRatioTotalChart = module.Chart{
103 + ID: "cache_hit_ratio_total",
104 + Title: "Cache Hit Ratio Total",
105 + Fam: "cache activity",
106 + Units: "percent",
107 + Ctx: "varnish.cache_hit_ratio_total",
108 + Type: module.Stacked,
109 + Priority: prioCacheHitRatioTotal,
110 + Dims: module.Dims{
111 + {ID: "MAIN.cache_hit", Name: "hit", Algo: module.PercentOfAbsolute},
112 + {ID: "MAIN.cache_miss", Name: "miss", Algo: module.PercentOfAbsolute},
113 + {ID: "MAIN.cache_hitpass", Name: "hitpass", Algo: module.PercentOfAbsolute},
114 + {ID: "MAIN.cache_hitmiss", Name: "hitmiss", Algo: module.PercentOfAbsolute},
115 + },
116 + }
117 + cacheHitRatioDeltaChart = module.Chart{
118 + ID: "cache_hit_ratio_delta",
119 + Title: "Cache Hit Ratio Current Poll",
120 + Fam: "cache activity",
121 + Units: "percent",
122 + Ctx: "varnish.cache_hit_ratio_delta",
123 + Type: module.Stacked,
124 + Priority: prioCacheHitRatioDelta,
125 + Dims: module.Dims{
126 + {ID: "MAIN.cache_hit", Name: "hit", Algo: module.PercentOfIncremental},
127 + {ID: "MAIN.cache_miss", Name: "miss", Algo: module.PercentOfIncremental},
128 + {ID: "MAIN.cache_hitpass", Name: "hitpass", Algo: module.PercentOfIncremental},
129 + {ID: "MAIN.cache_hitmiss", Name: "hitmiss", Algo: module.PercentOfIncremental},
130 + },
131 + }
132 + cachedObjectsExpiredChart = module.Chart{
133 + ID: "cache_expired_objects",
134 + Title: "Cache Expired Objects",
135 + Fam: "cache activity",
136 + Units: "objects/s",
137 + Ctx: "varnish.cache_expired_objects",
138 + Type: module.Line,
139 + Priority: prioCacheExpiredObjects,
140 + Dims: module.Dims{
141 + {ID: "MAIN.n_expired", Name: "expired", Algo: module.Incremental},
142 + },
143 + }
144 + cacheLRUActivityChart = module.Chart{
145 + ID: "cache_lru_activity",
146 + Title: "Cache LRU Activity",
147 + Fam: "cache activity",
148 + Units: "objects/s",
149 + Ctx: "varnish.cache_lru_activity",
150 + Type: module.Line,
151 + Priority: prioCacheLRUActivity,
152 + Dims: module.Dims{
153 + {ID: "MAIN.n_lru_nuked", Name: "nuked", Algo: module.Incremental},
154 + {ID: "MAIN.n_lru_moved", Name: "moved", Algo: module.Incremental},
155 + },
156 + }
157 +)
158 +
159 +// Threads
160 +var (
161 + threadsTotalChart = module.Chart{
162 + ID: "threads",
163 + Title: "Threads In All Pools",
164 + Fam: "threads",
165 + Units: "threads",
166 + Ctx: "varnish.threads",
167 + Type: module.Line,
168 + Priority: prioThreadsTotal,
169 + Dims: module.Dims{
170 + {ID: "MAIN.threads", Name: "threads"},
171 + },
172 + }
173 + threadManagementActivityChart = module.Chart{
174 + ID: "thread_management_activity",
175 + Title: "Thread Management Activity",
176 + Fam: "threads",
177 + Units: "threads/s",
178 + Ctx: "varnish.thread_management_activity",
179 + Type: module.Line,
180 + Priority: prioThreadManagementActivity,
181 + Dims: module.Dims{
182 + {ID: "MAIN.threads_created", Name: "created", Algo: module.Incremental},
183 + {ID: "MAIN.threads_failed", Name: "failed", Algo: module.Incremental},
184 + {ID: "MAIN.threads_destroyed", Name: "destroyed", Algo: module.Incremental},
185 + {ID: "MAIN.threads_limited", Name: "limited", Algo: module.Incremental},
186 + },
187 + }
188 + threadQueueLenChart = module.Chart{
189 + ID: "thread_queue_len",
190 + Title: "Session Queue Length",
191 + Fam: "threads",
192 + Units: "requests",
193 + Ctx: "varnish.thread_queue_len",
194 + Type: module.Line,
195 + Priority: prioThreadQueueLen,
196 + Dims: module.Dims{
197 + {ID: "MAIN.thread_queue_len", Name: "queue_len"},
198 + },
199 + }
200 +)
201 +
202 +var (
203 + backendConnectionsChart = module.Chart{
204 + ID: "backends_connections",
205 + Title: "Backend Connections",
206 + Fam: "backend connections",
207 + Units: "connections/s",
208 + Ctx: "varnish.backends_connections",
209 + Type: module.Line,
210 + Priority: prioBackendsConnections,
211 + Dims: module.Dims{
212 + {ID: "MAIN.backend_conn", Name: "successful", Algo: module.Incremental},
213 + {ID: "MAIN.backend_unhealthy", Name: "unhealthy", Algo: module.Incremental},
214 + {ID: "MAIN.backend_busy", Name: "busy", Algo: module.Incremental},
215 + {ID: "MAIN.backend_fail", Name: "failed", Algo: module.Incremental},
216 + {ID: "MAIN.backend_reuse", Name: "reused", Algo: module.Incremental},
217 + {ID: "MAIN.backend_recycle", Name: "recycled", Algo: module.Incremental},
218 + {ID: "MAIN.backend_retry", Name: "retry", Algo: module.Incremental},
219 + },
220 + }
221 + backendRequestsChart = module.Chart{
222 + ID: "backends_requests",
223 + Title: "Backend Requests",
224 + Fam: "backend requests",
225 + Units: "requests/s",
226 + Ctx: "varnish.backends_requests",
227 + Type: module.Line,
228 + Priority: prioBackendsRequests,
229 + Dims: module.Dims{
230 + {ID: "MAIN.backend_req", Name: "sent", Algo: module.Incremental},
231 + },
232 + }
233 +)
234 +
235 +// ESI
236 +var (
237 + esiParsingIssuesChart = module.Chart{
238 + ID: "esi_parsing_issues",
239 + Title: "ESI Parsing Issues",
240 + Fam: "esi",
241 + Units: "issues/s",
242 + Ctx: "varnish.esi_parsing_issues",
243 + Type: module.Line,
244 + Priority: prioEsiStatistics,
245 + Dims: module.Dims{
246 + {ID: "MAIN.esi_errors", Name: "errors", Algo: module.Incremental},
247 + {ID: "MAIN.esi_warnings", Name: "warnings", Algo: module.Incremental},
248 + },
249 + }
250 +)
251 +
252 +// Uptime
253 +var (
254 + mgmtProcessUptimeChart = module.Chart{
255 + ID: "mgmt_process_uptime",
256 + Title: "Management Process Uptime",
257 + Fam: "uptime",
258 + Units: "seconds",
259 + Ctx: "varnish.mgmt_process_uptime",
260 + Type: module.Line,
261 + Priority: prioMgmtProcessUptime,
262 + Dims: module.Dims{
263 + {ID: "MGT.uptime", Name: "uptime"},
264 + },
265 + }
266 + childProcessUptimeChart = module.Chart{
267 + ID: "child_process_uptime",
268 + Title: "Child Process Uptime",
269 + Fam: "uptime",
270 + Units: "seconds",
271 + Ctx: "varnish.child_process_uptime",
272 + Type: module.Line,
273 + Priority: prioChildProcessUptime,
274 + Dims: module.Dims{
275 + {ID: "MAIN.uptime", Name: "uptime"},
276 + },
277 + }
278 +)
279 +
280 +var (
281 + backendDataTransferChartTmpl = module.Chart{
282 + ID: "backend_%s_data_transfer",
283 + Title: "Backend Data Transfer",
284 + Fam: "backend traffic",
285 + Units: "bytes/s",
286 + Ctx: "varnish.backend_data_transfer",
287 + Type: module.Area,
288 + Priority: prioBackendDataTransfer,
289 + Dims: module.Dims{
290 + {ID: "VBE.%s.bereq_hdrbytes", Name: "req_header", Algo: module.Incremental},
291 + {ID: "VBE.%s.bereq_bodybytes", Name: "req_body", Algo: module.Incremental},
292 + {ID: "VBE.%s.beresp_hdrbytes", Name: "resp_header", Algo: module.Incremental, Mul: -1},
293 + {ID: "VBE.%s.beresp_bodybytes", Name: "resp_body", Algo: module.Incremental, Mul: -1},
294 + },
295 + }
296 +)
297 +
298 +var (
299 + storageSpaceUsageChartTmpl = module.Chart{
300 + ID: "storage_%s_usage",
301 + Title: "Storage Space Usage",
302 + Fam: "storage usage",
303 + Units: "bytes",
304 + Ctx: "varnish.storage_space_usage",
305 + Type: module.Stacked,
306 + Priority: prioStorageSpaceUsage,
307 + Dims: module.Dims{
308 + {ID: "%s.g_space", Name: "free"},
309 + {ID: "%s.g_bytes", Name: "used"},
310 + },
311 + }
312 +
313 + storageAllocatedObjectsChartTmpl = module.Chart{
314 + ID: "storage_%s_allocated_objects",
315 + Title: "Storage Allocated Objects",
316 + Fam: "storage usage",
317 + Units: "objects",
318 + Ctx: "varnish.storage_allocated_objects",
319 + Type: module.Line,
320 + Priority: prioStorageAllocatedObjects,
321 + Dims: module.Dims{
322 + {ID: "%s.g_alloc", Name: "allocated"},
323 + },
324 + }
325 +)
326 +
327 +func (v *Varnish) addBackendCharts(fullName string) {
328 + charts := backendChartsTmpl.Copy()
329 +
330 + for _, chart := range *charts {
331 + chart.ID = cleanChartID(fmt.Sprintf(chart.ID, fullName))
332 + chart.Labels = []module.Label{
333 + {Key: "backend", Value: fullName},
334 + }
335 + for _, dim := range chart.Dims {
336 + dim.ID = fmt.Sprintf(dim.ID, fullName)
337 + }
338 + }
339 +
340 + if err := v.Charts().Add(*charts...); err != nil {
341 + v.Warning(err)
342 + }
343 +
344 +}
345 +
346 +func (v *Varnish) addStorageCharts(name string) {
347 + charts := storageChartsTmpl.Copy()
348 +
349 + for _, chart := range *charts {
350 + chart.ID = cleanChartID(fmt.Sprintf(chart.ID, name))
351 + chart.Labels = []module.Label{
352 + {Key: "storage", Value: name},
353 + }
354 + for _, dim := range chart.Dims {
355 + dim.ID = fmt.Sprintf(dim.ID, name)
356 + }
357 + }
358 +
359 + if err := v.Charts().Add(*charts...); err != nil {
360 + v.Warning(err)
361 + }
362 +
363 +}
364 +
365 +func (v *Varnish) removeBackendCharts(name string) {
366 + px := fmt.Sprintf("backend_%s_", name)
367 + v.removeCharts(cleanChartID(px))
368 +}
369 +
370 +func (v *Varnish) removeStorageCharts(name string) {
371 + px := fmt.Sprintf("storage_%s_", name)
372 + v.removeCharts(cleanChartID(px))
373 +}
374 +
375 +func (v *Varnish) removeCharts(prefix string) {
376 + for _, chart := range *v.Charts() {
377 + if strings.HasPrefix(chart.ID, prefix) {
378 + chart.MarkRemove()
379 + chart.MarkNotCreated()
380 + }
381 + }
382 +}
383 +
384 +func cleanChartID(id string) string {
385 + id = strings.ReplaceAll(id, ".", "_")
386 + return strings.ToLower(id)
387 +}
src/go/plugin/go.d/modules/varnish/collect.go new
+182
@@ -0,0 +1,182 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package varnish
4 +
5 +import (
6 + "bufio"
7 + "bytes"
8 + "strconv"
9 + "strings"
10 +)
11 +
12 +func (v *Varnish) collect() (map[string]int64, error) {
13 + bs, err := v.exec.statistics()
14 + if err != nil {
15 + return nil, err
16 + }
17 +
18 + mx := make(map[string]int64)
19 +
20 + if err := v.collectStatistics(mx, bs); err != nil {
21 + return nil, err
22 + }
23 +
24 + return mx, nil
25 +}
26 +
27 +func (v *Varnish) collectStatistics(mx map[string]int64, bs []byte) error {
28 + seenBackends, seenStorages := make(map[string]bool), make(map[string]bool)
29 +
30 + sc := bufio.NewScanner(bytes.NewReader(bs))
31 +
32 + for sc.Scan() {
33 + line := strings.TrimSpace(sc.Text())
34 + if line == "" {
35 + continue
36 + }
37 +
38 + parts := strings.Fields(line)
39 + if len(parts) < 4 {
40 + v.Debugf("invalid line format: '%s'. Expected at least 4 fields, skipping line.", line)
41 + continue
42 + }
43 +
44 + fullMetric := parts[0]
45 + valueStr := parts[1]
46 +
47 + category, metric, ok := strings.Cut(fullMetric, ".")
48 + if !ok {
49 + v.Debugf("invalid metric format: '%s'. Expected 'category.metric', skipping metric.", fullMetric)
50 + continue
51 + }
52 + value, err := strconv.ParseInt(valueStr, 10, 64)
53 + if err != nil {
54 + v.Debugf("failed to parse metric '%s' value '%s': %v, skipping metric", fullMetric, valueStr, err)
55 + continue
56 + }
57 +
58 + switch category {
59 + case "MGT":
60 + if mgtMetrics[metric] {
61 + mx[fullMetric] = value
62 + }
63 + case "MAIN":
64 + if mainMetrics[metric] {
65 + mx[fullMetric] = value
66 + }
67 + case "SMA", "SMF", "MSE":
68 + storage, sMetric, ok := strings.Cut(metric, ".")
69 + if !ok {
70 + v.Debugf("invalid metric format: '%s'. Expected 'type.storage.metric', skipping metric.", fullMetric)
71 + continue
72 + }
73 +
74 + fullStorage := category + "." + storage
75 +
76 + if storageMetrics[sMetric] {
77 + seenStorages[fullStorage] = true
78 + mx[fullMetric] = value
79 + }
80 + case "VBE":
81 + // Varnish 4.0.x is not supported (values are 'VBE.default(127.0.0.1,,81).happy')
82 + parts := strings.Split(metric, ".")
83 + if len(parts) != 3 {
84 + v.Debugf("invalid metric format: '%s'. Expected 'VBE.vcl.backend.metric', skipping metric.", fullMetric)
85 + continue
86 + }
87 +
88 + vcl, backend, bMetric := parts[0], parts[1], parts[2]
89 +
90 + if backendMetrics[bMetric] {
91 + seenBackends[vcl+"."+backend] = true
92 + mx[fullMetric] = value
93 + }
94 + }
95 + }
96 +
97 + if len(mx) == 0 {
98 + return nil
99 + }
100 +
101 + for name := range seenStorages {
102 + if !v.seenStorages[name] {
103 + v.seenStorages[name] = true
104 + v.addStorageCharts(name)
105 + }
106 + }
107 + for name := range v.seenStorages {
108 + if !seenStorages[name] {
109 + delete(v.seenStorages, name)
110 + v.removeBackendCharts(name)
111 + }
112 + }
113 +
114 + for fullName := range seenBackends {
115 + if !v.seenBackends[fullName] {
116 + v.seenBackends[fullName] = true
117 + v.addBackendCharts(fullName)
118 + }
119 + }
120 + for fullName := range v.seenBackends {
121 + if !seenBackends[fullName] {
122 + delete(v.seenBackends, fullName)
123 + v.removeBackendCharts(fullName)
124 + }
125 + }
126 +
127 + return nil
128 +}
129 +
130 +var mgtMetrics = map[string]bool{
131 + "uptime": true,
132 + "child_start": true,
133 + "child_exit": true,
134 + "child_stop": true,
135 + "child_died": true,
136 + "child_dump": true,
137 + "child_panic": true,
138 +}
139 +
140 +var mainMetrics = map[string]bool{
141 + "sess_conn": true,
142 + "sess_dropped": true,
143 + "client_req": true,
144 + "cache_hit": true,
145 + "cache_hitpass": true,
146 + "cache_miss": true,
147 + "cache_hitmiss": true,
148 + "n_expired": true,
149 + "n_lru_nuked": true,
150 + "n_lru_moved": true,
151 + "n_lru_limited": true,
152 + "threads": true,
153 + "threads_limited": true,
154 + "threads_created": true,
155 + "threads_destroyed": true,
156 + "threads_failed": true,
157 + "thread_queue_len": true,
158 + "backend_conn": true,
159 + "backend_unhealthy": true,
160 + "backend_busy": true,
161 + "backend_fail": true,
162 + "backend_reuse": true,
163 + "backend_recycle": true,
164 + "backend_retry": true,
165 + "backend_req": true,
166 + "esi_errors": true,
167 + "esi_warnings": true,
168 + "uptime": true,
169 +}
170 +
171 +var storageMetrics = map[string]bool{
172 + "g_space": true,
173 + "g_bytes": true,
174 + "g_alloc": true,
175 +}
176 +
177 +var backendMetrics = map[string]bool{
178 + "bereq_hdrbytes": true,
179 + "bereq_bodybytes": true,
180 + "beresp_hdrbytes": true,
181 + "beresp_bodybytes": true,
182 +}
src/go/plugin/go.d/modules/varnish/config_schema.json new
+47
@@ -0,0 +1,47 @@
1 +{
2 + "jsonSchema": {
3 + "$schema": "http://json-schema.org/draft-07/schema#",
4 + "title": "Varnish collector configuration.",
5 + "type": "object",
6 + "properties": {
7 + "update_every": {
8 + "title": "Update every",
9 + "description": "Data collection interval, measured in seconds.",
10 + "type": "integer",
11 + "minimum": 1,
12 + "default": 10
13 + },
14 + "timeout": {
15 + "title": "Timeout",
16 + "description": "Timeout for executing the binary, specified in seconds.",
17 + "type": "number",
18 + "minimum": 0.5,
19 + "default": 2
20 + },
21 + "instance_name": {
22 + "title": "Instance name",
23 + "description": "Specifies the name of the Varnish instance to collect metrics from.",
24 + "type": "string"
25 + }
26 + },
27 + "required": [],
28 + "additionalProperties": false,
29 + "patternProperties": {
30 + "^name$": {}
31 + }
32 + },
33 + "uiSchema": {
34 + "uiOptions": {
35 + "fullPage": true
36 + },
37 + "binary_path": {
38 + "ui:help": "If an absolute path is provided, the collector will use it directly; otherwise, it will search for the binary in directories specified in the PATH environment variable."
39 + },
40 + "timeout": {
41 + "ui:help": "Accepts decimals for precise control (e.g., type 1.5 for 1.5 seconds)."
42 + },
43 + "instance_name": {
44 + "ui:help": "This corresponds to the `-n` argument used with the [varnishstat](https://varnish-cache.org/docs/trunk/reference/varnishstat.html) command. If not provided, the hostname will be used."
45 + }
46 + }
47 +}
src/go/plugin/go.d/modules/varnish/exec.go new
+48
@@ -0,0 +1,48 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package varnish
4 +
5 +import (
6 + "context"
7 + "fmt"
8 + "os/exec"
9 + "time"
10 +
11 + "github.com/netdata/netdata/go/plugins/logger"
12 +)
13 +
14 +type varnishstatBinary interface {
15 + statistics() ([]byte, error)
16 +}
17 +
18 +func newVarnishstatBinary(binPath string, cfg Config, log *logger.Logger) varnishstatBinary {
19 + return &varnishstatExec{
20 + Logger: log,
21 + binPath: binPath,
22 + timeout: cfg.Timeout.Duration(),
23 + instanceName: cfg.InstanceName,
24 + }
25 +}
26 +
27 +type varnishstatExec struct {
28 + *logger.Logger
29 +
30 + binPath string
31 + timeout time.Duration
32 + instanceName string
33 +}
34 +
35 +func (e *varnishstatExec) statistics() ([]byte, error) {
36 + ctx, cancel := context.WithTimeout(context.Background(), e.timeout)
37 + defer cancel()
38 +
39 + cmd := exec.CommandContext(ctx, e.binPath, "varnishstat-stats", "--instanceName", e.instanceName)
40 + e.Debugf("executing '%s'", cmd)
41 +
42 + bs, err := cmd.Output()
43 + if err != nil {
44 + return nil, fmt.Errorf("error on '%s': %v", cmd, err)
45 + }
46 +
47 + return bs, nil
48 +}
src/go/plugin/go.d/modules/varnish/init.go new
+24
@@ -0,0 +1,24 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package varnish
4 +
5 +import (
6 + "fmt"
7 + "os"
8 + "path/filepath"
9 +
10 + "github.com/netdata/netdata/go/plugins/pkg/executable"
11 +)
12 +
13 +func (v *Varnish) initVarnishstatBinary() (varnishstatBinary, error) {
14 + ndsudoPath := filepath.Join(executable.Directory, "ndsudo")
15 +
16 + if _, err := os.Stat(ndsudoPath); err != nil {
17 + return nil, fmt.Errorf("ndsudo executable not found: %v", err)
18 +
19 + }
20 +
21 + varnishstat := newVarnishstatBinary(ndsudoPath, v.Config, v.Logger)
22 +
23 + return varnishstat, nil
24 +}
src/go/plugin/go.d/modules/varnish/metadata.yaml new
+219
@@ -0,0 +1,219 @@
1 +plugin_name: go.d.plugin
2 +modules:
3 + - meta:
4 + plugin_name: go.d.plugin
5 + module_name: varnish
6 + monitored_instance:
7 + name: Varnish
8 + link: https://varnish-cache.org/
9 + categories:
10 + - data-collection.web-servers-and-web-proxies
11 + icon_filename: "varnish.svg"
12 + related_resources:
13 + integrations:
14 + list: []
15 + info_provided_to_referring_integrations:
16 + description: ""
17 + keywords:
18 + - varnish
19 + - varnishstat
20 + - varnishd
21 + - cache
22 + - web server
23 + - web cache
24 + most_popular: false
25 + overview:
26 + data_collection:
27 + metrics_description: |
28 + This collector monitors Varnish instances, supporting both the open-source Varnish-Cache and the commercial Varnish-Plus.
29 +
30 + It tracks key performance metrics, along with detailed statistics for Backends (VBE) and Storages (SMF, SMA, MSE).
31 +
32 + It relies on the [`varnishstat`](https://varnish-cache.org/docs/trunk/reference/varnishstat.html) CLI tool but avoids directly executing the binary.
33 + Instead, it utilizes `ndsudo`, a Netdata helper specifically designed to run privileged commands securely within the Netdata environment.
34 + This approach eliminates the need to use `sudo`, improving security and potentially simplifying permission management.
35 + method_description: ""
36 + supported_platforms:
37 + include: []
38 + exclude: []
39 + multi_instance: false
40 + additional_permissions:
41 + description: ""
42 + default_behavior:
43 + auto_detection:
44 + description: ""
45 + limits:
46 + description: ""
47 + performance_impact:
48 + description: ""
49 + setup:
50 + prerequisites:
51 + list: []
52 + configuration:
53 + file:
54 + name: go.d/varnish.conf
55 + options:
56 + description: |
57 + The following options can be defined globally: update_every.
58 + folding:
59 + title: Config options
60 + enabled: true
61 + list:
62 + - name: update_every
63 + description: Data collection frequency.
64 + default_value: 10
65 + required: false
66 + - name: timeout
67 + description: Timeout for executing the binary, specified in seconds.
68 + default_value: 2
69 + required: false
70 + - name: instance_name
71 + description: "Specifies the name of the Varnish instance to collect metrics from. This corresponds to the `-n` argument used with the [varnishstat](https://varnish-cache.org/docs/trunk/reference/varnishstat.html) command."
72 + default_value: ""
73 + required: false
74 + examples:
75 + folding:
76 + title: ""
77 + enabled: false
78 + list:
79 + - name: Custom update_every
80 + description: Allows you to override the default data collection interval.
81 + config: |
82 + jobs:
83 + - name: varnish
84 + update_every: 5
85 + troubleshooting:
86 + problems:
87 + list: []
88 + alerts: []
89 + metrics:
90 + folding:
91 + title: Metrics
92 + enabled: false
93 + description: ""
94 + availability: []
95 + scopes:
96 + - name: global
97 + description: "These metrics refer to the entire monitored application."
98 + labels: []
99 + metrics:
100 + - name: varnish.client_session_connections
101 + description: Connections Statistics
102 + unit: "connections/s"
103 + chart_type: line
104 + dimensions:
105 + - name: accepted
106 + - name: dropped
107 + - name: varnish.client_requests
108 + description: Client Requests
109 + unit: "requests/s"
110 + chart_type: line
111 + dimensions:
112 + - name: received
113 + - name: varnish.cache_hit_ratio_total
114 + description: Cache Hit Ratio Total
115 + unit: "percent"
116 + chart_type: stacked
117 + dimensions:
118 + - name: hit
119 + - name: miss
120 + - name: hitpass
121 + - name: hitmiss
122 + - name: varnish.cache_hit_ratio_delta
123 + description: Cache Hit Ratio Current Poll
124 + unit: "percent"
125 + chart_type: stacked
126 + dimensions:
127 + - name: hit
128 + - name: miss
129 + - name: hitpass
130 + - name: hitmiss
131 + - name: varnish.cache_expired_objects
132 + description: Cache Expired Objects
133 + unit: "objects/s"
134 + chart_type: line
135 + dimensions:
136 + - name: expired
137 + - name: varnish.cache_lru_activity
138 + description: Cache LRU Activity
139 + unit: "objects/s"
140 + chart_type: line
141 + dimensions:
142 + - name: nuked
143 + - name: moved
144 + - name: varnish.threads
145 + description: Threads In All Pools
146 + unit: "threads"
147 + chart_type: line
148 + dimensions:
149 + - name: threads
150 + - name: varnish.thread_management_activity
151 + description: Thread Management Activity
152 + unit: "threads/s"
153 + chart_type: line
154 + dimensions:
155 + - name: created
156 + - name: failed
157 + - name: destroyed
158 + - name: limited
159 + - name: varnish.thread_queue_len
160 + description: Session Queue Length
161 + unit: "threads"
162 + chart_type: line
163 + dimensions:
164 + - name: queue_length
165 + - name: varnish.backends_requests
166 + description: Backend Requests
167 + unit: "requests/s"
168 + chart_type: line
169 + dimensions:
170 + - name: sent
171 + - name: varnish.esi_parsing_issues
172 + description: ESI Parsing Issues
173 + unit: "issues/s"
174 + chart_type: line
175 + dimensions:
176 + - name: errors
177 + - name: warnings
178 + - name: varnish.mgmt_process_uptime
179 + description: Management Process Uptime
180 + unit: "seconds"
181 + chart_type: line
182 + dimensions:
183 + - name: uptime
184 + - name: varnish.child_process_uptime
185 + description: Child Process Uptime
186 + unit: "seconds"
187 + chart_type: line
188 + dimensions:
189 + - name: uptime
190 + - name: Backend
191 + description: "These metrics refer to the Backend (VBE)."
192 + labels: []
193 + metrics:
194 + - name: varnish.backend_data_transfer
195 + description: Backend Data Transfer
196 + unit: "bytes/s"
197 + chart_type: area
198 + dimensions:
199 + - name: req_header
200 + - name: req_body
201 + - name: resp_header
202 + - name: resp_body
203 + - name: Storage
204 + description: "These metrics refer to the Storage (SMA, SMF, MSE)."
205 + labels: []
206 + metrics:
207 + - name: varnish.storage_space_usage
208 + description: Storage Space Usage
209 + unit: "bytes"
210 + chart_type: stacked
211 + dimensions:
212 + - name: free
213 + - name: used
214 + - name: varnish.storage_allocated_objects
215 + description: Storage Allocated Objects
216 + unit: "objects"
217 + chart_type: line
218 + dimensions:
219 + - name: allocated
src/go/plugin/go.d/modules/varnish/testdata/config.json new
+5
@@ -0,0 +1,5 @@
1 +{
2 + "update_every": 123,
3 + "timeout": 123.123,
4 + "instance_name": "ok"
5 +}
src/go/plugin/go.d/modules/varnish/testdata/config.yaml new
+3
@@ -0,0 +1,3 @@
1 +update_every: 123
2 +timeout: 123.123
3 +instance_name: "ok"
src/go/plugin/go.d/modules/varnish/testdata/v7.1/varnishstat.txt new
+370
@@ -0,0 +1,370 @@
1 +MGT.uptime 33833 1.00 Management process uptime
2 +MGT.child_start 1 0.00 Child process started
3 +MGT.child_exit 0 0.00 Child process normal exit
4 +MGT.child_stop 0 0.00 Child process unexpected exit
5 +MGT.child_died 0 0.00 Child process died (signal)
6 +MGT.child_dump 0 0.00 Child process core dumped
7 +MGT.child_panic 0 0.00 Child process panic
8 +MAIN.summs 20 0.00 stat summ operations
9 +MAIN.uptime 33834 1.00 Child process uptime
10 +MAIN.sess_conn 4 0.00 Sessions accepted
11 +MAIN.sess_fail 0 0.00 Session accept failures
12 +MAIN.sess_fail_econnaborted 0 0.00 Session accept failures: connection aborted
13 +MAIN.sess_fail_eintr 0 0.00 Session accept failures: interrupted system call
14 +MAIN.sess_fail_emfile 0 0.00 Session accept failures: too many open files
15 +MAIN.sess_fail_ebadf 0 0.00 Session accept failures: bad file descriptor
16 +MAIN.sess_fail_enomem 0 0.00 Session accept failures: not enough memory
17 +MAIN.sess_fail_other 0 0.00 Session accept failures: other
18 +MAIN.client_req_400 0 0.00 Client requests received, subject to 400 errors
19 +MAIN.client_req_417 0 0.00 Client requests received, subject to 417 errors
20 +MAIN.client_req 4 0.00 Good client requests received
21 +MAIN.esi_req 0 0.00 ESI subrequests
22 +MAIN.cache_hit 0 0.00 Cache hits
23 +MAIN.cache_hit_grace 0 0.00 Cache grace hits
24 +MAIN.cache_hitpass 0 0.00 Cache hits for pass.
25 +MAIN.cache_hitmiss 0 0.00 Cache hits for miss.
26 +MAIN.cache_miss 0 0.00 Cache misses
27 +MAIN.beresp_uncacheable 4 0.00 Uncacheable backend responses
28 +MAIN.beresp_shortlived 0 0.00 Shortlived objects
29 +MAIN.backend_conn 2 0.00 Backend conn. success
30 +MAIN.backend_unhealthy 0 0.00 Backend conn. not attempted
31 +MAIN.backend_busy 0 0.00 Backend conn. too many
32 +MAIN.backend_fail 0 0.00 Backend conn. failures
33 +MAIN.backend_reuse 2 0.00 Backend conn. reuses
34 +MAIN.backend_recycle 4 0.00 Backend conn. recycles
35 +MAIN.backend_retry 0 0.00 Backend conn. retry
36 +MAIN.fetch_head 0 0.00 Fetch no body (HEAD)
37 +MAIN.fetch_length 2 0.00 Fetch with Length
38 +MAIN.fetch_chunked 0 0.00 Fetch chunked
39 +MAIN.fetch_eof 0 0.00 Fetch EOF
40 +MAIN.fetch_bad 0 0.00 Fetch bad T-E
41 +MAIN.fetch_none 0 0.00 Fetch no body
42 +MAIN.fetch_1xx 0 0.00 Fetch no body (1xx)
43 +MAIN.fetch_204 0 0.00 Fetch no body (204)
44 +MAIN.fetch_304 2 0.00 Fetch no body (304)
45 +MAIN.fetch_failed 0 0.00 Fetch failed (all causes)
46 +MAIN.fetch_no_thread 0 0.00 Fetch failed (no thread)
47 +MAIN.pools 2 . Number of thread pools
48 +MAIN.threads 200 . Total number of threads
49 +MAIN.threads_limited 0 0.00 Threads hit max
50 +MAIN.threads_created 200 0.01 Threads created
51 +MAIN.threads_destroyed 0 0.00 Threads destroyed
52 +MAIN.threads_failed 0 0.00 Thread creation failed
53 +MAIN.thread_queue_len 0 . Length of session queue
54 +MAIN.busy_sleep 0 0.00 Number of requests sent to sleep on busy objhdr
55 +MAIN.busy_wakeup 0 0.00 Number of requests woken after sleep on busy objhdr
56 +MAIN.busy_killed 0 0.00 Number of requests killed after sleep on busy objhdr
57 +MAIN.sess_queued 0 0.00 Sessions queued for thread
58 +MAIN.sess_dropped 0 0.00 Sessions dropped for thread
59 +MAIN.req_dropped 0 0.00 Requests dropped
60 +MAIN.n_object 0 . object structs made
61 +MAIN.n_vampireobject 0 . unresurrected objects
62 +MAIN.n_objectcore 0 . objectcore structs made
63 +MAIN.n_objecthead 0 . objecthead structs made
64 +MAIN.n_backend 2 . Number of backends
65 +MAIN.n_expired 0 0.00 Number of expired objects
66 +MAIN.n_lru_nuked 0 0.00 Number of LRU nuked objects
67 +MAIN.n_lru_moved 0 0.00 Number of LRU moved objects
68 +MAIN.n_lru_limited 0 0.00 Reached nuke_limit
69 +MAIN.losthdr 0 0.00 HTTP header overflows
70 +MAIN.s_sess 4 0.00 Total sessions seen
71 +MAIN.n_pipe 0 . Number of ongoing pipe sessions
72 +MAIN.pipe_limited 0 0.00 Pipes hit pipe_sess_max
73 +MAIN.s_pipe 0 0.00 Total pipe sessions seen
74 +MAIN.s_pass 4 0.00 Total pass-ed requests seen
75 +MAIN.s_fetch 4 0.00 Total backend fetches initiated
76 +MAIN.s_bgfetch 0 0.00 Total backend background fetches initiated
77 +MAIN.s_synth 0 0.00 Total synthetic responses made
78 +MAIN.s_req_hdrbytes 5137 0.15 Request header bytes
79 +MAIN.s_req_bodybytes 0 0.00 Request body bytes
80 +MAIN.s_resp_hdrbytes 969 0.03 Response header bytes
81 +MAIN.s_resp_bodybytes 1170 0.03 Response body bytes
82 +MAIN.s_pipe_hdrbytes 0 0.00 Pipe request header bytes
83 +MAIN.s_pipe_in 0 0.00 Piped bytes from client
84 +MAIN.s_pipe_out 0 0.00 Piped bytes to client
85 +MAIN.sess_closed 0 0.00 Session Closed
86 +MAIN.sess_closed_err 0 0.00 Session Closed with error
87 +MAIN.sess_readahead 0 0.00 Session Read Ahead
88 +MAIN.sess_herd 6 0.00 Session herd
89 +MAIN.sc_rem_close 0 0.00 Session OK REM_CLOSE
90 +MAIN.sc_req_close 0 0.00 Session OK REQ_CLOSE
91 +MAIN.sc_req_http10 0 0.00 Session Err REQ_HTTP10
92 +MAIN.sc_rx_bad 0 0.00 Session Err RX_BAD
93 +MAIN.sc_rx_body 0 0.00 Session Err RX_BODY
94 +MAIN.sc_rx_junk 0 0.00 Session Err RX_JUNK
95 +MAIN.sc_rx_overflow 0 0.00 Session Err RX_OVERFLOW
96 +MAIN.sc_rx_timeout 0 0.00 Session Err RX_TIMEOUT
97 +MAIN.sc_rx_close_idle 4 0.00 Session Err RX_CLOSE_IDLE
98 +MAIN.sc_tx_pipe 0 0.00 Session OK TX_PIPE
99 +MAIN.sc_tx_error 0 0.00 Session Err TX_ERROR
100 +MAIN.sc_tx_eof 0 0.00 Session OK TX_EOF
101 +MAIN.sc_resp_close 0 0.00 Session OK RESP_CLOSE
102 +MAIN.sc_overload 0 0.00 Session Err OVERLOAD
103 +MAIN.sc_pipe_overflow 0 0.00 Session Err PIPE_OVERFLOW
104 +MAIN.sc_range_short 0 0.00 Session Err RANGE_SHORT
105 +MAIN.sc_req_http20 0 0.00 Session Err REQ_HTTP20
106 +MAIN.sc_vcl_failure 0 0.00 Session Err VCL_FAILURE
107 +MAIN.client_resp_500 0 0.00 Delivery failed due to insufficient workspace.
108 +MAIN.ws_backend_overflow 0 0.00 workspace_backend overflows
109 +MAIN.ws_client_overflow 0 0.00 workspace_client overflows
110 +MAIN.ws_thread_overflow 0 0.00 workspace_thread overflows
111 +MAIN.ws_session_overflow 0 0.00 workspace_session overflows
112 +MAIN.shm_records 22960 0.68 SHM records
113 +MAIN.shm_writes 22612 0.67 SHM writes
114 +MAIN.shm_flushes 0 0.00 SHM flushes due to overflow
115 +MAIN.shm_cont 0 0.00 SHM MTX contention
116 +MAIN.shm_cycles 0 0.00 SHM cycles through buffer
117 +MAIN.backend_req 4 0.00 Backend requests made
118 +MAIN.n_vcl 1 . Number of loaded VCLs in total
119 +MAIN.n_vcl_avail 1 . Number of VCLs available
120 +MAIN.n_vcl_discard 0 . Number of discarded VCLs
121 +MAIN.vcl_fail 0 0.00 VCL failures
122 +MAIN.bans 1 . Count of bans
123 +MAIN.bans_completed 1 . Number of bans marked 'completed'
124 +MAIN.bans_obj 0 . Number of bans using obj.*
125 +MAIN.bans_req 0 . Number of bans using req.*
126 +MAIN.bans_added 1 0.00 Bans added
127 +MAIN.bans_deleted 0 0.00 Bans deleted
128 +MAIN.bans_tested 0 0.00 Bans tested against objects (lookup)
129 +MAIN.bans_obj_killed 0 0.00 Objects killed by bans (lookup)
130 +MAIN.bans_lurker_tested 0 0.00 Bans tested against objects (lurker)
131 +MAIN.bans_tests_tested 0 0.00 Ban tests tested against objects (lookup)
132 +MAIN.bans_lurker_tests_tested 0 0.00 Ban tests tested against objects (lurker)
133 +MAIN.bans_lurker_obj_killed 0 0.00 Objects killed by bans (lurker)
134 +MAIN.bans_lurker_obj_killed_cutoff 0 0.00 Objects killed by bans for cutoff (lurker)
135 +MAIN.bans_dups 0 0.00 Bans superseded by other bans
136 +MAIN.bans_lurker_contention 0 0.00 Lurker gave way for lookup
137 +MAIN.bans_persisted_bytes 16 . Bytes used by the persisted ban lists
138 +MAIN.bans_persisted_fragmentation 0 . Extra bytes in persisted ban lists due to fragmentation
139 +MAIN.n_purges 0 0.00 Number of purge operations executed
140 +MAIN.n_obj_purged 0 0.00 Number of purged objects
141 +MAIN.exp_mailed 0 0.00 Number of objects mailed to expiry thread
142 +MAIN.exp_received 0 0.00 Number of objects received by expiry thread
143 +MAIN.hcb_nolock 0 0.00 HCB Lookups without lock
144 +MAIN.hcb_lock 0 0.00 HCB Lookups with lock
145 +MAIN.hcb_insert 0 0.00 HCB Inserts
146 +MAIN.esi_errors 0 0.00 ESI parse errors (unlock)
147 +MAIN.esi_warnings 0 0.00 ESI parse warnings (unlock)
148 +MAIN.vmods 0 . Loaded VMODs
149 +MAIN.n_gzip 0 0.00 Gzip operations
150 +MAIN.n_gunzip 0 0.00 Gunzip operations
151 +MAIN.n_test_gunzip 0 0.00 Test gunzip operations
152 +LCK.ban.creat 1 0.00 Created locks
153 +LCK.ban.destroy 0 0.00 Destroyed locks
154 +LCK.ban.locks 1374 0.04 Lock Operations
155 +LCK.ban.dbg_busy 0 0.00 Contended lock operations
156 +LCK.ban.dbg_try_fail 0 0.00 Contended trylock operations
157 +LCK.busyobj.creat 4 0.00 Created locks
158 +LCK.busyobj.destroy 4 0.00 Destroyed locks
159 +LCK.busyobj.locks 26 0.00 Lock Operations
160 +LCK.busyobj.dbg_busy 0 0.00 Contended lock operations
161 +LCK.busyobj.dbg_try_fail 0 0.00 Contended trylock operations
162 +LCK.cli.creat 1 0.00 Created locks
163 +LCK.cli.destroy 0 0.00 Destroyed locks
164 +LCK.cli.locks 11302 0.33 Lock Operations
165 +LCK.cli.dbg_busy 0 0.00 Contended lock operations
166 +LCK.cli.dbg_try_fail 0 0.00 Contended trylock operations
167 +LCK.director.creat 2 0.00 Created locks
168 +LCK.director.destroy 0 0.00 Destroyed locks
169 +LCK.director.locks 8 0.00 Lock Operations
170 +LCK.director.dbg_busy 0 0.00 Contended lock operations
171 +LCK.director.dbg_try_fail 0 0.00 Contended trylock operations
172 +LCK.exp.creat 1 0.00 Created locks
173 +LCK.exp.destroy 0 0.00 Destroyed locks
174 +LCK.exp.locks 10771 0.32 Lock Operations
175 +LCK.exp.dbg_busy 0 0.00 Contended lock operations
176 +LCK.exp.dbg_try_fail 0 0.00 Contended trylock operations
177 +LCK.hcb.creat 1 0.00 Created locks
178 +LCK.hcb.destroy 0 0.00 Destroyed locks
179 +LCK.hcb.locks 188 0.01 Lock Operations
180 +LCK.hcb.dbg_busy 0 0.00 Contended lock operations
181 +LCK.hcb.dbg_try_fail 0 0.00 Contended trylock operations
182 +LCK.lru.creat 2 0.00 Created locks
183 +LCK.lru.destroy 0 0.00 Destroyed locks
184 +LCK.lru.locks 0 0.00 Lock Operations
185 +LCK.lru.dbg_busy 0 0.00 Contended lock operations
186 +LCK.lru.dbg_try_fail 0 0.00 Contended trylock operations
187 +LCK.mempool.creat 5 0.00 Created locks
188 +LCK.mempool.destroy 0 0.00 Destroyed locks
189 +LCK.mempool.locks 149990 4.43 Lock Operations
190 +LCK.mempool.dbg_busy 0 0.00 Contended lock operations
191 +LCK.mempool.dbg_try_fail 0 0.00 Contended trylock operations
192 +LCK.objhdr.creat 1 0.00 Created locks
193 +LCK.objhdr.destroy 0 0.00 Destroyed locks
194 +LCK.objhdr.locks 41 0.00 Lock Operations
195 +LCK.objhdr.dbg_busy 0 0.00 Contended lock operations
196 +LCK.objhdr.dbg_try_fail 0 0.00 Contended trylock operations
197 +LCK.perpool.creat 2 0.00 Created locks
198 +LCK.perpool.destroy 0 0.00 Destroyed locks
199 +LCK.perpool.locks 460 0.01 Lock Operations
200 +LCK.perpool.dbg_busy 0 0.00 Contended lock operations
201 +LCK.perpool.dbg_try_fail 0 0.00 Contended trylock operations
202 +LCK.pipestat.creat 1 0.00 Created locks
203 +LCK.pipestat.destroy 0 0.00 Destroyed locks
204 +LCK.pipestat.locks 0 0.00 Lock Operations
205 +LCK.pipestat.dbg_busy 0 0.00 Contended lock operations
206 +LCK.pipestat.dbg_try_fail 0 0.00 Contended trylock operations
207 +LCK.probe.creat 1 0.00 Created locks
208 +LCK.probe.destroy 0 0.00 Destroyed locks
209 +LCK.probe.locks 1 0.00 Lock Operations
210 +LCK.probe.dbg_busy 0 0.00 Contended lock operations
211 +LCK.probe.dbg_try_fail 0 0.00 Contended trylock operations
212 +LCK.sess.creat 4 0.00 Created locks
213 +LCK.sess.destroy 4 0.00 Destroyed locks
214 +LCK.sess.locks 12 0.00 Lock Operations
215 +LCK.sess.dbg_busy 0 0.00 Contended lock operations
216 +LCK.sess.dbg_try_fail 0 0.00 Contended trylock operations
217 +LCK.conn_pool.creat 3 0.00 Created locks
218 +LCK.conn_pool.destroy 0 0.00 Destroyed locks
219 +LCK.conn_pool.locks 16 0.00 Lock Operations
220 +LCK.conn_pool.dbg_busy 0 0.00 Contended lock operations
221 +LCK.conn_pool.dbg_try_fail 0 0.00 Contended trylock operations
222 +LCK.vbe.creat 1 0.00 Created locks
223 +LCK.vbe.destroy 0 0.00 Destroyed locks
224 +LCK.vbe.locks 2 0.00 Lock Operations
225 +LCK.vbe.dbg_busy 0 0.00 Contended lock operations
226 +LCK.vbe.dbg_try_fail 0 0.00 Contended trylock operations
227 +LCK.vcapace.creat 1 0.00 Created locks
228 +LCK.vcapace.destroy 0 0.00 Destroyed locks
229 +LCK.vcapace.locks 0 0.00 Lock Operations
230 +LCK.vcapace.dbg_busy 0 0.00 Contended lock operations
231 +LCK.vcapace.dbg_try_fail 0 0.00 Contended trylock operations
232 +LCK.vcl.creat 1 0.00 Created locks
233 +LCK.vcl.destroy 0 0.00 Destroyed locks
234 +LCK.vcl.locks 25 0.00 Lock Operations
235 +LCK.vcl.dbg_busy 0 0.00 Contended lock operations
236 +LCK.vcl.dbg_try_fail 0 0.00 Contended trylock operations
237 +LCK.vxid.creat 1 0.00 Created locks
238 +LCK.vxid.destroy 0 0.00 Destroyed locks
239 +LCK.vxid.locks 2 0.00 Lock Operations
240 +LCK.vxid.dbg_busy 0 0.00 Contended lock operations
241 +LCK.vxid.dbg_try_fail 0 0.00 Contended trylock operations
242 +LCK.waiter.creat 2 0.00 Created locks
243 +LCK.waiter.destroy 0 0.00 Destroyed locks
244 +LCK.waiter.locks 714 0.02 Lock Operations
245 +LCK.waiter.dbg_busy 0 0.00 Contended lock operations
246 +LCK.waiter.dbg_try_fail 0 0.00 Contended trylock operations
247 +LCK.wq.creat 1 0.00 Created locks
248 +LCK.wq.destroy 0 0.00 Destroyed locks
249 +LCK.wq.locks 34033 1.01 Lock Operations
250 +LCK.wq.dbg_busy 0 0.00 Contended lock operations
251 +LCK.wq.dbg_try_fail 0 0.00 Contended trylock operations
252 +LCK.wstat.creat 1 0.00 Created locks
253 +LCK.wstat.destroy 0 0.00 Destroyed locks
254 +LCK.wstat.locks 11651 0.34 Lock Operations
255 +LCK.wstat.dbg_busy 0 0.00 Contended lock operations
256 +LCK.wstat.dbg_try_fail 0 0.00 Contended trylock operations
257 +MEMPOOL.busyobj.live 0 . In use
258 +MEMPOOL.busyobj.pool 10 . In Pool
259 +MEMPOOL.busyobj.sz_wanted 98304 . Size requested
260 +MEMPOOL.busyobj.sz_actual 98272 . Size allocated
261 +MEMPOOL.busyobj.allocs 4 0.00 Allocations
262 +MEMPOOL.busyobj.frees 4 0.00 Frees
263 +MEMPOOL.busyobj.recycle 4 0.00 Recycled from pool
264 +MEMPOOL.busyobj.timeout 0 0.00 Timed out from pool
265 +MEMPOOL.busyobj.toosmall 0 0.00 Too small to recycle
266 +MEMPOOL.busyobj.surplus 0 0.00 Too many for pool
267 +MEMPOOL.busyobj.randry 0 0.00 Pool ran dry
268 +MEMPOOL.req0.live 0 . In use
269 +MEMPOOL.req0.pool 10 . In Pool
270 +MEMPOOL.req0.sz_wanted 98304 . Size requested
271 +MEMPOOL.req0.sz_actual 98272 . Size allocated
272 +MEMPOOL.req0.allocs 4 0.00 Allocations
273 +MEMPOOL.req0.frees 4 0.00 Frees
274 +MEMPOOL.req0.recycle 4 0.00 Recycled from pool
275 +MEMPOOL.req0.timeout 0 0.00 Timed out from pool
276 +MEMPOOL.req0.toosmall 0 0.00 Too small to recycle
277 +MEMPOOL.req0.surplus 0 0.00 Too many for pool
278 +MEMPOOL.req0.randry 0 0.00 Pool ran dry
279 +MEMPOOL.sess0.live 0 . In use
280 +MEMPOOL.sess0.pool 10 . In Pool
281 +MEMPOOL.sess0.sz_wanted 768 . Size requested
282 +MEMPOOL.sess0.sz_actual 736 . Size allocated
283 +MEMPOOL.sess0.allocs 2 0.00 Allocations
284 +MEMPOOL.sess0.frees 2 0.00 Frees
285 +MEMPOOL.sess0.recycle 2 0.00 Recycled from pool
286 +MEMPOOL.sess0.timeout 2 0.00 Timed out from pool
287 +MEMPOOL.sess0.toosmall 0 0.00 Too small to recycle
288 +MEMPOOL.sess0.surplus 0 0.00 Too many for pool
289 +MEMPOOL.sess0.randry 0 0.00 Pool ran dry
290 +LCK.sma.creat 2 0.00 Created locks
291 +LCK.sma.destroy 0 0.00 Destroyed locks
292 +LCK.sma.locks 12 0.00 Lock Operations
293 +LCK.sma.dbg_busy 0 0.00 Contended lock operations
294 +LCK.sma.dbg_try_fail 0 0.00 Contended trylock operations
295 +SMA.s0.c_req 0 0.00 Allocator requests
296 +SMA.s0.c_fail 0 0.00 Allocator failures
297 +SMA.s0.c_bytes 0 0.00 Bytes allocated
298 +SMA.s0.c_freed 0 0.00 Bytes freed
299 +SMA.s0.g_alloc 0 . Allocations outstanding
300 +SMA.s0.g_bytes 0 . Bytes outstanding
301 +SMA.s0.g_space 268435456 . Bytes available
302 +SMA.Transient.c_req 6 0.00 Allocator requests
303 +SMA.Transient.c_fail 0 0.00 Allocator failures
304 +SMA.Transient.c_bytes 2322 0.07 Bytes allocated
305 +SMA.Transient.c_freed 2322 0.07 Bytes freed
306 +SMA.Transient.g_alloc 0 . Allocations outstanding
307 +SMA.Transient.g_bytes 0 . Bytes outstanding
308 +SMA.Transient.g_space 0 . Bytes available
309 +MEMPOOL.req1.live 0 . In use
310 +MEMPOOL.req1.pool 10 . In Pool
311 +MEMPOOL.req1.sz_wanted 98304 . Size requested
312 +MEMPOOL.req1.sz_actual 98272 . Size allocated
313 +MEMPOOL.req1.allocs 2 0.00 Allocations
314 +MEMPOOL.req1.frees 2 0.00 Frees
315 +MEMPOOL.req1.recycle 2 0.00 Recycled from pool
316 +MEMPOOL.req1.timeout 0 0.00 Timed out from pool
317 +MEMPOOL.req1.toosmall 0 0.00 Too small to recycle
318 +MEMPOOL.req1.surplus 0 0.00 Too many for pool
319 +MEMPOOL.req1.randry 0 0.00 Pool ran dry
320 +VBE.boot.default.happy 0 . Happy health probes
321 +VBE.boot.default.bereq_hdrbytes 5214 0.15 Request header bytes
322 +VBE.boot.default.bereq_bodybytes 0 0.00 Request body bytes
323 +VBE.boot.default.beresp_hdrbytes 753 0.02 Response header bytes
324 +VBE.boot.default.beresp_bodybytes 1170 0.03 Response body bytes
325 +VBE.boot.default.pipe_hdrbytes 0 0.00 Pipe request header bytes
326 +VBE.boot.default.pipe_out 0 0.00 Piped bytes to backend
327 +VBE.boot.default.pipe_in 0 0.00 Piped bytes from backend
328 +VBE.boot.default.conn 0 . Concurrent connections used
329 +VBE.boot.default.req 4 0.00 Backend requests sent
330 +VBE.boot.default.unhealthy 0 0.00 Fetches not attempted due to backend being unhealthy
331 +VBE.boot.default.busy 0 0.00 Fetches not attempted due to backend being busy
332 +VBE.boot.default.fail 0 0.00 Connections failed
333 +VBE.boot.default.fail_eacces 0 0.00 Connections failed with EACCES or EPERM
334 +VBE.boot.default.fail_eaddrnotavail 0 0.00 Connections failed with EADDRNOTAVAIL
335 +VBE.boot.default.fail_econnrefused 0 0.00 Connections failed with ECONNREFUSED
336 +VBE.boot.default.fail_enetunreach 0 0.00 Connections failed with ENETUNREACH
337 +VBE.boot.default.fail_etimedout 0 0.00 Connections failed ETIMEDOUT
338 +VBE.boot.default.fail_other 0 0.00 Connections failed for other reason
339 +VBE.boot.default.helddown 0 0.00 Connection opens not attempted
340 +VBE.boot.nginx2.happy 0 . Happy health probes
341 +VBE.boot.nginx2.bereq_hdrbytes 0 0.00 Request header bytes
342 +VBE.boot.nginx2.bereq_bodybytes 0 0.00 Request body bytes
343 +VBE.boot.nginx2.beresp_hdrbytes 0 0.00 Response header bytes
344 +VBE.boot.nginx2.beresp_bodybytes 0 0.00 Response body bytes
345 +VBE.boot.nginx2.pipe_hdrbytes 0 0.00 Pipe request header bytes
346 +VBE.boot.nginx2.pipe_out 0 0.00 Piped bytes to backend
347 +VBE.boot.nginx2.pipe_in 0 0.00 Piped bytes from backend
348 +VBE.boot.nginx2.conn 0 . Concurrent connections used
349 +VBE.boot.nginx2.req 0 0.00 Backend requests sent
350 +VBE.boot.nginx2.unhealthy 0 0.00 Fetches not attempted due to backend being unhealthy
351 +VBE.boot.nginx2.busy 0 0.00 Fetches not attempted due to backend being busy
352 +VBE.boot.nginx2.fail 0 0.00 Connections failed
353 +VBE.boot.nginx2.fail_eacces 0 0.00 Connections failed with EACCES or EPERM
354 +VBE.boot.nginx2.fail_eaddrnotavail 0 0.00 Connections failed with EADDRNOTAVAIL
355 +VBE.boot.nginx2.fail_econnrefused 0 0.00 Connections failed with ECONNREFUSED
356 +VBE.boot.nginx2.fail_enetunreach 0 0.00 Connections failed with ENETUNREACH
357 +VBE.boot.nginx2.fail_etimedout 0 0.00 Connections failed ETIMEDOUT
358 +VBE.boot.nginx2.fail_other 0 0.00 Connections failed for other reason
359 +VBE.boot.nginx2.helddown 0 0.00 Connection opens not attempted
360 +MEMPOOL.sess1.live 0 . In use
361 +MEMPOOL.sess1.pool 10 . In Pool
362 +MEMPOOL.sess1.sz_wanted 768 . Size requested
363 +MEMPOOL.sess1.sz_actual 736 . Size allocated
364 +MEMPOOL.sess1.allocs 2 0.00 Allocations
365 +MEMPOOL.sess1.frees 2 0.00 Frees
366 +MEMPOOL.sess1.recycle 2 0.00 Recycled from pool
367 +MEMPOOL.sess1.timeout 2 0.00 Timed out from pool
368 +MEMPOOL.sess1.toosmall 0 0.00 Too small to recycle
369 +MEMPOOL.sess1.surplus 0 0.00 Too many for pool
370 +MEMPOOL.sess1.randry 0 0.00 Pool ran dry
src/go/plugin/go.d/modules/varnish/varnish.go new
+105
@@ -0,0 +1,105 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package varnish
4 +
5 +import (
6 + _ "embed"
7 + "errors"
8 + "time"
9 +
10 + "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module"
11 + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web"
12 +)
13 +
14 +//go:embed "config_schema.json"
15 +var configSchema string
16 +
17 +func init() {
18 + module.Register("varnish", module.Creator{
19 + JobConfigSchema: configSchema,
20 + Defaults: module.Defaults{
21 + UpdateEvery: 10,
22 + },
23 + Create: func() module.Module { return New() },
24 + Config: func() any { return &Config{} },
25 + })
26 +}
27 +
28 +func New() *Varnish {
29 + return &Varnish{
30 + Config: Config{
31 + Timeout: web.Duration(time.Second * 2),
32 + },
33 +
34 + seenBackends: make(map[string]bool),
35 + seenStorages: make(map[string]bool),
36 + charts: varnishCharts.Copy(),
37 + }
38 +
39 +}
40 +
41 +type Config struct {
42 + UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"`
43 + Timeout web.Duration `yaml:"timeout,omitempty" json:"timeout"`
44 + InstanceName string `yaml:"instance_name,omitempty" json:"instance_name,omitempty"`
45 +}
46 +
47 +type Varnish struct {
48 + module.Base
49 + Config `yaml:",inline" json:""`
50 +
51 + charts *module.Charts
52 +
53 + exec varnishstatBinary
54 +
55 + seenBackends map[string]bool
56 + seenStorages map[string]bool
57 +}
58 +
59 +func (v *Varnish) Configuration() any {
60 + return v.Config
61 +}
62 +
63 +func (v *Varnish) Init() error {
64 + vs, err := v.initVarnishstatBinary()
65 + if err != nil {
66 + v.Errorf("varnishstat exec initialization: %v", err)
67 + return err
68 + }
69 + v.exec = vs
70 +
71 + return nil
72 +}
73 +
74 +func (v *Varnish) Check() error {
75 + mx, err := v.collect()
76 + if err != nil {
77 + v.Error(err)
78 + return err
79 + }
80 +
81 + if len(mx) == 0 {
82 + return errors.New("no metrics collected")
83 + }
84 +
85 + return nil
86 +}
87 +
88 +func (v *Varnish) Charts() *module.Charts {
89 + return v.charts
90 +}
91 +
92 +func (v *Varnish) Collect() map[string]int64 {
93 + mx, err := v.collect()
94 + if err != nil {
95 + v.Error(err)
96 + }
97 +
98 + if len(mx) == 0 {
99 + return nil
100 + }
101 +
102 + return mx
103 +}
104 +
105 +func (v *Varnish) Cleanup() {}
src/go/plugin/go.d/modules/varnish/varnish_test.go new
+255
@@ -0,0 +1,255 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package varnish
4 +
5 +import (
6 + "errors"
7 + "os"
8 + "testing"
9 +
10 + "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module"
11 +
12 + "github.com/stretchr/testify/assert"
13 + "github.com/stretchr/testify/require"
14 +)
15 +
16 +var (
17 + dataConfigJSON, _ = os.ReadFile("testdata/config.json")
18 + dataConfigYAML, _ = os.ReadFile("testdata/config.yaml")
19 +
20 + dataVer71Varnishstat, _ = os.ReadFile("testdata/v7.1/varnishstat.txt")
21 +)
22 +
23 +func Test_testDataIsValid(t *testing.T) {
24 + for name, data := range map[string][]byte{
25 + "dataConfigJSON": dataConfigJSON,
26 + "dataConfigYAML": dataConfigYAML,
27 + "dataVer71Varnishstat": dataVer71Varnishstat,
28 + } {
29 + require.NotNil(t, data, name)
30 + }
31 +}
32 +
33 +func TestVarnish_Configuration(t *testing.T) {
34 + module.TestConfigurationSerialize(t, &Varnish{}, dataConfigJSON, dataConfigYAML)
35 +}
36 +
37 +func TestVarnish_Init(t *testing.T) {
38 + tests := map[string]struct {
39 + config Config
40 + wantFail bool
41 + }{
42 + "fails if failed to locate ndsudo": {
43 + wantFail: true,
44 + config: New().Config,
45 + },
46 + }
47 +
48 + for name, test := range tests {
49 + t.Run(name, func(t *testing.T) {
50 + varnish := New()
51 + varnish.Config = test.config
52 +
53 + if test.wantFail {
54 + assert.Error(t, varnish.Init())
55 + } else {
56 + assert.NoError(t, varnish.Init())
57 + }
58 + })
59 + }
60 +}
61 +
62 +func TestVarnish_Cleanup(t *testing.T) {
63 + tests := map[string]struct {
64 + prepare func() *Varnish
65 + }{
66 + "not initialized exec": {
67 + prepare: func() *Varnish {
68 + return New()
69 + },
70 + },
71 + "after check": {
72 + prepare: func() *Varnish {
73 + varnish := New()
74 + varnish.exec = prepareMockOkVer71()
75 + _ = varnish.Check()
76 + return varnish
77 + },
78 + },
79 + "after collect": {
80 + prepare: func() *Varnish {
81 + varnish := New()
82 + varnish.exec = prepareMockOkVer71()
83 + _ = varnish.Collect()
84 + return varnish
85 + },
86 + },
87 + }
88 +
89 + for name, test := range tests {
90 + t.Run(name, func(t *testing.T) {
91 + varnish := test.prepare()
92 +
93 + assert.NotPanics(t, varnish.Cleanup)
94 + })
95 + }
96 +}
97 +
98 +func TestVarnish_Charts(t *testing.T) {
99 + assert.NotNil(t, New().Charts())
100 +}
101 +
102 +func TestVarnish_Check(t *testing.T) {
103 + tests := map[string]struct {
104 + prepareMock func() *mockVarnishstatExec
105 + wantFail bool
106 + }{
107 + "success case": {
108 + wantFail: false,
109 + prepareMock: prepareMockOkVer71,
110 + },
111 + "error on varnishstat call": {
112 + wantFail: true,
113 + prepareMock: prepareMockErrOnVarnishstatCall,
114 + },
115 + "unexpected response": {
116 + wantFail: true,
117 + prepareMock: prepareMockUnexpectedResponse,
118 + },
119 + }
120 +
121 + for name, test := range tests {
122 + t.Run(name, func(t *testing.T) {
123 + varnish := New()
124 + varnish.exec = test.prepareMock()
125 +
126 + if test.wantFail {
127 + assert.Error(t, varnish.Check())
128 + } else {
129 + assert.NoError(t, varnish.Check())
130 + }
131 + })
132 + }
133 +}
134 +
135 +func TestVarnish_Collect(t *testing.T) {
136 + tests := map[string]struct {
137 + prepareMock func() *mockVarnishstatExec
138 + wantMetrics map[string]int64
139 + wantCharts int
140 + }{
141 + "success case varnish v7.1": {
142 + prepareMock: prepareMockOkVer71,
143 + wantCharts: len(varnishCharts) + len(backendChartsTmpl)*2 + len(storageChartsTmpl)*2,
144 + wantMetrics: map[string]int64{
145 + "MAIN.backend_busy": 0,
146 + "MAIN.backend_conn": 2,
147 + "MAIN.backend_fail": 0,
148 + "MAIN.backend_recycle": 4,
149 + "MAIN.backend_req": 4,
150 + "MAIN.backend_retry": 0,
151 + "MAIN.backend_reuse": 2,
152 + "MAIN.backend_unhealthy": 0,
153 + "MAIN.cache_hit": 0,
154 + "MAIN.cache_hitmiss": 0,
155 + "MAIN.cache_hitpass": 0,
156 + "MAIN.cache_miss": 0,
157 + "MAIN.client_req": 4,
158 + "MAIN.esi_errors": 0,
159 + "MAIN.esi_warnings": 0,
160 + "MAIN.n_expired": 0,
161 + "MAIN.n_lru_limited": 0,
162 + "MAIN.n_lru_moved": 0,
163 + "MAIN.n_lru_nuked": 0,
164 + "MAIN.sess_conn": 4,
165 + "MAIN.sess_dropped": 0,
166 + "MAIN.thread_queue_len": 0,
167 + "MAIN.threads": 200,
168 + "MAIN.threads_created": 200,
169 + "MAIN.threads_destroyed": 0,
170 + "MAIN.threads_failed": 0,
171 + "MAIN.threads_limited": 0,
172 + "MAIN.uptime": 33834,
173 + "MGT.child_died": 0,
174 + "MGT.child_dump": 0,
175 + "MGT.child_exit": 0,
176 + "MGT.child_panic": 0,
177 + "MGT.child_start": 1,
178 + "MGT.child_stop": 0,
179 + "MGT.uptime": 33833,
180 + "SMA.Transient.g_alloc": 0,
181 + "SMA.Transient.g_bytes": 0,
182 + "SMA.Transient.g_space": 0,
183 + "SMA.s0.g_alloc": 0,
184 + "SMA.s0.g_bytes": 0,
185 + "SMA.s0.g_space": 268435456,
186 + "VBE.boot.default.bereq_bodybytes": 0,
187 + "VBE.boot.default.bereq_hdrbytes": 5214,
188 + "VBE.boot.default.beresp_bodybytes": 1170,
189 + "VBE.boot.default.beresp_hdrbytes": 753,
190 + "VBE.boot.nginx2.bereq_bodybytes": 0,
191 + "VBE.boot.nginx2.bereq_hdrbytes": 0,
192 + "VBE.boot.nginx2.beresp_bodybytes": 0,
193 + "VBE.boot.nginx2.beresp_hdrbytes": 0,
194 + },
195 + },
196 + "error on varnishstat call": {
197 + prepareMock: prepareMockErrOnVarnishstatCall,
198 + },
199 + "unexpected response": {
200 + prepareMock: prepareMockUnexpectedResponse,
201 + },
202 + }
203 +
204 + for name, test := range tests {
205 + t.Run(name, func(t *testing.T) {
206 + varnish := New()
207 + varnish.exec = test.prepareMock()
208 +
209 + mx := varnish.Collect()
210 +
211 + assert.Equal(t, test.wantMetrics, mx)
212 +
213 + if len(test.wantMetrics) > 0 {
214 + assert.Equal(t, test.wantCharts, len(*varnish.Charts()))
215 + module.TestMetricsHasAllChartsDims(t, varnish.Charts(), mx)
216 + }
217 + })
218 + }
219 +}
220 +
221 +func prepareMockOkVer71() *mockVarnishstatExec {
222 + return &mockVarnishstatExec{
223 + dataVarnishstat: dataVer71Varnishstat,
224 + }
225 +}
226 +
227 +func prepareMockErrOnVarnishstatCall() *mockVarnishstatExec {
228 + return &mockVarnishstatExec{
229 + dataVarnishstat: nil,
230 + errOnVarnishstatCall: true,
231 + }
232 +}
233 +
234 +func prepareMockUnexpectedResponse() *mockVarnishstatExec {
235 + return &mockVarnishstatExec{
236 + dataVarnishstat: []byte(`
237 +Lorem ipsum dolor sit amet, consectetur adipiscing elit.
238 +Nulla malesuada erat id magna mattis, eu viverra tellus rhoncus.
239 +Fusce et felis pulvinar, posuere sem non, porttitor eros.
240 +`),
241 + }
242 +}
243 +
244 +type mockVarnishstatExec struct {
245 + errOnVarnishstatCall bool
246 + dataVarnishstat []byte
247 +}
248 +
249 +func (m *mockVarnishstatExec) statistics() ([]byte, error) {
250 + if m.errOnVarnishstatCall {
251 + return nil, errors.New("mock statistics() error")
252 + }
253 +
254 + return m.dataVarnishstat, nil
255 +}