Skip to content

Commit a365950

Browse files
authored
Add stream metrics support (#16)
Closes: #1 * Add streamUpstream metrics * Add streamUpstreamServer metrics * Add streamServerZone metrics * Metric descriptor must be the same for every metric with the same metricName, so Metric descriptions must be the same regardless of label * Add stream metrics documentation to readme * Fix readme typo Upsteams->Upstreams
1 parent 4d8ada8 commit a365950

File tree

2 files changed

+116
-4
lines changed

2 files changed

+116
-4
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,10 @@ Usage of ./nginx-prometheus-exporter:
7070
* [HTTP](http://nginx.org/en/docs/http/ngx_http_api_module.html#http_).
7171
* [SSL](http://nginx.org/en/docs/http/ngx_http_api_module.html#def_nginx_ssl_object).
7272
* [HTTP Server Zones](http://nginx.org/en/docs/http/ngx_http_api_module.html#def_nginx_http_server_zone).
73-
* [HTTP Upsteams](http://nginx.org/en/docs/http/ngx_http_api_module.html#def_nginx_http_upstream). Note: for the `state` metric, the string values are converted to float64 using the following rule: `"up"` -> `1.0`, `"draining"` -> `2.0`, `"down"` -> `3.0`, `"unavail"` –> `4.0`, `"checking"` –> `5.0`, `"unhealthy"` -> `6.0`.
73+
* [Stream Server Zones](http://nginx.org/en/docs/http/ngx_http_api_module.html#def_nginx_stream_server_zone).
74+
* [HTTP Upstreams](http://nginx.org/en/docs/http/ngx_http_api_module.html#def_nginx_http_upstream). Note: for the `state` metric, the string values are converted to float64 using the following rule: `"up"` -> `1.0`, `"draining"` -> `2.0`, `"down"` -> `3.0`, `"unavail"` –> `4.0`, `"checking"` –> `5.0`, `"unhealthy"` -> `6.0`.
75+
* [Stream Upstreams](http://nginx.org/en/docs/http/ngx_http_api_module.html#def_nginx_stream_upstream). Note: for the `state` metric, the string values are converted to float64 using the following rule: `"up"` -> `1.0`, `"down"` -> `3.0`, `"unavail"` –> `4.0`, `"checking"` –> `5.0`, `"unhealthy"` -> `6.0`.
76+
7477
7578
Connect to the `/metrics` page of the running exporter to see the complete list of metrics along with their descriptions. Note: to see server zones related metrics you must configure [status zones](https://nginx.org/en/docs/http/ngx_http_status_module.html#status_zone) and to see upstream related metrics you must configure upstreams with a [shared memory zone](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#zone).
7679

collector/nginx_plus.go

Lines changed: 112 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,15 @@ import (
1010

1111
// NginxPlusCollector collects NGINX Plus metrics. It implements prometheus.Collector interface.
1212
type NginxPlusCollector struct {
13-
nginxClient *plusclient.NginxClient
14-
totalMetrics, serverZoneMetrics, upstreamMetrics, upstreamServerMetrics map[string]*prometheus.Desc
15-
mutex sync.Mutex
13+
nginxClient *plusclient.NginxClient
14+
totalMetrics map[string]*prometheus.Desc
15+
serverZoneMetrics map[string]*prometheus.Desc
16+
upstreamMetrics map[string]*prometheus.Desc
17+
upstreamServerMetrics map[string]*prometheus.Desc
18+
streamServerZoneMetrics map[string]*prometheus.Desc
19+
streamUpstreamMetrics map[string]*prometheus.Desc
20+
streamUpstreamServerMetrics map[string]*prometheus.Desc
21+
mutex sync.Mutex
1622
}
1723

1824
// NewNginxPlusCollector creates an NginxPlusCollector.
@@ -42,10 +48,23 @@ func NewNginxPlusCollector(nginxClient *plusclient.NginxClient, namespace string
4248
"received": newServerZoneMetric(namespace, "received", "Bytes received from clients", nil),
4349
"sent": newServerZoneMetric(namespace, "sent", "Bytes sent to clients", nil),
4450
},
51+
streamServerZoneMetrics: map[string]*prometheus.Desc{
52+
"processing": newStreamServerZoneMetric(namespace, "processing", "Client connections that are currently being processed", nil),
53+
"connections": newStreamServerZoneMetric(namespace, "connections", "Total connections", nil),
54+
"sessions_2xx": newStreamServerZoneMetric(namespace, "sessions", "Total sessions completed", prometheus.Labels{"code": "2xx"}),
55+
"sessions_4xx": newStreamServerZoneMetric(namespace, "sessions", "Total sessions completed", prometheus.Labels{"code": "4xx"}),
56+
"sessions_5xx": newStreamServerZoneMetric(namespace, "sessions", "Total sessions completed", prometheus.Labels{"code": "5xx"}),
57+
"discarded": newStreamServerZoneMetric(namespace, "discarded", "Connections completed without creating a session", nil),
58+
"received": newStreamServerZoneMetric(namespace, "received", "Bytes received from clients", nil),
59+
"sent": newStreamServerZoneMetric(namespace, "sent", "Bytes sent to clients", nil),
60+
},
4561
upstreamMetrics: map[string]*prometheus.Desc{
4662
"keepalives": newUpstreamMetric(namespace, "keepalives", "Idle keepalive connections"),
4763
"zombies": newUpstreamMetric(namespace, "zombies", "Servers removed from the group but still processing active client requests"),
4864
},
65+
streamUpstreamMetrics: map[string]*prometheus.Desc{
66+
"zombies": newStreamUpstreamMetric(namespace, "zombies", "Servers removed from the group but still processing active client connections"),
67+
},
4968
upstreamServerMetrics: map[string]*prometheus.Desc{
5069
"state": newUpstreamServerMetric(namespace, "state", "Current state", nil),
5170
"active": newUpstreamServerMetric(namespace, "active", "Active connections", nil),
@@ -65,6 +84,21 @@ func NewNginxPlusCollector(nginxClient *plusclient.NginxClient, namespace string
6584
"health_checks_fails": newUpstreamServerMetric(namespace, "health_checks_fails", "Failed health checks", nil),
6685
"health_checks_unhealthy": newUpstreamServerMetric(namespace, "health_checks_unhealthy", "How many times the server became unhealthy (state 'unhealthy')", nil),
6786
},
87+
streamUpstreamServerMetrics: map[string]*prometheus.Desc{
88+
"state": newStreamUpstreamServerMetric(namespace, "state", "Current state"),
89+
"active": newStreamUpstreamServerMetric(namespace, "active", "Active connections"),
90+
"sent": newStreamUpstreamServerMetric(namespace, "sent", "Bytes sent to this server"),
91+
"received": newStreamUpstreamServerMetric(namespace, "received", "Bytes received from this server"),
92+
"fails": newStreamUpstreamServerMetric(namespace, "fails", "Number of unsuccessful attempts to communicate with the server"),
93+
"unavail": newStreamUpstreamServerMetric(namespace, "unavail", "How many times the server became unavailable for client connections (state 'unavail') due to the number of unsuccessful attempts reaching the max_fails threshold"),
94+
"connections": newStreamUpstreamServerMetric(namespace, "connections", "Total number of client connections forwarded to this server"),
95+
"connect_time": newStreamUpstreamServerMetric(namespace, "connect_time", "Average time to connect to the upstream server"),
96+
"first_byte_time": newStreamUpstreamServerMetric(namespace, "first_byte_time", "Average time to receive the first byte of data"),
97+
"response_time": newStreamUpstreamServerMetric(namespace, "response_time", "Average time to receive the last byte of data"),
98+
"health_checks_checks": newStreamUpstreamServerMetric(namespace, "health_checks_checks", "Total health check requests"),
99+
"health_checks_fails": newStreamUpstreamServerMetric(namespace, "health_checks_fails", "Failed health checks"),
100+
"health_checks_unhealthy": newStreamUpstreamServerMetric(namespace, "health_checks_unhealthy", "How many times the server became unhealthy (state 'unhealthy')"),
101+
},
68102
}
69103
}
70104

@@ -83,6 +117,15 @@ func (c *NginxPlusCollector) Describe(ch chan<- *prometheus.Desc) {
83117
for _, m := range c.upstreamServerMetrics {
84118
ch <- m
85119
}
120+
for _, m := range c.streamServerZoneMetrics {
121+
ch <- m
122+
}
123+
for _, m := range c.streamUpstreamMetrics {
124+
ch <- m
125+
}
126+
for _, m := range c.streamUpstreamServerMetrics {
127+
ch <- m
128+
}
86129
}
87130

88131
// Collect fetches metrics from NGINX Plus and sends them to the provided channel.
@@ -138,6 +181,25 @@ func (c *NginxPlusCollector) Collect(ch chan<- prometheus.Metric) {
138181
prometheus.CounterValue, float64(zone.Sent), name)
139182
}
140183

184+
for name, zone := range stats.StreamServerZones {
185+
ch <- prometheus.MustNewConstMetric(c.streamServerZoneMetrics["processing"],
186+
prometheus.GaugeValue, float64(zone.Processing), name)
187+
ch <- prometheus.MustNewConstMetric(c.streamServerZoneMetrics["connections"],
188+
prometheus.CounterValue, float64(zone.Connections), name)
189+
ch <- prometheus.MustNewConstMetric(c.streamServerZoneMetrics["sessions_2xx"],
190+
prometheus.CounterValue, float64(zone.Sessions.Sessions2xx), name)
191+
ch <- prometheus.MustNewConstMetric(c.streamServerZoneMetrics["sessions_4xx"],
192+
prometheus.CounterValue, float64(zone.Sessions.Sessions4xx), name)
193+
ch <- prometheus.MustNewConstMetric(c.streamServerZoneMetrics["sessions_5xx"],
194+
prometheus.CounterValue, float64(zone.Sessions.Sessions5xx), name)
195+
ch <- prometheus.MustNewConstMetric(c.streamServerZoneMetrics["discarded"],
196+
prometheus.CounterValue, float64(zone.Discarded), name)
197+
ch <- prometheus.MustNewConstMetric(c.streamServerZoneMetrics["received"],
198+
prometheus.CounterValue, float64(zone.Received), name)
199+
ch <- prometheus.MustNewConstMetric(c.streamServerZoneMetrics["sent"],
200+
prometheus.CounterValue, float64(zone.Sent), name)
201+
}
202+
141203
for name, upstream := range stats.Upstreams {
142204
for _, peer := range upstream.Peers {
143205
ch <- prometheus.MustNewConstMetric(c.upstreamServerMetrics["state"],
@@ -183,6 +245,41 @@ func (c *NginxPlusCollector) Collect(ch chan<- prometheus.Metric) {
183245
ch <- prometheus.MustNewConstMetric(c.upstreamMetrics["zombies"],
184246
prometheus.GaugeValue, float64(upstream.Zombies), name)
185247
}
248+
249+
for name, upstream := range stats.StreamUpstreams {
250+
for _, peer := range upstream.Peers {
251+
ch <- prometheus.MustNewConstMetric(c.streamUpstreamServerMetrics["state"],
252+
prometheus.GaugeValue, upstreamServerStates[peer.State], name, peer.Server)
253+
ch <- prometheus.MustNewConstMetric(c.streamUpstreamServerMetrics["active"],
254+
prometheus.GaugeValue, float64(peer.Active), name, peer.Server)
255+
ch <- prometheus.MustNewConstMetric(c.streamUpstreamServerMetrics["connections"],
256+
prometheus.CounterValue, float64(peer.Connections), name, peer.Server)
257+
ch <- prometheus.MustNewConstMetric(c.streamUpstreamServerMetrics["connect_time"],
258+
prometheus.GaugeValue, float64(peer.ConnectTime), name, peer.Server)
259+
ch <- prometheus.MustNewConstMetric(c.streamUpstreamServerMetrics["first_byte_time"],
260+
prometheus.GaugeValue, float64(peer.FirstByteTime), name, peer.Server)
261+
ch <- prometheus.MustNewConstMetric(c.streamUpstreamServerMetrics["response_time"],
262+
prometheus.GaugeValue, float64(peer.ResponseTime), name, peer.Server)
263+
ch <- prometheus.MustNewConstMetric(c.streamUpstreamServerMetrics["sent"],
264+
prometheus.CounterValue, float64(peer.Sent), name, peer.Server)
265+
ch <- prometheus.MustNewConstMetric(c.streamUpstreamServerMetrics["received"],
266+
prometheus.CounterValue, float64(peer.Received), name, peer.Server)
267+
ch <- prometheus.MustNewConstMetric(c.streamUpstreamServerMetrics["fails"],
268+
prometheus.CounterValue, float64(peer.Fails), name, peer.Server)
269+
ch <- prometheus.MustNewConstMetric(c.streamUpstreamServerMetrics["unavail"],
270+
prometheus.CounterValue, float64(peer.Unavail), name, peer.Server)
271+
if peer.HealthChecks != (plusclient.HealthChecks{}) {
272+
ch <- prometheus.MustNewConstMetric(c.streamUpstreamServerMetrics["health_checks_checks"],
273+
prometheus.CounterValue, float64(peer.HealthChecks.Checks), name, peer.Server)
274+
ch <- prometheus.MustNewConstMetric(c.streamUpstreamServerMetrics["health_checks_fails"],
275+
prometheus.CounterValue, float64(peer.HealthChecks.Fails), name, peer.Server)
276+
ch <- prometheus.MustNewConstMetric(c.streamUpstreamServerMetrics["health_checks_unhealthy"],
277+
prometheus.CounterValue, float64(peer.HealthChecks.Unhealthy), name, peer.Server)
278+
}
279+
}
280+
ch <- prometheus.MustNewConstMetric(c.streamUpstreamMetrics["zombies"],
281+
prometheus.GaugeValue, float64(upstream.Zombies), name)
282+
}
186283
}
187284

188285
var upstreamServerStates = map[string]float64{
@@ -198,10 +295,22 @@ func newServerZoneMetric(namespace string, metricName string, docString string,
198295
return prometheus.NewDesc(prometheus.BuildFQName(namespace, "server_zone", metricName), docString, []string{"server_zone"}, constLabels)
199296
}
200297

298+
func newStreamServerZoneMetric(namespace string, metricName string, docString string, constLabels prometheus.Labels) *prometheus.Desc {
299+
return prometheus.NewDesc(prometheus.BuildFQName(namespace, "stream_server_zone", metricName), docString, []string{"server_zone"}, constLabels)
300+
}
301+
201302
func newUpstreamMetric(namespace string, metricName string, docString string) *prometheus.Desc {
202303
return prometheus.NewDesc(prometheus.BuildFQName(namespace, "upstream", metricName), docString, []string{"upstream"}, nil)
203304
}
204305

306+
func newStreamUpstreamMetric(namespace string, metricName string, docString string) *prometheus.Desc {
307+
return prometheus.NewDesc(prometheus.BuildFQName(namespace, "stream_upstream", metricName), docString, []string{"upstream"}, nil)
308+
}
309+
205310
func newUpstreamServerMetric(namespace string, metricName string, docString string, constLabels prometheus.Labels) *prometheus.Desc {
206311
return prometheus.NewDesc(prometheus.BuildFQName(namespace, "upstream_server", metricName), docString, []string{"upstream", "server"}, constLabels)
207312
}
313+
314+
func newStreamUpstreamServerMetric(namespace string, metricName string, docString string) *prometheus.Desc {
315+
return prometheus.NewDesc(prometheus.BuildFQName(namespace, "stream_upstream_server", metricName), docString, []string{"upstream", "server"}, nil)
316+
}

0 commit comments

Comments
 (0)