master
go 384 lines 11.9 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package nginxplus
4
5 import (
6 "errors"
7 "fmt"
8 "time"
9
10 "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/oldmetrix"
11 )
12
13 func (c *Collector) collect() (map[string]int64, error) {
14 if c.apiVersion == 0 {
15 v, err := c.queryAPIVersion()
16 if err != nil {
17 return nil, err
18 }
19 c.apiVersion = v
20 }
21
22 now := time.Now()
23 if now.Sub(c.queryEndpointsTime) > c.queryEndpointsEvery {
24 c.queryEndpointsTime = now
25 if err := c.queryAvailableEndpoints(); err != nil {
26 return nil, err
27 }
28 }
29
30 ms := c.queryMetrics()
31 if ms.empty() {
32 return nil, errors.New("no metrics collected")
33 }
34
35 mx := make(map[string]int64)
36 c.cache.resetUpdated()
37 c.collectInfo(mx, ms)
38 c.collectConnections(mx, ms)
39 c.collectSSL(mx, ms)
40 c.collectHTTPRequests(mx, ms)
41 c.collectHTTPCache(mx, ms)
42 c.collectHTTPServerZones(mx, ms)
43 c.collectHTTPLocationZones(mx, ms)
44 c.collectHTTPUpstreams(mx, ms)
45 c.collectStreamServerZones(mx, ms)
46 c.collectStreamUpstreams(mx, ms)
47 c.collectResolvers(mx, ms)
48 c.updateCharts()
49
50 return mx, nil
51 }
52
53 func (c *Collector) collectInfo(mx map[string]int64, ms *nginxMetrics) {
54 if ms.info == nil {
55 return
56 }
57 mx["uptime"] = int64(ms.info.Timestamp.Sub(ms.info.LoadTimestamp).Seconds())
58 }
59
60 func (c *Collector) collectConnections(mx map[string]int64, ms *nginxMetrics) {
61 if ms.connections == nil {
62 return
63 }
64 mx["connections_accepted"] = ms.connections.Accepted
65 mx["connections_dropped"] = ms.connections.Dropped
66 mx["connections_active"] = ms.connections.Active
67 mx["connections_idle"] = ms.connections.Idle
68 }
69
70 func (c *Collector) collectSSL(mx map[string]int64, ms *nginxMetrics) {
71 if ms.ssl == nil {
72 return
73 }
74 mx["ssl_handshakes"] = ms.ssl.Handshakes
75 mx["ssl_handshakes_failed"] = ms.ssl.HandshakesFailed
76 mx["ssl_session_reuses"] = ms.ssl.SessionReuses
77 mx["ssl_no_common_protocol"] = ms.ssl.NoCommonProtocol
78 mx["ssl_no_common_cipher"] = ms.ssl.NoCommonCipher
79 mx["ssl_handshake_timeout"] = ms.ssl.HandshakeTimeout
80 mx["ssl_peer_rejected_cert"] = ms.ssl.PeerRejectedCert
81 mx["ssl_verify_failures_no_cert"] = ms.ssl.VerifyFailures.NoCert
82 mx["ssl_verify_failures_expired_cert"] = ms.ssl.VerifyFailures.ExpiredCert
83 mx["ssl_verify_failures_revoked_cert"] = ms.ssl.VerifyFailures.RevokedCert
84 mx["ssl_verify_failures_hostname_mismatch"] = ms.ssl.VerifyFailures.HostnameMismatch
85 mx["ssl_verify_failures_other"] = ms.ssl.VerifyFailures.Other
86 }
87
88 func (c *Collector) collectHTTPRequests(mx map[string]int64, ms *nginxMetrics) {
89 if ms.httpRequests == nil {
90 return
91 }
92 mx["http_requests_total"] = ms.httpRequests.Total
93 mx["http_requests_current"] = ms.httpRequests.Current
94 }
95
96 func (c *Collector) collectHTTPCache(mx map[string]int64, ms *nginxMetrics) {
97 if ms.httpCaches == nil {
98 return
99 }
100 for name, cache := range *ms.httpCaches {
101 c.cache.putHTTPCache(name)
102 px := fmt.Sprintf("http_cache_%s_", name)
103 mx[px+"state_cold"] = oldmetrix.Bool(cache.Cold)
104 mx[px+"state_warm"] = oldmetrix.Bool(!cache.Cold)
105 mx[px+"size"] = cache.Size
106 mx[px+"served_responses"] = cache.Hit.Responses + cache.Stale.Responses + cache.Updating.Responses + cache.Revalidated.Responses
107 mx[px+"written_responses"] = cache.Miss.ResponsesWritten + cache.Expired.ResponsesWritten + cache.Bypass.ResponsesWritten
108 mx[px+"bypassed_responses"] = cache.Miss.Responses + cache.Expired.Responses + cache.Bypass.Responses
109 mx[px+"served_bytes"] = cache.Hit.Bytes + cache.Stale.Bytes + cache.Updating.Bytes + cache.Revalidated.Bytes
110 mx[px+"written_bytes"] = cache.Miss.BytesWritten + cache.Expired.BytesWritten + cache.Bypass.BytesWritten
111 mx[px+"bypassed_bytes"] = cache.Miss.Bytes + cache.Expired.Bytes + cache.Bypass.Bytes
112 }
113 }
114
115 func (c *Collector) collectHTTPServerZones(mx map[string]int64, ms *nginxMetrics) {
116 if ms.httpServerZones == nil {
117 return
118 }
119 for name, zone := range *ms.httpServerZones {
120 c.cache.putHTTPServerZone(name)
121
122 px := fmt.Sprintf("http_server_zone_%s_", name)
123 mx[px+"requests_processing"] = zone.Processing
124 mx[px+"requests"] = zone.Requests
125 mx[px+"requests_discarded"] = zone.Discarded
126 mx[px+"bytes_received"] = zone.Received
127 mx[px+"bytes_sent"] = zone.Sent
128 mx[px+"responses"] = zone.Responses.Total
129 mx[px+"responses_1xx"] = zone.Responses.Class1xx
130 mx[px+"responses_2xx"] = zone.Responses.Class2xx
131 mx[px+"responses_3xx"] = zone.Responses.Class3xx
132 mx[px+"responses_4xx"] = zone.Responses.Class4xx
133 mx[px+"responses_5xx"] = zone.Responses.Class5xx
134 }
135 }
136
137 func (c *Collector) collectHTTPLocationZones(mx map[string]int64, ms *nginxMetrics) {
138 if ms.httpLocationZones == nil {
139 return
140 }
141 for name, zone := range *ms.httpLocationZones {
142 c.cache.putHTTPLocationZone(name)
143
144 px := fmt.Sprintf("http_location_zone_%s_", name)
145 mx[px+"requests"] = zone.Requests
146 mx[px+"requests_discarded"] = zone.Discarded
147 mx[px+"bytes_received"] = zone.Received
148 mx[px+"bytes_sent"] = zone.Sent
149 mx[px+"responses"] = zone.Responses.Total
150 mx[px+"responses_1xx"] = zone.Responses.Class1xx
151 mx[px+"responses_2xx"] = zone.Responses.Class2xx
152 mx[px+"responses_3xx"] = zone.Responses.Class3xx
153 mx[px+"responses_4xx"] = zone.Responses.Class4xx
154 mx[px+"responses_5xx"] = zone.Responses.Class5xx
155 }
156 }
157
158 func (c *Collector) collectHTTPUpstreams(mx map[string]int64, ms *nginxMetrics) {
159 if ms.httpUpstreams == nil {
160 return
161 }
162 for name, upstream := range *ms.httpUpstreams {
163 c.cache.putHTTPUpstream(name, upstream.Zone)
164
165 px := fmt.Sprintf("http_upstream_%s_zone_%s_", name, upstream.Zone)
166 mx[px+"zombies"] = upstream.Zombies
167 mx[px+"keepalive"] = upstream.Keepalive
168 mx[px+"peers"] = int64(len(upstream.Peers))
169
170 for _, peer := range upstream.Peers {
171 c.cache.putHTTPUpstreamServer(name, peer.Server, peer.Name, upstream.Zone)
172
173 px = fmt.Sprintf("http_upstream_%s_server_%s_zone_%s_", name, peer.Server, upstream.Zone)
174 mx[px+"active"] = peer.Active
175 for _, v := range []string{"up", "down", "draining", "unavail", "checking", "unhealthy"} {
176 mx[px+"state_"+v] = oldmetrix.Bool(peer.State == v)
177 }
178 mx[px+"bytes_received"] = peer.Received
179 mx[px+"bytes_sent"] = peer.Sent
180 mx[px+"requests"] = peer.Requests
181 mx[px+"responses"] = peer.Responses.Total
182 mx[px+"responses_1xx"] = peer.Responses.Class1xx
183 mx[px+"responses_2xx"] = peer.Responses.Class2xx
184 mx[px+"responses_3xx"] = peer.Responses.Class3xx
185 mx[px+"responses_4xx"] = peer.Responses.Class4xx
186 mx[px+"responses_5xx"] = peer.Responses.Class5xx
187 mx[px+"response_time"] = peer.ResponseTime
188 mx[px+"header_time"] = peer.HeaderTime
189 mx[px+"downtime"] = peer.Downtime / 1000
190 }
191 }
192 }
193
194 func (c *Collector) collectStreamServerZones(mx map[string]int64, ms *nginxMetrics) {
195 if ms.streamServerZones == nil {
196 return
197 }
198 for name, zone := range *ms.streamServerZones {
199 c.cache.putStreamServerZone(name)
200
201 px := fmt.Sprintf("stream_server_zone_%s_", name)
202 mx[px+"connections"] = zone.Connections
203 mx[px+"connections_processing"] = zone.Processing
204 mx[px+"connections_discarded"] = zone.Discarded
205 mx[px+"bytes_received"] = zone.Received
206 mx[px+"bytes_sent"] = zone.Sent
207 mx[px+"sessions"] = zone.Sessions.Total
208 mx[px+"sessions_2xx"] = zone.Sessions.Class2xx
209 mx[px+"sessions_4xx"] = zone.Sessions.Class4xx
210 mx[px+"sessions_5xx"] = zone.Sessions.Class5xx
211 }
212 }
213
214 func (c *Collector) collectStreamUpstreams(mx map[string]int64, ms *nginxMetrics) {
215 if ms.streamUpstreams == nil {
216 return
217 }
218 for name, upstream := range *ms.streamUpstreams {
219 c.cache.putStreamUpstream(name, upstream.Zone)
220
221 px := fmt.Sprintf("stream_upstream_%s_zone_%s_", name, upstream.Zone)
222 mx[px+"zombies"] = upstream.Zombies
223 mx[px+"peers"] = int64(len(upstream.Peers))
224
225 for _, peer := range upstream.Peers {
226 c.cache.putStreamUpstreamServer(name, peer.Server, peer.Name, upstream.Zone)
227
228 px = fmt.Sprintf("stream_upstream_%s_server_%s_zone_%s_", name, peer.Server, upstream.Zone)
229
230 mx[px+"active"] = peer.Active
231 mx[px+"connections"] = peer.Connections
232 for _, v := range []string{"up", "down", "unavail", "checking", "unhealthy"} {
233 mx[px+"state_"+v] = oldmetrix.Bool(peer.State == v)
234 }
235 mx[px+"bytes_received"] = peer.Received
236 mx[px+"bytes_sent"] = peer.Sent
237 mx[px+"downtime"] = peer.Downtime / 1000
238 }
239 }
240 }
241
242 func (c *Collector) collectResolvers(mx map[string]int64, ms *nginxMetrics) {
243 if ms.resolvers == nil {
244 return
245 }
246 for name, zone := range *ms.resolvers {
247 c.cache.putResolver(name)
248
249 px := fmt.Sprintf("resolver_zone_%s_", name)
250 mx[px+"requests_name"] = zone.Requests.Name
251 mx[px+"requests_srv"] = zone.Requests.Srv
252 mx[px+"requests_addr"] = zone.Requests.Addr
253 mx[px+"responses_noerror"] = zone.Responses.NoError
254 mx[px+"responses_formerr"] = zone.Responses.Formerr
255 mx[px+"responses_servfail"] = zone.Responses.Servfail
256 mx[px+"responses_nxdomain"] = zone.Responses.Nxdomain
257 mx[px+"responses_notimp"] = zone.Responses.Notimp
258 mx[px+"responses_refused"] = zone.Responses.Refused
259 mx[px+"responses_timedout"] = zone.Responses.TimedOut
260 mx[px+"responses_unknown"] = zone.Responses.Unknown
261 }
262 }
263
264 func (c *Collector) updateCharts() {
265 const notSeenLimit = 3
266
267 for key, v := range c.cache.httpCaches {
268 if v.updated && !v.hasCharts {
269 v.hasCharts = true
270 c.addHTTPCacheCharts(v.name)
271 continue
272 }
273 if !v.updated {
274 if v.notSeenTimes++; v.notSeenTimes >= notSeenLimit {
275 delete(c.cache.httpCaches, key)
276 c.removeHTTPCacheCharts(v.name)
277 }
278 }
279 }
280 for key, v := range c.cache.httpServerZones {
281 if v.updated && !v.hasCharts {
282 v.hasCharts = true
283 c.addHTTPServerZoneCharts(v.zone)
284 continue
285 }
286 if !v.updated {
287 if v.notSeenTimes++; v.notSeenTimes >= notSeenLimit {
288 delete(c.cache.httpServerZones, key)
289 c.removeHTTPServerZoneCharts(v.zone)
290 }
291 }
292 }
293 for key, v := range c.cache.httpLocationZones {
294 if v.updated && !v.hasCharts {
295 v.hasCharts = true
296 c.addHTTPLocationZoneCharts(v.zone)
297 continue
298 }
299 if !v.updated {
300 if v.notSeenTimes++; v.notSeenTimes >= notSeenLimit {
301 delete(c.cache.httpLocationZones, key)
302 c.removeHTTPLocationZoneCharts(v.zone)
303 }
304 }
305 }
306 for key, v := range c.cache.httpUpstreams {
307 if v.updated && !v.hasCharts {
308 v.hasCharts = true
309 c.addHTTPUpstreamCharts(v.name, v.zone)
310 continue
311 }
312 if !v.updated {
313 if v.notSeenTimes++; v.notSeenTimes >= notSeenLimit {
314 delete(c.cache.httpUpstreams, key)
315 c.removeHTTPUpstreamCharts(v.name, v.zone)
316 }
317 }
318 }
319 for key, v := range c.cache.httpUpstreamServers {
320 if v.updated && !v.hasCharts {
321 v.hasCharts = true
322 c.addHTTPUpstreamServerCharts(v.name, v.serverAddr, v.serverName, v.zone)
323 continue
324 }
325 if !v.updated {
326 if v.notSeenTimes++; v.notSeenTimes >= notSeenLimit {
327 delete(c.cache.httpUpstreamServers, key)
328 c.removeHTTPUpstreamServerCharts(v.name, v.serverAddr, v.zone)
329 }
330 }
331 }
332 for key, v := range c.cache.streamServerZones {
333 if v.updated && !v.hasCharts {
334 v.hasCharts = true
335 c.addStreamServerZoneCharts(v.zone)
336 continue
337 }
338 if !v.updated {
339 if v.notSeenTimes++; v.notSeenTimes >= notSeenLimit {
340 delete(c.cache.streamServerZones, key)
341 c.removeStreamServerZoneCharts(v.zone)
342 }
343 }
344 }
345 for key, v := range c.cache.streamUpstreams {
346 if v.updated && !v.hasCharts {
347 v.hasCharts = true
348 c.addStreamUpstreamCharts(v.name, v.zone)
349 continue
350 }
351 if !v.updated {
352 if v.notSeenTimes++; v.notSeenTimes >= notSeenLimit {
353 delete(c.cache.streamUpstreams, key)
354 c.removeStreamUpstreamCharts(v.name, v.zone)
355 }
356 }
357 }
358 for key, v := range c.cache.streamUpstreamServers {
359 if v.updated && !v.hasCharts {
360 v.hasCharts = true
361 c.addStreamUpstreamServerCharts(v.name, v.serverAddr, v.serverName, v.zone)
362 continue
363 }
364 if !v.updated {
365 if v.notSeenTimes++; v.notSeenTimes >= notSeenLimit {
366 delete(c.cache.streamUpstreamServers, key)
367 c.removeStreamUpstreamServerCharts(v.name, v.serverAddr, v.zone)
368 }
369 }
370 }
371 for key, v := range c.cache.resolvers {
372 if v.updated && !v.hasCharts {
373 v.hasCharts = true
374 c.addResolverZoneCharts(v.zone)
375 continue
376 }
377 if !v.updated {
378 if v.notSeenTimes++; v.notSeenTimes >= notSeenLimit {
379 delete(c.cache.resolvers, key)
380 c.removeResolverZoneCharts(v.zone)
381 }
382 }
383 }
384 }