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
+}