这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .promu.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
repository:
path: github.com/hnlq715/nginx-vts-exporter
build:
flags: -a -tags netgo
ldflags: |
-X {{repoPath}}/vendor/github.com/prometheus/common/version.Version={{.Version}}
-X {{repoPath}}/vendor/github.com/prometheus/common/version.Revision={{.Revision}}
-X {{repoPath}}/vendor/github.com/prometheus/common/version.Branch={{.Branch}}
-X {{repoPath}}/vendor/github.com/prometheus/common/version.BuildUser={{user}}@{{host}}
-X {{repoPath}}/vendor/github.com/prometheus/common/version.BuildDate={{date "20060102-15:04:05"}}
tarball:
files:
- LICENSE

crossbuild:
platforms:
- linux/amd64
- linux/386
- darwin/amd64
- darwin/386
- windows/amd64
- windows/386
1 change: 1 addition & 0 deletions VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0.1
206 changes: 94 additions & 112 deletions nginx_vts_exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import (
"net/http"
"os"
"strconv"
"sync"
"time"

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/prometheus/common/version"
)

type NginxVts struct {
Expand Down Expand Up @@ -142,61 +142,48 @@ func FloatToString(input_num float64) string {
}

type Exporter struct {
URI string
mutex sync.RWMutex
URI string

serverMetrics, upstreamMetrics, cacheMetrics map[string]*prometheus.GaugeVec
serverMetrics, upstreamMetrics, cacheMetrics map[string]*prometheus.Desc
}

func newServerMetric(metricName string, docString string, labels []string) *prometheus.GaugeVec {
return prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: *metricsNamespace,
Name: "server_" + metricName,
Help: docString,
},
labels,
func newServerMetric(metricName string, docString string, labels []string) *prometheus.Desc {
return prometheus.NewDesc(
prometheus.BuildFQName(*metricsNamespace, "server", metricName),
docString, labels, nil,
)
}

func newUpstreamMetric(metricName string, docString string, labels []string) *prometheus.GaugeVec {
return prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: *metricsNamespace,
Name: "upstream_" + metricName,
Help: docString,
},
labels,
func newUpstreamMetric(metricName string, docString string, labels []string) *prometheus.Desc {
return prometheus.NewDesc(
prometheus.BuildFQName(*metricsNamespace, "upstream", metricName),
docString, labels, nil,
)
}

func newCacheMetric(metricName string, docString string, labels []string) *prometheus.GaugeVec {
return prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: *metricsNamespace,
Name: "cache_" + metricName,
Help: docString,
},
labels,
func newCacheMetric(metricName string, docString string, labels []string) *prometheus.Desc {
return prometheus.NewDesc(
prometheus.BuildFQName(*metricsNamespace, "cache", metricName),
docString, labels, nil,
)
}

func NewExporter(uri string) *Exporter {

return &Exporter{
URI: uri,
serverMetrics: map[string]*prometheus.GaugeVec{
serverMetrics: map[string]*prometheus.Desc{
"connections": newServerMetric("connections", "nginx connections", []string{"status"}),
"requests": newServerMetric("requests", "requests counter", []string{"host", "code"}),
"bytes": newServerMetric("bytes", "request/response bytes", []string{"host", "direction"}),
"cache": newServerMetric("cache", "cache counter", []string{"host", "status"}),
},
upstreamMetrics: map[string]*prometheus.GaugeVec{
upstreamMetrics: map[string]*prometheus.Desc{
"requests": newUpstreamMetric("requests", "requests counter", []string{"upstream", "code"}),
"bytes": newUpstreamMetric("bytes", "request/response bytes", []string{"upstream", "direction"}),
"response": newUpstreamMetric("response", "request response time", []string{"upstream", "backend"}),
},
cacheMetrics: map[string]*prometheus.GaugeVec{
cacheMetrics: map[string]*prometheus.Desc{
"requests": newCacheMetric("requests", "cache requests counter", []string{"zone", "status"}),
"bytes": newCacheMetric("bytes", "cache request/response bytes", []string{"zone", "direction"}),
},
Expand All @@ -205,51 +192,18 @@ func NewExporter(uri string) *Exporter {

func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
for _, m := range e.serverMetrics {
m.Describe(ch)
ch <- m
}
for _, m := range e.upstreamMetrics {
m.Describe(ch)
ch <- m
}
for _, m := range e.cacheMetrics {
m.Describe(ch)
ch <- m
}
}

func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
e.mutex.Lock()
defer e.mutex.Unlock()

e.resetMetrics()
e.scrape()

e.collectMetrics(ch)
}

func (e *Exporter) resetMetrics() {
for _, m := range e.serverMetrics {
m.Reset()
}
for _, m := range e.upstreamMetrics {
m.Reset()
}
for _, m := range e.cacheMetrics {
m.Reset()
}
}

func (e *Exporter) collectMetrics(metrics chan<- prometheus.Metric) {
for _, m := range e.serverMetrics {
m.Collect(metrics)
}
for _, m := range e.upstreamMetrics {
m.Collect(metrics)
}
for _, m := range e.cacheMetrics {
m.Collect(metrics)
}
}

func (e *Exporter) scrape() {
body, err := fetchHTTP(e.URI, 2*time.Second)()
if err != nil {
log.Println("fetchHTTP failed", err)
Expand All @@ -270,63 +224,78 @@ func (e *Exporter) scrape() {
return
}

e.serverMetrics["connections"].WithLabelValues("active").Set(float64(nginxVtx.Connections.Active))
e.serverMetrics["connections"].WithLabelValues("reading").Set(float64(nginxVtx.Connections.Reading))
e.serverMetrics["connections"].WithLabelValues("waiting").Set(float64(nginxVtx.Connections.Waiting))
e.serverMetrics["connections"].WithLabelValues("writing").Set(float64(nginxVtx.Connections.Writing))
e.serverMetrics["connections"].WithLabelValues("accepted").Set(float64(nginxVtx.Connections.Accepted))
e.serverMetrics["connections"].WithLabelValues("handled").Set(float64(nginxVtx.Connections.Handled))
e.serverMetrics["connections"].WithLabelValues("requests").Set(float64(nginxVtx.Connections.Requests))
// connections
ch <- prometheus.MustNewConstMetric(e.serverMetrics["connections"], prometheus.GaugeValue, float64(nginxVtx.Connections.Active), "active")
ch <- prometheus.MustNewConstMetric(e.serverMetrics["connections"], prometheus.GaugeValue, float64(nginxVtx.Connections.Reading), "reading")
ch <- prometheus.MustNewConstMetric(e.serverMetrics["connections"], prometheus.GaugeValue, float64(nginxVtx.Connections.Waiting), "waiting")
ch <- prometheus.MustNewConstMetric(e.serverMetrics["connections"], prometheus.GaugeValue, float64(nginxVtx.Connections.Writing), "writing")
ch <- prometheus.MustNewConstMetric(e.serverMetrics["connections"], prometheus.GaugeValue, float64(nginxVtx.Connections.Accepted), "accepted")
ch <- prometheus.MustNewConstMetric(e.serverMetrics["connections"], prometheus.GaugeValue, float64(nginxVtx.Connections.Handled), "handled")
ch <- prometheus.MustNewConstMetric(e.serverMetrics["connections"], prometheus.GaugeValue, float64(nginxVtx.Connections.Requests), "requests")

// ServerZones
for host, s := range nginxVtx.ServerZones {
e.serverMetrics["requests"].WithLabelValues(host, "total").Set(float64(s.RequestCounter))
e.serverMetrics["requests"].WithLabelValues(host, "1xx").Set(float64(s.Responses.OneXx))
e.serverMetrics["requests"].WithLabelValues(host, "2xx").Set(float64(s.Responses.TwoXx))
e.serverMetrics["requests"].WithLabelValues(host, "3xx").Set(float64(s.Responses.ThreeXx))
e.serverMetrics["requests"].WithLabelValues(host, "4xx").Set(float64(s.Responses.FourXx))
e.serverMetrics["requests"].WithLabelValues(host, "5xx").Set(float64(s.Responses.FiveXx))

e.serverMetrics["cache"].WithLabelValues(host, "bypass").Set(float64(s.Responses.Bypass))
e.serverMetrics["cache"].WithLabelValues(host, "expired").Set(float64(s.Responses.Expired))
e.serverMetrics["cache"].WithLabelValues(host, "hit").Set(float64(s.Responses.Hit))
e.serverMetrics["cache"].WithLabelValues(host, "miss").Set(float64(s.Responses.Miss))
e.serverMetrics["cache"].WithLabelValues(host, "revalidated").Set(float64(s.Responses.Revalidated))
e.serverMetrics["cache"].WithLabelValues(host, "scarce").Set(float64(s.Responses.Scarce))
e.serverMetrics["cache"].WithLabelValues(host, "stale").Set(float64(s.Responses.Stale))
e.serverMetrics["cache"].WithLabelValues(host, "updating").Set(float64(s.Responses.Updating))

e.serverMetrics["bytes"].WithLabelValues(host, "in").Set(float64(s.InBytes))
e.serverMetrics["bytes"].WithLabelValues(host, "out").Set(float64(s.OutBytes))
ch <- prometheus.MustNewConstMetric(e.serverMetrics["requests"], prometheus.CounterValue, float64(s.RequestCounter), host, "total")
ch <- prometheus.MustNewConstMetric(e.serverMetrics["requests"], prometheus.CounterValue, float64(s.Responses.OneXx), host, "1xx")
ch <- prometheus.MustNewConstMetric(e.serverMetrics["requests"], prometheus.CounterValue, float64(s.Responses.TwoXx), host, "2xx")
ch <- prometheus.MustNewConstMetric(e.serverMetrics["requests"], prometheus.CounterValue, float64(s.Responses.ThreeXx), host, "3xx")
ch <- prometheus.MustNewConstMetric(e.serverMetrics["requests"], prometheus.CounterValue, float64(s.Responses.FourXx), host, "4xx")
ch <- prometheus.MustNewConstMetric(e.serverMetrics["requests"], prometheus.CounterValue, float64(s.Responses.FiveXx), host, "5xx")

ch <- prometheus.MustNewConstMetric(e.serverMetrics["cache"], prometheus.CounterValue, float64(s.Responses.Bypass), host, "bypass")
ch <- prometheus.MustNewConstMetric(e.serverMetrics["cache"], prometheus.CounterValue, float64(s.Responses.Expired), host, "expired")
ch <- prometheus.MustNewConstMetric(e.serverMetrics["cache"], prometheus.CounterValue, float64(s.Responses.Hit), host, "hit")
ch <- prometheus.MustNewConstMetric(e.serverMetrics["cache"], prometheus.CounterValue, float64(s.Responses.Miss), host, "miss")
ch <- prometheus.MustNewConstMetric(e.serverMetrics["cache"], prometheus.CounterValue, float64(s.Responses.Revalidated), host, "revalidated")
ch <- prometheus.MustNewConstMetric(e.serverMetrics["cache"], prometheus.CounterValue, float64(s.Responses.Scarce), host, "scarce")
ch <- prometheus.MustNewConstMetric(e.serverMetrics["cache"], prometheus.CounterValue, float64(s.Responses.Stale), host, "stale")
ch <- prometheus.MustNewConstMetric(e.serverMetrics["cache"], prometheus.CounterValue, float64(s.Responses.Updating), host, "updating")

ch <- prometheus.MustNewConstMetric(e.serverMetrics["bytes"], prometheus.CounterValue, float64(s.InBytes), host, "in")
ch <- prometheus.MustNewConstMetric(e.serverMetrics["bytes"], prometheus.CounterValue, float64(s.OutBytes), host, "out")
}

// UpstreamZones
for name, upstreamList := range nginxVtx.UpstreamZones {
var total, one, two, three, four, five, inbytes, outbytes float64
for _, s := range upstreamList {
e.upstreamMetrics["requests"].WithLabelValues(name, "total").Add(float64(s.RequestCounter))
e.upstreamMetrics["requests"].WithLabelValues(name, "1xx").Add(float64(s.Responses.OneXx))
e.upstreamMetrics["requests"].WithLabelValues(name, "2xx").Add(float64(s.Responses.TwoXx))
e.upstreamMetrics["requests"].WithLabelValues(name, "3xx").Add(float64(s.Responses.ThreeXx))
e.upstreamMetrics["requests"].WithLabelValues(name, "4xx").Add(float64(s.Responses.FourXx))
e.upstreamMetrics["requests"].WithLabelValues(name, "5xx").Add(float64(s.Responses.FiveXx))
total += float64(s.RequestCounter)
one += float64(s.Responses.OneXx)
two += float64(s.Responses.TwoXx)
three += float64(s.Responses.ThreeXx)
four += float64(s.Responses.FourXx)
five += float64(s.Responses.FiveXx)

e.upstreamMetrics["bytes"].WithLabelValues(name, "in").Add(float64(s.InBytes))
e.upstreamMetrics["bytes"].WithLabelValues(name, "out").Add(float64(s.OutBytes))
inbytes += float64(s.InBytes)
outbytes += float64(s.OutBytes)

e.upstreamMetrics["response"].WithLabelValues(name, s.Server).Add(float64(s.ResponseMsec))
ch <- prometheus.MustNewConstMetric(e.upstreamMetrics["response"], prometheus.GaugeValue, float64(s.ResponseMsec), name, s.Server)
}

ch <- prometheus.MustNewConstMetric(e.upstreamMetrics["requests"], prometheus.CounterValue, total, name, "total")
ch <- prometheus.MustNewConstMetric(e.upstreamMetrics["requests"], prometheus.CounterValue, one, name, "1xx")
ch <- prometheus.MustNewConstMetric(e.upstreamMetrics["requests"], prometheus.CounterValue, two, name, "2xx")
ch <- prometheus.MustNewConstMetric(e.upstreamMetrics["requests"], prometheus.CounterValue, three, name, "3xx")
ch <- prometheus.MustNewConstMetric(e.upstreamMetrics["requests"], prometheus.CounterValue, four, name, "4xx")
ch <- prometheus.MustNewConstMetric(e.upstreamMetrics["requests"], prometheus.CounterValue, five, name, "5xx")

ch <- prometheus.MustNewConstMetric(e.upstreamMetrics["bytes"], prometheus.CounterValue, inbytes, name, "in")
ch <- prometheus.MustNewConstMetric(e.upstreamMetrics["bytes"], prometheus.CounterValue, outbytes, name, "out")
}

// CacheZones
for zone, s := range nginxVtx.CacheZones {
e.cacheMetrics["requests"].WithLabelValues(zone, "bypass").Set(float64(s.Responses.Bypass))
e.cacheMetrics["requests"].WithLabelValues(zone, "expired").Set(float64(s.Responses.Expired))
e.cacheMetrics["requests"].WithLabelValues(zone, "hit").Set(float64(s.Responses.Hit))
e.cacheMetrics["requests"].WithLabelValues(zone, "miss").Set(float64(s.Responses.Miss))
e.cacheMetrics["requests"].WithLabelValues(zone, "revalidated").Set(float64(s.Responses.Revalidated))
e.cacheMetrics["requests"].WithLabelValues(zone, "scarce").Set(float64(s.Responses.Scarce))
e.cacheMetrics["requests"].WithLabelValues(zone, "stale").Set(float64(s.Responses.Stale))
e.cacheMetrics["requests"].WithLabelValues(zone, "updating").Set(float64(s.Responses.Updating))

e.cacheMetrics["bytes"].WithLabelValues(zone, "in").Set(float64(s.InBytes))
e.cacheMetrics["bytes"].WithLabelValues(zone, "out").Set(float64(s.OutBytes))
ch <- prometheus.MustNewConstMetric(e.cacheMetrics["requests"], prometheus.CounterValue, float64(s.Responses.Bypass), zone, "bypass")
ch <- prometheus.MustNewConstMetric(e.cacheMetrics["requests"], prometheus.CounterValue, float64(s.Responses.Expired), zone, "expired")
ch <- prometheus.MustNewConstMetric(e.cacheMetrics["requests"], prometheus.CounterValue, float64(s.Responses.Hit), zone, "hit")
ch <- prometheus.MustNewConstMetric(e.cacheMetrics["requests"], prometheus.CounterValue, float64(s.Responses.Miss), zone, "miss")
ch <- prometheus.MustNewConstMetric(e.cacheMetrics["requests"], prometheus.CounterValue, float64(s.Responses.Revalidated), zone, "revalidated")
ch <- prometheus.MustNewConstMetric(e.cacheMetrics["requests"], prometheus.CounterValue, float64(s.Responses.Scarce), zone, "scarce")
ch <- prometheus.MustNewConstMetric(e.cacheMetrics["requests"], prometheus.CounterValue, float64(s.Responses.Stale), zone, "stale")
ch <- prometheus.MustNewConstMetric(e.cacheMetrics["requests"], prometheus.CounterValue, float64(s.Responses.Updating), zone, "updating")

ch <- prometheus.MustNewConstMetric(e.cacheMetrics["bytes"], prometheus.CounterValue, float64(s.InBytes), zone, "in")
ch <- prometheus.MustNewConstMetric(e.cacheMetrics["bytes"], prometheus.CounterValue, float64(s.OutBytes), zone, "out")
}
}

Expand All @@ -347,16 +316,29 @@ func fetchHTTP(uri string, timeout time.Duration) func() (io.ReadCloser, error)
}

var (
showVersion = flag.Bool("version", false, "Print version information.")
listenAddress = flag.String("telemetry.address", ":9913", "Address on which to expose metrics.")
metricsEndpoint = flag.String("telemetry.endpoint", "/metrics", "Path under which to expose metrics.")
metricsNamespace = flag.String("metrics.namespace", "nginx", "Prometheus metrics namespace.")
nginxScrapeURI = flag.String("nginx.scrape_uri", "http://localhost/status", "URI to nginx stub status page")
insecure = flag.Bool("insecure", true, "Ignore server certificate if using https")
)

func init() {
prometheus.MustRegister(version.NewCollector("nginx_vts_exporter"))
}

func main() {
flag.Parse()

if *showVersion {
fmt.Fprintln(os.Stdout, version.Print("nginx_vts_exporter"))
os.Exit(0)
}

log.Printf("Starting nginx_vts_exporter %s", version.Info())
log.Printf("Build context %s", version.BuildContext())

exporter := NewExporter(*nginxScrapeURI)
prometheus.MustRegister(exporter)
prometheus.Unregister(prometheus.NewProcessCollector(os.Getpid(), ""))
Expand Down
Loading