master
go 182 lines 4 KB
Raw
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 (c *Collector) collect() (map[string]int64, error) {
13 bs, err := c.exec.statistics()
14 if err != nil {
15 return nil, err
16 }
17
18 mx := make(map[string]int64)
19
20 if err := c.collectStatistics(mx, bs); err != nil {
21 return nil, err
22 }
23
24 return mx, nil
25 }
26
27 func (c *Collector) 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 c.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 c.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 c.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 c.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 c.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 !c.seenStorages[name] {
103 c.seenStorages[name] = true
104 c.addStorageCharts(name)
105 }
106 }
107 for name := range c.seenStorages {
108 if !seenStorages[name] {
109 delete(c.seenStorages, name)
110 c.removeStorageCharts(name)
111 }
112 }
113
114 for fullName := range seenBackends {
115 if !c.seenBackends[fullName] {
116 c.seenBackends[fullName] = true
117 c.addBackendCharts(fullName)
118 }
119 }
120 for fullName := range c.seenBackends {
121 if !seenBackends[fullName] {
122 delete(c.seenBackends, fullName)
123 c.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 }