You've already forked nginx_exporter
mirror of
https://github.com/nginxinc/nginx-prometheus-exporter.git
synced 2025-08-09 16:02:43 +03:00
Replace flag with kingpin and use promlog (#420)
This commit is contained in:
22
.github/workflows/ci.yml
vendored
22
.github/workflows/ci.yml
vendored
@@ -4,27 +4,16 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- 'LICENSE'
|
||||
tags:
|
||||
- 'v[0-9]+.[0-9]+.[0-9]+'
|
||||
- "v[0-9]+.[0-9]+.[0-9]+"
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- 'LICENSE'
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- synchronize
|
||||
|
||||
env:
|
||||
DOCKER_PLATFORMS: "linux/arm,linux/arm64,linux/amd64,linux/ppc64le,linux/s390x,linux/mips64le,linux/386"
|
||||
|
||||
jobs:
|
||||
|
||||
unit-tests:
|
||||
name: Unit Tests
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -65,7 +54,6 @@ jobs:
|
||||
run: |
|
||||
echo "go_path=$(go env GOPATH)" >> $GITHUB_OUTPUT
|
||||
- name: Setup QEMU
|
||||
|
||||
uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # v2.1.0
|
||||
with:
|
||||
platforms: arm,arm64,ppc64le,s390x,mips64le,386
|
||||
@@ -142,18 +130,22 @@ jobs:
|
||||
uses: goreleaser/goreleaser-action@f82d6c1c344bcacabba2c841718984797f664a6b # v4.2.0
|
||||
with:
|
||||
version: latest
|
||||
args: ${{ !startsWith(github.ref, 'refs/tags/') && 'build --snapshot' || 'release' }} ${{ github.event_name == 'pull_request' && '--single-target' || '' }} --rm-dist
|
||||
args: ${{ !startsWith(github.ref, 'refs/tags/') && 'build --snapshot' || 'release' }} ${{ github.event_name == 'pull_request' && '--single-target' || '' }} --clean
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GOPATH: ${{ steps.go.outputs.go_path }}
|
||||
HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.NGINX_PAT }}
|
||||
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_COMMUNITY }}
|
||||
|
||||
- name: Print NGINX Prometheus Exporter info
|
||||
run: ./dist/nginx-prometheus-exporter_linux_amd64_v1/nginx-prometheus-exporter --version
|
||||
continue-on-error: true
|
||||
|
||||
- name: Build and Push Docker Image
|
||||
uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 # v4.0.0
|
||||
with:
|
||||
file: build/Dockerfile
|
||||
context: '.'
|
||||
context: "."
|
||||
target: goreleaser
|
||||
platforms: ${{ github.event_name != 'pull_request' && env.DOCKER_PLATFORMS || '' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
|
@@ -28,6 +28,9 @@ linters-settings:
|
||||
- name: unused-parameter
|
||||
- name: var-declaration
|
||||
- name: var-naming
|
||||
errcheck:
|
||||
exclude-functions:
|
||||
- (github.com/go-kit/log.Logger).Log
|
||||
|
||||
linters:
|
||||
enable:
|
||||
|
@@ -1,8 +1,3 @@
|
||||
before:
|
||||
hooks:
|
||||
- go mod tidy
|
||||
- go mod verify
|
||||
|
||||
builds:
|
||||
- env:
|
||||
- CGO_ENABLED=0
|
||||
@@ -33,26 +28,27 @@ builds:
|
||||
- all=-trimpath={{.Env.GOPATH}}
|
||||
asmflags:
|
||||
- all=-trimpath={{.Env.GOPATH}}
|
||||
|
||||
sboms:
|
||||
- artifacts: archive
|
||||
|
||||
archives:
|
||||
- format_overrides:
|
||||
- goos: windows
|
||||
format: zip
|
||||
|
||||
checksum:
|
||||
name_template: 'sha256sums.txt'
|
||||
ldflags:
|
||||
- '-s -w -X github.com/prometheus/common/version.Version={{.Version}} -X github.com/prometheus/common/version.BuildDate={{.Date}} -X github.com/prometheus/common/version.Branch={{.Branch}} -X github.com/prometheus/common/version.BuildUser=goreleaser'
|
||||
|
||||
changelog:
|
||||
skip: true
|
||||
|
||||
archives:
|
||||
- format_overrides:
|
||||
- goos: windows
|
||||
format: zip
|
||||
|
||||
sboms:
|
||||
- artifacts: archive
|
||||
documents:
|
||||
- "${artifact}.spdx.json"
|
||||
|
||||
brews:
|
||||
- tap:
|
||||
owner: nginxinc
|
||||
name: homebrew-tap
|
||||
token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}"
|
||||
token: '{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}'
|
||||
folder: Formula
|
||||
homepage: https://www.nginx.com/
|
||||
description: NGINX Prometheus Exporter for NGINX and NGINX Plus
|
||||
@@ -71,3 +67,6 @@ announce:
|
||||
|
||||
milestones:
|
||||
- close: true
|
||||
|
||||
snapshot:
|
||||
name_template: 'edge'
|
||||
|
4
Makefile
4
Makefile
@@ -4,12 +4,12 @@ PREFIX = nginx/nginx-prometheus-exporter
|
||||
|
||||
.PHONY: nginx-prometheus-exporter
|
||||
nginx-prometheus-exporter:
|
||||
CGO_ENABLED=0 go build -trimpath -ldflags "-s -w -X main.version=$(VERSION)" -o nginx-prometheus-exporter
|
||||
CGO_ENABLED=0 go build -trimpath -ldflags "-s -w -X github.com/prometheus/common/version.Version=$(VERSION)" -o nginx-prometheus-exporter
|
||||
|
||||
.PHONY: build-goreleaser
|
||||
build-goreleaser: ## Build all binaries using GoReleaser
|
||||
@goreleaser -v || (code=$$?; printf "\033[0;31mError\033[0m: there was a problem with GoReleaser. Follow the docs to install it https://goreleaser.com/install\n"; exit $$code)
|
||||
GOPATH=$(shell go env GOPATH) goreleaser build --rm-dist --snapshot
|
||||
GOPATH=$(shell go env GOPATH) goreleaser build --clean --snapshot
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
|
@@ -1,9 +1,10 @@
|
||||
package collector
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/nginxinc/nginx-prometheus-exporter/client"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
@@ -14,12 +15,14 @@ type NginxCollector struct {
|
||||
metrics map[string]*prometheus.Desc
|
||||
upMetric prometheus.Gauge
|
||||
mutex sync.Mutex
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
// NewNginxCollector creates an NginxCollector.
|
||||
func NewNginxCollector(nginxClient *client.NginxClient, namespace string, constLabels map[string]string) *NginxCollector {
|
||||
func NewNginxCollector(nginxClient *client.NginxClient, namespace string, constLabels map[string]string, logger log.Logger) *NginxCollector {
|
||||
return &NginxCollector{
|
||||
nginxClient: nginxClient,
|
||||
logger: logger,
|
||||
metrics: map[string]*prometheus.Desc{
|
||||
"connections_active": newGlobalMetric(namespace, "connections_active", "Active client connections", constLabels),
|
||||
"connections_accepted": newGlobalMetric(namespace, "connections_accepted", "Accepted client connections", constLabels),
|
||||
@@ -52,7 +55,7 @@ func (c *NginxCollector) Collect(ch chan<- prometheus.Metric) {
|
||||
if err != nil {
|
||||
c.upMetric.Set(nginxDown)
|
||||
ch <- c.upMetric
|
||||
log.Printf("Error getting stats: %v", err)
|
||||
level.Error(c.logger).Log("msg", "Error getting stats", "error", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
@@ -2,9 +2,10 @@ package collector
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
plusclient "github.com/nginxinc/nginx-plus-go-client/client"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
@@ -51,6 +52,7 @@ type NginxPlusCollector struct {
|
||||
upstreamServerPeerLabels map[string][]string
|
||||
streamUpstreamServerPeerLabels map[string][]string
|
||||
variableLabelsMutex sync.RWMutex
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
// UpdateUpstreamServerPeerLabels updates the Upstream Server Peer Labels
|
||||
@@ -222,7 +224,7 @@ func NewVariableLabelNames(upstreamServerVariableLabelNames []string, serverZone
|
||||
}
|
||||
|
||||
// NewNginxPlusCollector creates an NginxPlusCollector.
|
||||
func NewNginxPlusCollector(nginxClient *plusclient.NginxClient, namespace string, variableLabelNames VariableLabelNames, constLabels map[string]string) *NginxPlusCollector {
|
||||
func NewNginxPlusCollector(nginxClient *plusclient.NginxClient, namespace string, variableLabelNames VariableLabelNames, constLabels map[string]string, logger log.Logger) *NginxPlusCollector {
|
||||
upstreamServerVariableLabelNames := append(variableLabelNames.UpstreamServerVariableLabelNames, variableLabelNames.UpstreamServerPeerVariableLabelNames...)
|
||||
streamUpstreamServerVariableLabelNames := append(variableLabelNames.StreamUpstreamServerVariableLabelNames, variableLabelNames.StreamUpstreamServerPeerVariableLabelNames...)
|
||||
return &NginxPlusCollector{
|
||||
@@ -234,6 +236,7 @@ func NewNginxPlusCollector(nginxClient *plusclient.NginxClient, namespace string
|
||||
streamUpstreamServerPeerLabels: make(map[string][]string),
|
||||
streamUpstreamServerLabels: make(map[string][]string),
|
||||
nginxClient: nginxClient,
|
||||
logger: logger,
|
||||
totalMetrics: map[string]*prometheus.Desc{
|
||||
"connections_accepted": newGlobalMetric(namespace, "connections_accepted", "Accepted client connections", constLabels),
|
||||
"connections_dropped": newGlobalMetric(namespace, "connections_dropped", "Dropped client connections", constLabels),
|
||||
@@ -551,7 +554,7 @@ func (c *NginxPlusCollector) Collect(ch chan<- prometheus.Metric) {
|
||||
if err != nil {
|
||||
c.upMetric.Set(nginxDown)
|
||||
ch <- c.upMetric
|
||||
log.Printf("Error getting stats: %v", err)
|
||||
level.Warn(c.logger).Log("msg", "Error getting stats", "error", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
@@ -582,8 +585,7 @@ func (c *NginxPlusCollector) Collect(ch chan<- prometheus.Metric) {
|
||||
varLabelValues := c.getServerZoneLabelValues(name)
|
||||
|
||||
if c.variableLabelNames.ServerZoneVariableLabelNames != nil && len(varLabelValues) != len(c.variableLabelNames.ServerZoneVariableLabelNames) {
|
||||
log.Printf("wrong number of labels for http zone %v. For labels %v, got values: %v. Empty labels will be used instead",
|
||||
name, c.variableLabelNames.ServerZoneVariableLabelNames, varLabelValues)
|
||||
level.Warn(c.logger).Log("msg", "wrong number of labels for http zone, empty labels will be used instead", "zone", name, "expected", len(c.variableLabelNames.ServerZoneVariableLabelNames), "got", len(varLabelValues))
|
||||
for range c.variableLabelNames.ServerZoneVariableLabelNames {
|
||||
labelValues = append(labelValues, "")
|
||||
}
|
||||
@@ -704,8 +706,7 @@ func (c *NginxPlusCollector) Collect(ch chan<- prometheus.Metric) {
|
||||
varLabelValues := c.getStreamServerZoneLabelValues(name)
|
||||
|
||||
if c.variableLabelNames.StreamServerZoneVariableLabelNames != nil && len(varLabelValues) != len(c.variableLabelNames.StreamServerZoneVariableLabelNames) {
|
||||
log.Printf("wrong number of labels for stream server zone %v. For labels %v, got values: %v. Empty labels will be used instead",
|
||||
name, c.variableLabelNames.StreamServerZoneVariableLabelNames, varLabelValues)
|
||||
level.Warn(c.logger).Log("msg", "wrong number of labels for stream server zone, empty labels will be used instead", "zone", name, "expected", len(c.variableLabelNames.StreamServerZoneVariableLabelNames), "got", len(varLabelValues))
|
||||
for range c.variableLabelNames.StreamServerZoneVariableLabelNames {
|
||||
labelValues = append(labelValues, "")
|
||||
}
|
||||
@@ -742,8 +743,7 @@ func (c *NginxPlusCollector) Collect(ch chan<- prometheus.Metric) {
|
||||
varLabelValues := c.getUpstreamServerLabelValues(name)
|
||||
|
||||
if c.variableLabelNames.UpstreamServerVariableLabelNames != nil && len(varLabelValues) != len(c.variableLabelNames.UpstreamServerVariableLabelNames) {
|
||||
log.Printf("wrong number of labels for upstream %v. For labels %v, got values: %v. Empty labels will be used instead",
|
||||
name, c.variableLabelNames.UpstreamServerVariableLabelNames, varLabelValues)
|
||||
level.Warn(c.logger).Log("msg", "wrong number of labels for upstream, empty labels will be used instead", "upstream", name, "expected", len(c.variableLabelNames.UpstreamServerVariableLabelNames), "got", len(varLabelValues))
|
||||
for range c.variableLabelNames.UpstreamServerVariableLabelNames {
|
||||
labelValues = append(labelValues, "")
|
||||
}
|
||||
@@ -754,8 +754,7 @@ func (c *NginxPlusCollector) Collect(ch chan<- prometheus.Metric) {
|
||||
upstreamServer := fmt.Sprintf("%v/%v", name, peer.Server)
|
||||
varPeerLabelValues := c.getUpstreamServerPeerLabelValues(upstreamServer)
|
||||
if c.variableLabelNames.UpstreamServerPeerVariableLabelNames != nil && len(varPeerLabelValues) != len(c.variableLabelNames.UpstreamServerPeerVariableLabelNames) {
|
||||
log.Printf("wrong number of labels for upstream peer %v. For labels %v, got values: %v. Empty labels will be used instead",
|
||||
peer.Server, c.variableLabelNames.UpstreamServerPeerVariableLabelNames, varPeerLabelValues)
|
||||
level.Warn(c.logger).Log("msg", "wrong number of labels for upstream peer, empty labels will be used instead", "upstream", name, "peer", peer.Server, "expected", len(c.variableLabelNames.UpstreamServerPeerVariableLabelNames), "got", len(varPeerLabelValues))
|
||||
for range c.variableLabelNames.UpstreamServerPeerVariableLabelNames {
|
||||
labelValues = append(labelValues, "")
|
||||
}
|
||||
@@ -901,8 +900,7 @@ func (c *NginxPlusCollector) Collect(ch chan<- prometheus.Metric) {
|
||||
varLabelValues := c.getStreamUpstreamServerLabelValues(name)
|
||||
|
||||
if c.variableLabelNames.StreamUpstreamServerVariableLabelNames != nil && len(varLabelValues) != len(c.variableLabelNames.StreamUpstreamServerVariableLabelNames) {
|
||||
log.Printf("wrong number of labels for stream server %v. For labels %v, got values: %v. Empty labels will be used instead",
|
||||
name, c.variableLabelNames.StreamUpstreamServerVariableLabelNames, varLabelValues)
|
||||
level.Warn(c.logger).Log("msg", "wrong number of labels for stream server, empty labels will be used instead", "server", name, "labels", c.variableLabelNames.StreamUpstreamServerVariableLabelNames, "values", varLabelValues)
|
||||
for range c.variableLabelNames.StreamUpstreamServerVariableLabelNames {
|
||||
labelValues = append(labelValues, "")
|
||||
}
|
||||
@@ -913,8 +911,7 @@ func (c *NginxPlusCollector) Collect(ch chan<- prometheus.Metric) {
|
||||
upstreamServer := fmt.Sprintf("%v/%v", name, peer.Server)
|
||||
varPeerLabelValues := c.getStreamUpstreamServerPeerLabelValues(upstreamServer)
|
||||
if c.variableLabelNames.StreamUpstreamServerPeerVariableLabelNames != nil && len(varPeerLabelValues) != len(c.variableLabelNames.StreamUpstreamServerPeerVariableLabelNames) {
|
||||
log.Printf("wrong number of labels for stream upstream peer %v. For labels %v, got values: %v. Empty labels will be used instead",
|
||||
peer.Server, c.variableLabelNames.StreamUpstreamServerPeerVariableLabelNames, varPeerLabelValues)
|
||||
level.Warn(c.logger).Log("msg", "wrong number of labels for stream upstream peer, empty labels will be used instead", "server", upstreamServer, "labels", c.variableLabelNames.StreamUpstreamServerPeerVariableLabelNames, "values", varPeerLabelValues)
|
||||
for range c.variableLabelNames.StreamUpstreamServerPeerVariableLabelNames {
|
||||
labelValues = append(labelValues, "")
|
||||
}
|
||||
|
347
exporter.go
347
exporter.go
@@ -4,16 +4,11 @@ import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
@@ -21,69 +16,17 @@ import (
|
||||
plusclient "github.com/nginxinc/nginx-plus-go-client/client"
|
||||
"github.com/nginxinc/nginx-prometheus-exporter/client"
|
||||
"github.com/nginxinc/nginx-prometheus-exporter/collector"
|
||||
|
||||
"github.com/alecthomas/kingpin/v2"
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/prometheus/common/promlog"
|
||||
"github.com/prometheus/common/promlog/flag"
|
||||
"github.com/prometheus/common/version"
|
||||
)
|
||||
|
||||
func getEnv(key, defaultValue string) string {
|
||||
value, ok := os.LookupEnv(key)
|
||||
if !ok {
|
||||
return defaultValue
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func getEnvUint(key string, defaultValue uint) uint {
|
||||
value, ok := os.LookupEnv(key)
|
||||
if !ok {
|
||||
return defaultValue
|
||||
}
|
||||
i, err := strconv.ParseUint(value, 10, 64)
|
||||
if err != nil {
|
||||
log.Fatalf("Environment variable value for %s must be an uint: %v", key, err)
|
||||
}
|
||||
return uint(i)
|
||||
}
|
||||
|
||||
func getEnvBool(key string, defaultValue bool) bool {
|
||||
value, ok := os.LookupEnv(key)
|
||||
if !ok {
|
||||
return defaultValue
|
||||
}
|
||||
b, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
log.Fatalf("Environment variable value for %s must be a boolean: %v", key, err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func getEnvPositiveDuration(key string, defaultValue time.Duration) positiveDuration {
|
||||
value, ok := os.LookupEnv(key)
|
||||
if !ok {
|
||||
return positiveDuration{defaultValue}
|
||||
}
|
||||
|
||||
posDur, err := parsePositiveDuration(value)
|
||||
if err != nil {
|
||||
log.Fatalf("Environment variable value for %s must be a positive duration: %v", key, err)
|
||||
}
|
||||
return posDur
|
||||
}
|
||||
|
||||
func getEnvConstLabels(key string, defaultValue map[string]string) constLabel {
|
||||
value, ok := os.LookupEnv(key)
|
||||
if !ok {
|
||||
return constLabel{defaultValue}
|
||||
}
|
||||
|
||||
cLabel, err := parseConstLabels(value)
|
||||
if err != nil {
|
||||
log.Fatalf("Environment variable value for %s must be a const label or a list of const labels: %v", key, err)
|
||||
}
|
||||
return cLabel
|
||||
}
|
||||
|
||||
// positiveDuration is a wrapper of time.Duration to ensure only positive values are accepted
|
||||
type positiveDuration struct{ time.Duration }
|
||||
|
||||
@@ -108,62 +51,13 @@ func parsePositiveDuration(s string) (positiveDuration, error) {
|
||||
return positiveDuration{dur}, nil
|
||||
}
|
||||
|
||||
func createPositiveDurationFlag(name string, value positiveDuration, usage string) *positiveDuration {
|
||||
flag.Var(&value, name, usage)
|
||||
return &value
|
||||
func createPositiveDurationFlag(s kingpin.Settings) (target *time.Duration) {
|
||||
target = new(time.Duration)
|
||||
s.SetValue(&positiveDuration{Duration: *target})
|
||||
return
|
||||
}
|
||||
|
||||
type constLabel struct{ labels map[string]string }
|
||||
|
||||
func (cl *constLabel) Set(s string) error {
|
||||
labelList, err := parseConstLabels(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cl.labels = labelList.labels
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cl *constLabel) String() string {
|
||||
return fmt.Sprint(cl.labels)
|
||||
}
|
||||
|
||||
func parseConstLabels(labels string) (constLabel, error) {
|
||||
if labels == "" {
|
||||
return constLabel{}, nil
|
||||
}
|
||||
|
||||
constLabels := make(map[string]string)
|
||||
labelList := strings.Split(labels, ",")
|
||||
|
||||
for _, l := range labelList {
|
||||
dat := strings.Split(l, "=")
|
||||
if len(dat) != 2 {
|
||||
return constLabel{}, fmt.Errorf("const label %s has wrong format. Example valid input 'labelName=labelValue'", l)
|
||||
}
|
||||
|
||||
labelName := model.LabelName(dat[0])
|
||||
if !labelName.IsValid() {
|
||||
return constLabel{}, fmt.Errorf("const label %s has wrong format. %s contains invalid characters", l, labelName)
|
||||
}
|
||||
|
||||
labelValue := model.LabelValue(dat[1])
|
||||
if !labelValue.IsValid() {
|
||||
return constLabel{}, fmt.Errorf("const label %s has wrong format. %s contains invalid characters", l, labelValue)
|
||||
}
|
||||
|
||||
constLabels[dat[0]] = dat[1]
|
||||
}
|
||||
return constLabel{labels: constLabels}, nil
|
||||
}
|
||||
|
||||
func createConstLabelsFlag(name string, value constLabel, usage string) *constLabel {
|
||||
flag.Var(&value, name, usage)
|
||||
return &value
|
||||
}
|
||||
|
||||
func createClientWithRetries(getClient func() (interface{}, error), retries uint, retryInterval time.Duration) (interface{}, error) {
|
||||
func createClientWithRetries(getClient func() (interface{}, error), retries uint, retryInterval time.Duration, logger log.Logger) (interface{}, error) {
|
||||
var err error
|
||||
var nginxClient interface{}
|
||||
|
||||
@@ -173,7 +67,7 @@ func createClientWithRetries(getClient func() (interface{}, error), retries uint
|
||||
return nginxClient, nil
|
||||
}
|
||||
if i < int(retries) {
|
||||
log.Printf("Could not create Nginx Client. Retrying in %v...", retryInterval)
|
||||
level.Error(logger).Log("msg", fmt.Sprintf("Could not create Nginx Client. Retrying in %v...", retryInterval))
|
||||
time.Sleep(retryInterval)
|
||||
}
|
||||
}
|
||||
@@ -213,135 +107,61 @@ func getListener(listenAddress string) (net.Listener, error) {
|
||||
if err != nil {
|
||||
return listener, err
|
||||
}
|
||||
log.Printf("Listening on %s", listenAddress)
|
||||
return listener, nil
|
||||
}
|
||||
|
||||
var (
|
||||
// Set during go build
|
||||
version string
|
||||
|
||||
// Defaults values
|
||||
defaultListenAddress = getEnv("LISTEN_ADDRESS", ":9113")
|
||||
defaultSecuredMetrics = getEnvBool("SECURED_METRICS", false)
|
||||
defaultSslServerCert = getEnv("SSL_SERVER_CERT", "")
|
||||
defaultSslServerKey = getEnv("SSL_SERVER_KEY", "")
|
||||
defaultMetricsPath = getEnv("TELEMETRY_PATH", "/metrics")
|
||||
defaultNginxPlus = getEnvBool("NGINX_PLUS", false)
|
||||
defaultScrapeURI = getEnv("SCRAPE_URI", "http://127.0.0.1:8080/stub_status")
|
||||
defaultSslVerify = getEnvBool("SSL_VERIFY", true)
|
||||
defaultSslCaCert = getEnv("SSL_CA_CERT", "")
|
||||
defaultSslClientCert = getEnv("SSL_CLIENT_CERT", "")
|
||||
defaultSslClientKey = getEnv("SSL_CLIENT_KEY", "")
|
||||
defaultTimeout = getEnvPositiveDuration("TIMEOUT", time.Second*5)
|
||||
defaultNginxRetries = getEnvUint("NGINX_RETRIES", 0)
|
||||
defaultNginxRetryInterval = getEnvPositiveDuration("NGINX_RETRY_INTERVAL", time.Second*5)
|
||||
defaultConstLabels = getEnvConstLabels("CONST_LABELS", map[string]string{})
|
||||
constLabels = map[string]string{}
|
||||
|
||||
// Command-line flags
|
||||
listenAddr = flag.String("web.listen-address",
|
||||
defaultListenAddress,
|
||||
"An address or unix domain socket path to listen on for web interface and telemetry. The default value can be overwritten by LISTEN_ADDRESS environment variable.")
|
||||
securedMetrics = flag.Bool("web.secured-metrics",
|
||||
defaultSecuredMetrics,
|
||||
"Expose metrics using https. The default value can be overwritten by SECURED_METRICS variable.")
|
||||
sslServerCert = flag.String("web.ssl-server-cert",
|
||||
defaultSslServerCert,
|
||||
"Path to the PEM encoded certificate for the nginx-exporter metrics server(when web.secured-metrics=true). The default value can be overwritten by SSL_SERVER_CERT variable.")
|
||||
sslServerKey = flag.String("web.ssl-server-key",
|
||||
defaultSslServerKey,
|
||||
"Path to the PEM encoded key for the nginx-exporter metrics server (when web.secured-metrics=true). The default value can be overwritten by SSL_SERVER_KEY variable.")
|
||||
metricsPath = flag.String("web.telemetry-path",
|
||||
defaultMetricsPath,
|
||||
"A path under which to expose metrics. The default value can be overwritten by TELEMETRY_PATH environment variable.")
|
||||
nginxPlus = flag.Bool("nginx.plus",
|
||||
defaultNginxPlus,
|
||||
"Start the exporter for NGINX Plus. By default, the exporter is started for NGINX. The default value can be overwritten by NGINX_PLUS environment variable.")
|
||||
scrapeURI = flag.String("nginx.scrape-uri",
|
||||
defaultScrapeURI,
|
||||
`A URI or unix domain socket path for scraping NGINX or NGINX Plus metrics.
|
||||
For NGINX, the stub_status page must be available through the URI. For NGINX Plus -- the API. The default value can be overwritten by SCRAPE_URI environment variable.`)
|
||||
sslVerify = flag.Bool("nginx.ssl-verify",
|
||||
defaultSslVerify,
|
||||
"Perform SSL certificate verification. The default value can be overwritten by SSL_VERIFY environment variable.")
|
||||
sslCaCert = flag.String("nginx.ssl-ca-cert",
|
||||
defaultSslCaCert,
|
||||
"Path to the PEM encoded CA certificate file used to validate the servers SSL certificate. The default value can be overwritten by SSL_CA_CERT environment variable.")
|
||||
sslClientCert = flag.String("nginx.ssl-client-cert",
|
||||
defaultSslClientCert,
|
||||
"Path to the PEM encoded client certificate file to use when connecting to the server. The default value can be overwritten by SSL_CLIENT_CERT environment variable.")
|
||||
sslClientKey = flag.String("nginx.ssl-client-key",
|
||||
defaultSslClientKey,
|
||||
"Path to the PEM encoded client certificate key file to use when connecting to the server. The default value can be overwritten by SSL_CLIENT_KEY environment variable.")
|
||||
nginxRetries = flag.Uint("nginx.retries",
|
||||
defaultNginxRetries,
|
||||
"A number of retries the exporter will make on start to connect to the NGINX stub_status page/NGINX Plus API before exiting with an error. The default value can be overwritten by NGINX_RETRIES environment variable.")
|
||||
displayVersion = flag.Bool("version",
|
||||
false,
|
||||
"Display the NGINX exporter version.")
|
||||
listenAddr = kingpin.Flag("web.listen-address", "An address or unix domain socket path to listen on for web interface and telemetry.").Default(":9113").Envar("LISTEN_ADDRESS").String()
|
||||
securedMetrics = kingpin.Flag("web.secured-metrics", "Expose metrics using https.").Default("false").Envar("SECURED_METRICS").Bool()
|
||||
sslServerCert = kingpin.Flag("web.ssl-server-cert", "Path to the PEM encoded certificate for the nginx-exporter metrics server(when web.secured-metrics=true).").Default("").Envar("SSL_SERVER_CERT").String()
|
||||
sslServerKey = kingpin.Flag("web.ssl-server-key", "Path to the PEM encoded key for the nginx-exporter metrics server(when web.secured-metrics=true).").Default("").Envar("SSL_SERVER_KEY").String()
|
||||
metricsPath = kingpin.Flag("web.telemetry-path", "Path under which to expose metrics.").Default("/metrics").Envar("TELEMETRY_PATH").String()
|
||||
nginxPlus = kingpin.Flag("nginx.plus", "Start the exporter for NGINX Plus. By default, the exporter is started for NGINX.").Default("false").Envar("NGINX_PLUS").Bool()
|
||||
scrapeURI = kingpin.Flag("nginx.scrape-uri", "A URI or unix domain socket path for scraping NGINX or NGINX Plus metrics. For NGINX, the stub_status page must be available through the URI. For NGINX Plus -- the API.").Default("http://127.0.0.1:8080/stub_status").String()
|
||||
sslVerify = kingpin.Flag("nginx.ssl-verify", "Perform SSL certificate verification.").Default("false").Envar("SSL_VERIFY").Bool()
|
||||
sslCaCert = kingpin.Flag("nginx.ssl-ca-cert", "Path to the PEM encoded CA certificate file used to validate the servers SSL certificate.").Default("").Envar("SSL_CA_CERT").String()
|
||||
sslClientCert = kingpin.Flag("nginx.ssl-client-cert", "Path to the PEM encoded client certificate file to use when connecting to the server.").Default("").Envar("SSL_CLIENT_CERT").String()
|
||||
sslClientKey = kingpin.Flag("nginx.ssl-client-key", "Path to the PEM encoded client certificate key file to use when connecting to the server.").Default("").Envar("SSL_CLIENT_KEY").String()
|
||||
nginxRetries = kingpin.Flag("nginx.retries", "A number of retries the exporter will make on start to connect to the NGINX stub_status page/NGINX Plus API before exiting with an error.").Default("0").Envar("NGINX_RETRIES").Uint()
|
||||
|
||||
// Custom command-line flags
|
||||
timeout = createPositiveDurationFlag("nginx.timeout",
|
||||
defaultTimeout,
|
||||
"A timeout for scraping metrics from NGINX or NGINX Plus. The default value can be overwritten by TIMEOUT environment variable.")
|
||||
|
||||
nginxRetryInterval = createPositiveDurationFlag("nginx.retry-interval",
|
||||
defaultNginxRetryInterval,
|
||||
"An interval between retries to connect to the NGINX stub_status page/NGINX Plus API on start. The default value can be overwritten by NGINX_RETRY_INTERVAL environment variable.")
|
||||
|
||||
constLabels = createConstLabelsFlag("prometheus.const-labels",
|
||||
defaultConstLabels,
|
||||
"A comma separated list of constant labels that will be used in every metric. Format is label1=value1,label2=value2... The default value can be overwritten by CONST_LABELS environment variable.")
|
||||
timeout = createPositiveDurationFlag(kingpin.Flag("nginx.timeout", "A timeout for scraping metrics from NGINX or NGINX Plus.").Default("5s").Envar("TIMEOUT"))
|
||||
nginxRetryInterval = createPositiveDurationFlag(kingpin.Flag("nginx.retry-interval", "An interval between retries to connect to the NGINX stub_status page/NGINX Plus API on start.").Default("5s").Envar("NGINX_RETRY_INTERVAL"))
|
||||
)
|
||||
|
||||
const exporterName = "nginx_exporter"
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
kingpin.Flag("prometheus.const-label", "Label that will be used in every metric. Format is label=value. It can be repeated multiple times.").Envar("CONST_LABELS").StringMapVar(&constLabels)
|
||||
|
||||
commitHash, commitTime, dirtyBuild := getBuildInfo()
|
||||
arch := fmt.Sprintf("%v/%v", runtime.GOOS, runtime.GOARCH)
|
||||
promlogConfig := &promlog.Config{}
|
||||
flag.AddFlags(kingpin.CommandLine, promlogConfig)
|
||||
kingpin.Version(version.Print(exporterName))
|
||||
kingpin.HelpFlag.Short('h')
|
||||
kingpin.Parse()
|
||||
logger := promlog.New(promlogConfig)
|
||||
|
||||
fmt.Printf("NGINX Prometheus Exporter version=%v commit=%v date=%v, dirty=%v, arch=%v, go=%v\n", version, commitHash, commitTime, dirtyBuild, arch, runtime.Version())
|
||||
level.Info(logger).Log("msg", "Starting nginx-prometheus-exporter", "version", version.Info())
|
||||
level.Info(logger).Log("msg", "Build context", "build_context", version.BuildContext())
|
||||
|
||||
if *displayVersion {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
log.Printf("Starting...")
|
||||
|
||||
registry := prometheus.NewRegistry()
|
||||
|
||||
buildInfoMetric := prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "nginxexporter_build_info",
|
||||
Help: "Exporter build information",
|
||||
ConstLabels: collector.MergeLabels(
|
||||
constLabels.labels,
|
||||
prometheus.Labels{
|
||||
"version": version,
|
||||
"commit": commitHash,
|
||||
"date": commitTime,
|
||||
"dirty": strconv.FormatBool(dirtyBuild),
|
||||
"arch": arch,
|
||||
"go": runtime.Version(),
|
||||
},
|
||||
),
|
||||
},
|
||||
)
|
||||
buildInfoMetric.Set(1)
|
||||
|
||||
registry.MustRegister(buildInfoMetric)
|
||||
prometheus.MustRegister(version.NewCollector(exporterName))
|
||||
|
||||
// #nosec G402
|
||||
sslConfig := &tls.Config{InsecureSkipVerify: !*sslVerify}
|
||||
if *sslCaCert != "" {
|
||||
caCert, err := os.ReadFile(*sslCaCert)
|
||||
if err != nil {
|
||||
log.Fatalf("Loading CA cert failed: %v", err)
|
||||
level.Error(logger).Log("msg", "Loading CA cert failed", "err", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
sslCaCertPool := x509.NewCertPool()
|
||||
ok := sslCaCertPool.AppendCertsFromPEM(caCert)
|
||||
if !ok {
|
||||
log.Fatal("Parsing CA cert file failed.")
|
||||
level.Error(logger).Log("msg", "Parsing CA cert file failed.")
|
||||
os.Exit(1)
|
||||
}
|
||||
sslConfig.RootCAs = sslCaCertPool
|
||||
}
|
||||
@@ -349,7 +169,8 @@ func main() {
|
||||
if *sslClientCert != "" && *sslClientKey != "" {
|
||||
clientCert, err := tls.LoadX509KeyPair(*sslClientCert, *sslClientKey)
|
||||
if err != nil {
|
||||
log.Fatalf("Loading client certificate failed: %v", err)
|
||||
level.Error(logger).Log("msg", "Loading client certificate failed", "error", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
sslConfig.Certificates = []tls.Certificate{clientCert}
|
||||
}
|
||||
@@ -360,7 +181,8 @@ func main() {
|
||||
if strings.HasPrefix(*scrapeURI, "unix:") {
|
||||
socketPath, requestPath, err := parseUnixSocketAddress(*scrapeURI)
|
||||
if err != nil {
|
||||
log.Fatalf("Parsing unix domain socket scrape address %s failed: %v", *scrapeURI, err)
|
||||
level.Error(logger).Log("msg", "Parsing unix domain socket scrape address failed", "uri", *scrapeURI, "error", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
transport.DialContext = func(_ context.Context, _, _ string) (net.Conn, error) {
|
||||
@@ -370,14 +192,14 @@ func main() {
|
||||
scrapeURI = &newScrapeURI
|
||||
}
|
||||
|
||||
userAgent := fmt.Sprintf("NGINX-Prometheus-Exporter/v%v", version)
|
||||
userAgent := fmt.Sprintf("NGINX-Prometheus-Exporter/v%v", version.Version)
|
||||
userAgentRT := &userAgentRoundTripper{
|
||||
agent: userAgent,
|
||||
rt: transport,
|
||||
}
|
||||
|
||||
httpClient := &http.Client{
|
||||
Timeout: timeout.Duration,
|
||||
Timeout: *timeout,
|
||||
Transport: userAgentRT,
|
||||
}
|
||||
|
||||
@@ -388,10 +210,11 @@ func main() {
|
||||
signalChan := make(chan os.Signal, 1)
|
||||
signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM)
|
||||
go func() {
|
||||
log.Printf("Signal received: %v. Exiting...", <-signalChan)
|
||||
level.Info(logger).Log("msg", "Signal received, exiting...", "signal", <-signalChan)
|
||||
err := srv.Close()
|
||||
if err != nil {
|
||||
log.Fatalf("Error occurred while closing the server: %v", err)
|
||||
level.Error(logger).Log("msg", "Error occurred while closing the server", "error", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Exit(0)
|
||||
}()
|
||||
@@ -399,22 +222,25 @@ func main() {
|
||||
if *nginxPlus {
|
||||
plusClient, err := createClientWithRetries(func() (interface{}, error) {
|
||||
return plusclient.NewNginxClient(httpClient, *scrapeURI)
|
||||
}, *nginxRetries, nginxRetryInterval.Duration)
|
||||
}, *nginxRetries, *nginxRetryInterval, logger)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not create Nginx Plus Client: %v", err)
|
||||
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)
|
||||
registry.MustRegister(collector.NewNginxPlusCollector(plusClient.(*plusclient.NginxClient), "nginxplus", variableLabelNames, constLabels.labels))
|
||||
prometheus.MustRegister(collector.NewNginxPlusCollector(plusClient.(*plusclient.NginxClient), "nginxplus", variableLabelNames, constLabels, logger))
|
||||
} else {
|
||||
ossClient, err := createClientWithRetries(func() (interface{}, error) {
|
||||
return client.NewNginxClient(httpClient, *scrapeURI)
|
||||
}, *nginxRetries, nginxRetryInterval.Duration)
|
||||
}, *nginxRetries, *nginxRetryInterval, logger)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not create Nginx Client: %v", err)
|
||||
level.Error(logger).Log("msg", "Could not create Nginx Client", "error", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
registry.MustRegister(collector.NewNginxCollector(ossClient.(*client.NginxClient), "nginx", constLabels.labels))
|
||||
prometheus.MustRegister(collector.NewNginxCollector(ossClient.(*client.NginxClient), "nginx", constLabels, logger))
|
||||
}
|
||||
http.Handle(*metricsPath, promhttp.HandlerFor(registry, promhttp.HandlerOpts{}))
|
||||
|
||||
http.Handle(*metricsPath, promhttp.Handler())
|
||||
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
_, err := fmt.Fprintf(w, `<!DOCTYPE html>
|
||||
@@ -423,30 +249,41 @@ func main() {
|
||||
<p><a href=%q>Metrics</a></p>`,
|
||||
*metricsPath)
|
||||
if err != nil {
|
||||
log.Printf("Error while sending a response for the '/' path: %v", err)
|
||||
level.Error(logger).Log("msg", "Error while sending a response for the '/' path", "error", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
})
|
||||
|
||||
listener, err := getListener(*listenAddr)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not create listener: %v", err)
|
||||
level.Error(logger).Log("msg", "Could not create listener", "error", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
level.Info(logger).Log("msg", "Listening on address", "address", *listenAddr)
|
||||
|
||||
if *securedMetrics {
|
||||
_, err = os.Stat(*sslServerCert)
|
||||
if err != nil {
|
||||
log.Fatalf("Cert file is not set, not readable or non-existent. Make sure you set -web.ssl-server-cert when starting your exporter with -web.secured-metrics=true: %v", err)
|
||||
level.Error(logger).Log("msg", "Cert file is not set, not readable or non-existent. Make sure you set -web.ssl-server-cert when starting your exporter with -web.secured-metrics=true", "error", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
_, err = os.Stat(*sslServerKey)
|
||||
if err != nil {
|
||||
log.Fatalf("Key file is not set, not readable or non-existent. Make sure you set -web.ssl-server-key when starting your exporter with -web.secured-metrics=true: %v", err)
|
||||
level.Error(logger).Log("msg", "Key file is not set, not readable or non-existent. Make sure you set -web.ssl-server-key when starting your exporter with -web.secured-metrics=true", "error", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
level.Info(logger).Log("msg", "NGINX Prometheus Exporter has successfully started using https")
|
||||
if err := srv.ServeTLS(listener, *sslServerCert, *sslServerKey); err != nil {
|
||||
level.Error(logger).Log("msg", "Error while serving", "error", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
log.Printf("NGINX Prometheus Exporter has successfully started using https")
|
||||
log.Fatal(srv.ServeTLS(listener, *sslServerCert, *sslServerKey))
|
||||
}
|
||||
|
||||
log.Printf("NGINX Prometheus Exporter has successfully started")
|
||||
log.Fatal(srv.Serve(listener))
|
||||
level.Info(logger).Log("msg", "NGINX Prometheus Exporter has successfully started")
|
||||
if err := srv.Serve(listener); err != nil {
|
||||
level.Error(logger).Log("msg", "Error while serving", "error", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
type userAgentRoundTripper struct {
|
||||
@@ -473,23 +310,3 @@ func cloneRequest(req *http.Request) *http.Request {
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func getBuildInfo() (string, string, bool) {
|
||||
var commitHash, commitTime string
|
||||
var dirtyBuild bool
|
||||
info, ok := debug.ReadBuildInfo()
|
||||
if !ok {
|
||||
return "", "", false
|
||||
}
|
||||
for _, kv := range info.Settings {
|
||||
switch kv.Key {
|
||||
case "vcs.revision":
|
||||
commitHash = kv.Value
|
||||
case "vcs.time":
|
||||
commitTime = kv.Value
|
||||
case "vcs.modified":
|
||||
dirtyBuild = kv.Value == "true"
|
||||
}
|
||||
}
|
||||
return commitHash, commitTime, dirtyBuild
|
||||
}
|
||||
|
@@ -5,6 +5,8 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
)
|
||||
|
||||
func TestCreateClientWithRetries(t *testing.T) {
|
||||
@@ -65,7 +67,7 @@ func TestCreateClientWithRetries(t *testing.T) {
|
||||
return tt.args.client, tt.args.err
|
||||
}
|
||||
|
||||
got, err := createClientWithRetries(getClient, tt.args.retries, tt.args.retryInterval)
|
||||
got, err := createClientWithRetries(getClient, tt.args.retries, tt.args.retryInterval, log.NewNopLogger())
|
||||
|
||||
actualRetries := invocations - 1
|
||||
|
||||
@@ -181,63 +183,3 @@ func TestParseUnixSocketAddress(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseConstLabels(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
labels string
|
||||
want constLabel
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Const labels with no labels",
|
||||
labels: "",
|
||||
want: constLabel{},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Const labels with one label with valid format",
|
||||
labels: "label=valid",
|
||||
want: constLabel{labels: map[string]string{"label": "valid"}},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Const labels with one label with invalid format",
|
||||
labels: "label: invalid",
|
||||
want: constLabel{},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Const labels with invalid format for multiple labels",
|
||||
labels: "label=valid,,label2=wrongformat",
|
||||
want: constLabel{},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Const labels with multiple labels, one label with invalid format",
|
||||
labels: "label=valid,label2:wrongformat",
|
||||
want: constLabel{},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Const labels with label name containing invalid char",
|
||||
labels: "l bel=invalid",
|
||||
want: constLabel{},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := parseConstLabels(tt.labels)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("parseConstLabels() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("parseConstLabels() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
18
go.mod
18
go.mod
@@ -3,18 +3,36 @@ module github.com/nginxinc/nginx-prometheus-exporter
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/alecthomas/kingpin/v2 v2.3.2
|
||||
github.com/go-kit/log v0.2.1
|
||||
github.com/nginxinc/nginx-plus-go-client v0.10.0
|
||||
github.com/prometheus/client_golang v1.15.1
|
||||
github.com/prometheus/common v0.44.0
|
||||
github.com/prometheus/exporter-toolkit v0.10.0
|
||||
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/go-logfmt/logfmt v0.5.1 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/jpillora/backoff v1.0.0 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
|
||||
github.com/prometheus/client_model v0.4.0 // indirect
|
||||
github.com/prometheus/procfs v0.9.0 // indirect
|
||||
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
|
||||
golang.org/x/crypto v0.8.0 // indirect
|
||||
golang.org/x/net v0.10.0 // indirect
|
||||
golang.org/x/oauth2 v0.8.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/sys v0.8.0 // indirect
|
||||
golang.org/x/text v0.9.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
55
go.sum
55
go.sum
@@ -1,31 +1,86 @@
|
||||
github.com/alecthomas/kingpin/v2 v2.3.2 h1:H0aULhgmSzN8xQ3nX1uxtdlTHYoPLu5AhHxWrKI6ocU=
|
||||
github.com/alecthomas/kingpin/v2 v2.3.2/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE=
|
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
|
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
|
||||
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nginxinc/nginx-plus-go-client v0.10.0 h1:3zsMMkPvRDo8D7ZSprXtbAEW/SDmezZWzxdyS+6oAlc=
|
||||
github.com/nginxinc/nginx-plus-go-client v0.10.0/go.mod h1:0v3RsQCvRn/IyrMtW+DK6CNkz+PxEsXDJPjQ3yUMBF0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI=
|
||||
github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
|
||||
github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
|
||||
github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
|
||||
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
|
||||
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
|
||||
github.com/prometheus/exporter-toolkit v0.10.0 h1:yOAzZTi4M22ZzVxD+fhy1URTuNRj/36uQJJ5S8IPza8=
|
||||
github.com/prometheus/exporter-toolkit v0.10.0/go.mod h1:+sVFzuvV5JDyw+Ih6p3zFxZNVnKQa3x5qPmDSiPu4ZY=
|
||||
github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
|
||||
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
|
||||
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
|
||||
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8=
|
||||
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
Reference in New Issue
Block a user