Skip to content

Commit

Permalink
Add metrics from NGINX Plus API version 9
Browse files Browse the repository at this point in the history
Signed-off-by: Haywood Shannon <[email protected]>
  • Loading branch information
haywoodsh committed Oct 26, 2023
1 parent ed87722 commit 111dcfd
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 3 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,17 @@ Name | Type | Description | Labels
`nginxplus_stream_limit_connection_rejected` | Counter | Total number of connections that were rejected | `zone` |
`nginxplus_stream_limit_connection_rejected_dry_run` | Counter | Total number of connections accounted as rejected in the dry run mode | `zone` |

#### [Worker Metrics](hhttps://nginx.org/en/docs/http/ngx_http_api_module.html#workers)

Name | Type | Description | Labels
----|-------|----|------------|
`nginxplus_worker_connection_accepted` | Counter | The total number of accepted client connections | `id`, `pid` |
`nginxplus_worker_connection_dropped` | Counter | The total number of accepted client connections | `id`, `pid` |
`nginxplus_worker_connection_active` | Gauge | The current number of active client connections | `id`, `pid` |
`nginxplus_worker_connection_idle` | Gauge | The current number of idle client connection | `id`, `pid` |
`nginxplus_worker_http_requests_total` | Counter | The total number of client requests received by the worker process | `id`, `pid` |
`nginxplus_worker_http_requests_current` | Gauge | The current number of client requests that are currently being processed by the worker process | `id`, `pid` |

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
Expand Down
74 changes: 72 additions & 2 deletions collector/nginx_plus.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package collector

import (
"fmt"
"strconv"
"sync"

"github.com/go-kit/log"
Expand All @@ -24,6 +25,8 @@ type LabelUpdater interface {
DeleteServerZoneLabels(zoneNames []string)
UpdateStreamServerZoneLabels(streamServerZoneLabelValues map[string][]string)
DeleteStreamServerZoneLabels(zoneNames []string)
UpdateWorkerLabels(workerLabelValues map[string][]string)
DeleteWorkerLabels(workerNames []string)
}

// NginxPlusCollector collects NGINX Plus metrics. It implements prometheus.Collector interface.
Expand Down Expand Up @@ -53,6 +56,8 @@ type NginxPlusCollector struct {
streamUpstreamServerPeerLabels map[string][]string
variableLabelsMutex sync.RWMutex
logger log.Logger
workerLabels map[string][]string
workerMetrics map[string]*prometheus.Desc
}

// UpdateUpstreamServerPeerLabels updates the Upstream Server Peer Labels
Expand Down Expand Up @@ -199,6 +204,30 @@ func (c *NginxPlusCollector) getStreamUpstreamServerPeerLabelValues(peer string)
return c.streamUpstreamServerPeerLabels[peer]
}

// UpdateWorkerLabels updates the Worker Labels
func (c *NginxPlusCollector) UpdateWorkerLabels(workerLabelValues map[string][]string) {
c.variableLabelsMutex.Lock()
for k, v := range workerLabelValues {
c.workerLabels[k] = v
}
c.variableLabelsMutex.Unlock()
}

// DeleteWorkerLabels deletes the Worker Labels
func (c *NginxPlusCollector) DeleteWorkerLabels(id []string) {
c.variableLabelsMutex.Lock()
for _, k := range id {
delete(c.workerLabels, k)
}
c.variableLabelsMutex.Unlock()
}

func (c *NginxPlusCollector) getWorkerLabelValues(id string) []string {
c.variableLabelsMutex.RLock()
defer c.variableLabelsMutex.RUnlock()
return c.workerLabels[id]
}

// VariableLabelNames holds all the variable label names for the different metrics
type VariableLabelNames struct {
UpstreamServerVariableLabelNames []string
Expand All @@ -207,11 +236,12 @@ type VariableLabelNames struct {
StreamUpstreamServerPeerVariableLabelNames []string
StreamServerZoneVariableLabelNames []string
StreamUpstreamServerVariableLabelNames []string
WorkerPIDVariableLabelNames []string
}

// NewVariableLabels creates a new struct for VariableNames for the collector
// NewVariableLabelNames NewVariableLabels creates a new struct for VariableNames for the collector
func NewVariableLabelNames(upstreamServerVariableLabelNames []string, serverZoneVariableLabelNames []string, upstreamServerPeerVariableLabelNames []string,
streamUpstreamServerVariableLabelNames []string, streamServerZoneLabels []string, streamUpstreamServerPeerVariableLabelNames []string,
streamUpstreamServerVariableLabelNames []string, streamServerZoneLabels []string, streamUpstreamServerPeerVariableLabelNames []string, workerPIDVariableLabelNames []string,
) VariableLabelNames {
return VariableLabelNames{
UpstreamServerVariableLabelNames: upstreamServerVariableLabelNames,
Expand All @@ -220,6 +250,7 @@ func NewVariableLabelNames(upstreamServerVariableLabelNames []string, serverZone
StreamUpstreamServerVariableLabelNames: streamUpstreamServerVariableLabelNames,
StreamServerZoneVariableLabelNames: streamServerZoneLabels,
StreamUpstreamServerPeerVariableLabelNames: streamUpstreamServerPeerVariableLabelNames,
WorkerPIDVariableLabelNames: workerPIDVariableLabelNames,
}
}

Expand Down Expand Up @@ -496,6 +527,14 @@ func NewNginxPlusCollector(nginxClient *plusclient.NginxClient, namespace string
"rejected_dry_run": newStreamLimitConnectionMetric(namespace, "rejected_dry_run", "Total number of connections accounted as rejected in the dry run mode", constLabels),
},
upMetric: newUpMetric(namespace, constLabels),
workerMetrics: map[string]*prometheus.Desc{
"connection_accepted": newWorkerMetric(namespace, "connection_accepted", "The total number of accepted client connections", variableLabelNames.WorkerPIDVariableLabelNames, constLabels),
"connection_dropped": newWorkerMetric(namespace, "connection_dropped", "The total number of dropped client connections", variableLabelNames.WorkerPIDVariableLabelNames, constLabels),
"connection_active": newWorkerMetric(namespace, "connection_active", "The current number of active client connections", variableLabelNames.WorkerPIDVariableLabelNames, constLabels),
"connection_idle": newWorkerMetric(namespace, "connection_idle", "The current number of idle client connections", variableLabelNames.WorkerPIDVariableLabelNames, constLabels),
"http_requests_total": newWorkerMetric(namespace, "http_requests_total", "The total number of client requests received by the worker process", variableLabelNames.WorkerPIDVariableLabelNames, constLabels),
"http_requests_current": newWorkerMetric(namespace, "http_requests_current", "The current number of client requests that are currently being processed by the worker process", variableLabelNames.WorkerPIDVariableLabelNames, constLabels),
},
}
}

Expand Down Expand Up @@ -543,6 +582,9 @@ func (c *NginxPlusCollector) Describe(ch chan<- *prometheus.Desc) {
for _, m := range c.streamLimitConnectionMetrics {
ch <- m
}
for _, m := range c.workerMetrics {
ch <- m
}
}

// Collect fetches metrics from NGINX Plus and sends them to the provided channel.
Expand Down Expand Up @@ -1125,6 +1167,28 @@ func (c *NginxPlusCollector) Collect(ch chan<- prometheus.Metric) {
ch <- prometheus.MustNewConstMetric(c.streamLimitConnectionMetrics["rejected"], prometheus.CounterValue, float64(zone.Rejected), name)
ch <- prometheus.MustNewConstMetric(c.streamLimitConnectionMetrics["rejected_dry_run"], prometheus.CounterValue, float64(zone.RejectedDryRun), name)
}

for _, worker := range stats.Workers {
labelValues := []string{strconv.FormatInt(int64(worker.ID), 10), strconv.FormatInt(int64(worker.ProcessID), 10)}
varLabelValues := c.getWorkerLabelValues(strconv.FormatInt(int64(worker.ID), 10))

if c.variableLabelNames.WorkerPIDVariableLabelNames != nil && len(varLabelValues) != len(c.variableLabelNames.WorkerPIDVariableLabelNames) {
level.Warn(c.logger).Log("wrong number of labels for worker %v. For labels %v, got values: %v. Empty labels will be used instead",
strconv.FormatInt(int64(worker.ID), 10), c.variableLabelNames.WorkerPIDVariableLabelNames, varLabelValues)
for range c.variableLabelNames.WorkerPIDVariableLabelNames {
labelValues = append(labelValues, "")
}
} else {
labelValues = append(labelValues, varLabelValues...)
}

ch <- prometheus.MustNewConstMetric(c.workerMetrics["connection_accepted"], prometheus.CounterValue, float64(worker.Connections.Accepted), labelValues...)
ch <- prometheus.MustNewConstMetric(c.workerMetrics["connection_dropped"], prometheus.CounterValue, float64(worker.Connections.Dropped), labelValues...)
ch <- prometheus.MustNewConstMetric(c.workerMetrics["connection_active"], prometheus.GaugeValue, float64(worker.Connections.Active), labelValues...)
ch <- prometheus.MustNewConstMetric(c.workerMetrics["connection_idle"], prometheus.GaugeValue, float64(worker.Connections.Idle), labelValues...)
ch <- prometheus.MustNewConstMetric(c.workerMetrics["http_requests_total"], prometheus.CounterValue, float64(worker.HTTP.HTTPRequests.Total), labelValues...)
ch <- prometheus.MustNewConstMetric(c.workerMetrics["http_requests_current"], prometheus.GaugeValue, float64(worker.HTTP.HTTPRequests.Current), labelValues...)
}
}

var upstreamServerStates = map[string]float64{
Expand Down Expand Up @@ -1195,3 +1259,9 @@ func newLimitConnectionMetric(namespace string, metricName string, docString str
func newStreamLimitConnectionMetric(namespace string, metricName string, docString string, constLabels prometheus.Labels) *prometheus.Desc {
return prometheus.NewDesc(prometheus.BuildFQName(namespace, "stream_limit_connection", metricName), docString, []string{"zone"}, constLabels)
}

func newWorkerMetric(namespace string, metricName string, docString string, variableLabelNames []string, constLabels prometheus.Labels) *prometheus.Desc {
labels := []string{"id", "pid"}
labels = append(labels, variableLabelNames...)
return prometheus.NewDesc(prometheus.BuildFQName(namespace, "worker", metricName), docString, labels, constLabels)
}
2 changes: 1 addition & 1 deletion exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ func main() {
level.Error(logger).Log("msg", "Could not create Nginx Plus Client", "error", err.Error())
os.Exit(1)
}
variableLabelNames := collector.NewVariableLabelNames(nil, nil, nil, nil, nil, nil)
variableLabelNames := collector.NewVariableLabelNames(nil, nil, nil, nil, nil, nil, nil)
prometheus.MustRegister(collector.NewNginxPlusCollector(plusClient, "nginxplus", variableLabelNames, constLabels, logger))
} else {
ossClient := client.NewNginxClient(httpClient, *scrapeURI)
Expand Down

0 comments on commit 111dcfd

Please sign in to comment.