Add Nginx Plus API input (#4837)

This commit is contained in:
Bugagazavr 2018-10-22 22:54:50 +03:00 committed by Daniel Nelson
parent 2f7450ec04
commit ff98ad710b
6 changed files with 1994 additions and 0 deletions

View File

@ -80,6 +80,7 @@ import (
_ "github.com/influxdata/telegraf/plugins/inputs/net_response" _ "github.com/influxdata/telegraf/plugins/inputs/net_response"
_ "github.com/influxdata/telegraf/plugins/inputs/nginx" _ "github.com/influxdata/telegraf/plugins/inputs/nginx"
_ "github.com/influxdata/telegraf/plugins/inputs/nginx_plus" _ "github.com/influxdata/telegraf/plugins/inputs/nginx_plus"
_ "github.com/influxdata/telegraf/plugins/inputs/nginx_plus_api"
_ "github.com/influxdata/telegraf/plugins/inputs/nsq" _ "github.com/influxdata/telegraf/plugins/inputs/nsq"
_ "github.com/influxdata/telegraf/plugins/inputs/nsq_consumer" _ "github.com/influxdata/telegraf/plugins/inputs/nsq_consumer"
_ "github.com/influxdata/telegraf/plugins/inputs/nstat" _ "github.com/influxdata/telegraf/plugins/inputs/nstat"

View File

@ -0,0 +1,216 @@
# Telegraf Plugin: nginx_plus_api
Nginx Plus is a commercial version of the open source web server Nginx. The use this plugin you will need a license. For more information about the differences between Nginx (F/OSS) and Nginx Plus, [click here](https://www.nginx.com/blog/whats-difference-nginx-foss-nginx-plus/).
### Configuration:
```
# Read Nginx Plus API advanced status information
[[inputs.nginx_plus_api]]
## An array of Nginx API URIs to gather stats.
urls = ["http://localhost/api"]
# Nginx API version, default: 3
# api_version = 3
```
### Migration from Nginx Plus (Status) input plugin
| Nginx Plus | Nginx Plus API |
|---------------------------------|--------------------------------------|
| nginx_plus_processes | nginx_plus_api_processes |
| nginx_plus_connections | nginx_plus_api_connections |
| nginx_plus_ssl | nginx_plus_api_ssl |
| nginx_plus_requests | nginx_plus_api_http_requests |
| nginx_plus_zone | nginx_plus_api_http_server_zones |
| nginx_plus_upstream | nginx_plus_api_http_upstreams |
| nginx_plus_upstream_peer | nginx_plus_api_http_upstream_peers |
| nginx_plus_cache | nginx_plus_api_http_caches |
| nginx_plus_stream_upstream | nginx_plus_api_stream_upstreams |
| nginx_plus_stream_upstream_peer | nginx_plus_api_stream_upstream_peers |
| nginx.stream.zone | nginx_plus_api_stream_server_zones |
### Measurements & Fields:
- nginx_plus_api_processes
- respawned
- nginx_plus_api_connections
- accepted
- dropped
- active
- idle
- nginx_plus_api_ssl
- handshakes
- handshakes_failed
- session_reuses
- nginx_plus_api_http_requests
- total
- current
- nginx_plus_api_http_server_zones
- processing
- requests
- responses_1xx
- responses_2xx
- responses_3xx
- responses_4xx
- responses_5xx
- responses_total
- received
- sent
- discarded
- nginx_plus_api_http_upstreams
- keepalive
- zombies
- nginx_plus_api_http_upstream_peers
- requests
- unavail
- healthchecks_checks
- header_time
- state
- response_time
- active
- healthchecks_last_passed
- weight
- responses_1xx
- responses_2xx
- responses_3xx
- responses_4xx
- responses_5xx
- received
- healthchecks_fails
- healthchecks_unhealthy
- backup
- responses_total
- sent
- fails
- downtime
- nginx_plus_api_http_caches
- size
- max_size
- cold
- hit_responses
- hit_bytes
- stale_responses
- stale_bytes
- updating_responses
- updating_bytes
- revalidated_responses
- revalidated_bytes
- miss_responses
- miss_bytes
- miss_responses_written
- miss_bytes_written
- expired_responses
- expired_bytes
- expired_responses_written
- expired_bytes_written
- bypass_responses
- bypass_bytes
- bypass_responses_written
- bypass_bytes_written
- nginx_plus_api_stream_upstreams
- zombies
- nginx_plus_api_stream_upstream_peers
- unavail
- healthchecks_checks
- healthchecks_fails
- healthchecks_unhealthy
- healthchecks_last_passed
- response_time
- state
- active
- weight
- received
- backup
- sent
- fails
- downtime
- nginx_plus_api_stream_server_zones
- processing
- connections
- received
- sent
### Tags:
- nginx_plus_api_processes, nginx_plus_api_connections, nginx_plus_api_ssl, nginx_plus_api_http_requests
- source
- port
- nginx_plus_api_http_upstreams, nginx_plus_api_stream_upstreams
- upstream
- source
- port
- nginx_plus_api_http_server_zones, nginx_plus_api_upstream_server_zones
- source
- port
- zone
- nginx_plus_api_upstream_peers, nginx_plus_api_stream_upstream_peers
- id
- upstream
- source
- port
- upstream_address
- nginx_plus_api_http_caches
- source
- port
### Example Output:
Using this configuration:
```
[[inputs.nginx_plus_api]]
## An array of Nginx Plus API URIs to gather stats.
urls = ["http://localhost/api"]
```
When run with:
```
./telegraf -config telegraf.conf -input-filter nginx_plus_api -test
```
It produces:
```
> nginx_plus_api_processes,host=localhost,port=80,source=localhost respawned=0i 1539163505000000000
> nginx_plus_api_connections,host=localhost,port=80,source=localhost accepted=120890747i,active=6i,dropped=0i,idle=67i 1539163505000000000
> nginx_plus_api_ssl,host=localhost,port=80,source=localhost handshakes=2983938i,handshakes_failed=54350i,session_reuses=2485267i 1539163506000000000
> nginx_plus_api_http_requests,host=localhost,port=80,source=localhost current=12i,total=175270198i 1539163506000000000
> nginx_plus_api_http_server_zones,host=localhost,port=80,source=localhost,zone=hg.nginx.org discarded=45i,processing=0i,received=35723884i,requests=134102i,responses_1xx=0i,responses_2xx=96890i,responses_3xx=6892i,responses_4xx=30270i,responses_5xx=5i,responses_total=134057i,sent=3681826618i 1539163506000000000
> nginx_plus_api_http_server_zones,host=localhost,port=80,source=localhost,zone=trac.nginx.org discarded=4034i,processing=9i,received=282399663i,requests=336129i,responses_1xx=0i,responses_2xx=101264i,responses_3xx=25454i,responses_4xx=68961i,responses_5xx=136407i,responses_total=332086i,sent=2346677493i 1539163506000000000
> nginx_plus_api_http_server_zones,host=localhost,port=80,source=localhost,zone=lxr.nginx.org discarded=4i,processing=1i,received=7223569i,requests=29661i,responses_1xx=0i,responses_2xx=28584i,responses_3xx=73i,responses_4xx=390i,responses_5xx=609i,responses_total=29656i,sent=5811238975i 1539163506000000000
> nginx_plus_api_http_upstreams,host=localhost,port=80,source=localhost,upstream=trac-backend keepalive=0i,zombies=0i 1539163506000000000
> nginx_plus_api_http_upstream_peers,host=localhost,id=0,port=80,source=localhost,upstream=trac-backend,upstream_address=10.0.0.1:8080 active=0i,backup=false,downtime=53870i,fails=5i,header_time=421i,healthchecks_checks=17275i,healthchecks_fails=0i,healthchecks_last_passed=true,healthchecks_unhealthy=0i,received=1885213684i,requests=88476i,response_time=423i,responses_1xx=0i,responses_2xx=50997i,responses_3xx=205i,responses_4xx=34344i,responses_5xx=2076i,responses_total=87622i,sent=189938404i,state="up",unavail=5i,weight=1i 1539163506000000000
> nginx_plus_api_http_upstream_peers,host=localhost,id=1,port=80,source=localhost,upstream=trac-backend,upstream_address=10.0.0.1:8081 active=0i,backup=true,downtime=173957231i,fails=0i,healthchecks_checks=17394i,healthchecks_fails=17394i,healthchecks_last_passed=false,healthchecks_unhealthy=1i,received=0i,requests=0i,responses_1xx=0i,responses_2xx=0i,responses_3xx=0i,responses_4xx=0i,responses_5xx=0i,responses_total=0i,sent=0i,state="unhealthy",unavail=0i,weight=1i 1539163506000000000
> nginx_plus_api_http_upstreams,host=localhost,port=80,source=localhost,upstream=hg-backend keepalive=0i,zombies=0i 1539163506000000000
> nginx_plus_api_http_upstream_peers,host=localhost,id=0,port=80,source=localhost,upstream=hg-backend,upstream_address=10.0.0.1:8088 active=0i,backup=false,downtime=0i,fails=0i,header_time=22i,healthchecks_checks=17319i,healthchecks_fails=0i,healthchecks_last_passed=true,healthchecks_unhealthy=0i,received=3724240605i,requests=89563i,response_time=44i,responses_1xx=0i,responses_2xx=81996i,responses_3xx=6886i,responses_4xx=639i,responses_5xx=5i,responses_total=89526i,sent=31597952i,state="up",unavail=0i,weight=5i 1539163506000000000
> nginx_plus_api_http_upstream_peers,host=localhost,id=1,port=80,source=localhost,upstream=hg-backend,upstream_address=10.0.0.1:8089 active=0i,backup=true,downtime=173957231i,fails=0i,healthchecks_checks=17394i,healthchecks_fails=17394i,healthchecks_last_passed=false,healthchecks_unhealthy=1i,received=0i,requests=0i,responses_1xx=0i,responses_2xx=0i,responses_3xx=0i,responses_4xx=0i,responses_5xx=0i,responses_total=0i,sent=0i,state="unhealthy",unavail=0i,weight=1i 1539163506000000000
> nginx_plus_api_http_upstreams,host=localhost,port=80,source=localhost,upstream=lxr-backend keepalive=0i,zombies=0i 1539163506000000000
> nginx_plus_api_http_upstream_peers,host=localhost,id=0,port=80,source=localhost,upstream=lxr-backend,upstream_address=unix:/tmp/cgi.sock active=0i,backup=false,downtime=0i,fails=609i,header_time=111i,healthchecks_checks=0i,healthchecks_fails=0i,healthchecks_unhealthy=0i,received=6220215064i,requests=28278i,response_time=172i,responses_1xx=0i,responses_2xx=27665i,responses_3xx=0i,responses_4xx=0i,responses_5xx=0i,responses_total=27665i,sent=21337016i,state="up",unavail=0i,weight=1i 1539163506000000000
> nginx_plus_api_http_upstream_peers,host=localhost,id=1,port=80,source=localhost,upstream=lxr-backend,upstream_address=unix:/tmp/cgib.sock active=0i,backup=true,downtime=0i,fails=0i,healthchecks_checks=0i,healthchecks_fails=0i,healthchecks_unhealthy=0i,max_conns=42i,received=0i,requests=0i,responses_1xx=0i,responses_2xx=0i,responses_3xx=0i,responses_4xx=0i,responses_5xx=0i,responses_total=0i,sent=0i,state="up",unavail=0i,weight=1i 1539163506000000000
> nginx_plus_api_http_upstreams,host=localhost,port=80,source=localhost,upstream=demo-backend keepalive=0i,zombies=0i 1539163506000000000
> nginx_plus_api_http_upstream_peers,host=localhost,id=0,port=80,source=localhost,upstream=demo-backend,upstream_address=10.0.0.2:15431 active=0i,backup=false,downtime=0i,fails=0i,healthchecks_checks=173640i,healthchecks_fails=0i,healthchecks_last_passed=true,healthchecks_unhealthy=0i,received=0i,requests=0i,responses_1xx=0i,responses_2xx=0i,responses_3xx=0i,responses_4xx=0i,responses_5xx=0i,responses_total=0i,sent=0i,state="up",unavail=0i,weight=1i 1539163506000000000
> nginx_plus_api_http_caches,cache=http_cache,host=localhost,port=80,source=localhost bypass_bytes=0i,bypass_bytes_written=0i,bypass_responses=0i,bypass_responses_written=0i,cold=false,expired_bytes=133671410i,expired_bytes_written=129210272i,expired_responses=15721i,expired_responses_written=15213i,hit_bytes=2459840828i,hit_responses=231195i,max_size=536870912i,miss_bytes=18742246i,miss_bytes_written=85199i,miss_responses=2816i,miss_responses_written=69i,revalidated_bytes=0i,revalidated_responses=0i,size=774144i,stale_bytes=0i,stale_responses=0i,updating_bytes=0i,updating_responses=0i 1539163506000000000
> nginx_plus_api_stream_server_zones,host=localhost,port=80,source=localhost,zone=postgresql_loadbalancer connections=173639i,processing=0i,received=17884817i,sent=33685966i 1539163506000000000
> nginx_plus_api_stream_server_zones,host=localhost,port=80,source=localhost,zone=dns_loadbalancer connections=97255i,processing=0i,received=2699082i,sent=16566552i 1539163506000000000
> nginx_plus_api_stream_upstreams,host=localhost,port=80,source=localhost,upstream=postgresql_backends zombies=0i 1539163507000000000
> nginx_plus_api_stream_upstream_peers,host=localhost,id=0,port=80,source=localhost,upstream=postgresql_backends,upstream_address=10.0.0.2:15432 active=0i,backup=false,connect_time=4i,connections=57880i,downtime=0i,fails=0i,first_byte_time=10i,healthchecks_checks=34781i,healthchecks_fails=0i,healthchecks_last_passed=true,healthchecks_unhealthy=0i,received=11228720i,response_time=10i,sent=5961640i,state="up",unavail=0i,weight=1i 1539163507000000000
> nginx_plus_api_stream_upstream_peers,host=localhost,id=1,port=80,source=localhost,upstream=postgresql_backends,upstream_address=10.0.0.2:15433 active=0i,backup=false,connect_time=3i,connections=57880i,downtime=0i,fails=0i,first_byte_time=9i,healthchecks_checks=34781i,healthchecks_fails=0i,healthchecks_last_passed=true,healthchecks_unhealthy=0i,received=11228720i,response_time=10i,sent=5961640i,state="up",unavail=0i,weight=1i 1539163507000000000
> nginx_plus_api_stream_upstream_peers,host=localhost,id=2,port=80,source=localhost,upstream=postgresql_backends,upstream_address=10.0.0.2:15434 active=0i,backup=false,connect_time=2i,connections=57879i,downtime=0i,fails=0i,first_byte_time=9i,healthchecks_checks=34781i,healthchecks_fails=0i,healthchecks_last_passed=true,healthchecks_unhealthy=0i,received=11228526i,response_time=9i,sent=5961537i,state="up",unavail=0i,weight=1i 1539163507000000000
> nginx_plus_api_stream_upstream_peers,host=localhost,id=3,port=80,source=localhost,upstream=postgresql_backends,upstream_address=10.0.0.2:15435 active=0i,backup=false,connections=0i,downtime=0i,fails=0i,healthchecks_checks=0i,healthchecks_fails=0i,healthchecks_unhealthy=0i,received=0i,sent=0i,state="down",unavail=0i,weight=1i 1539163507000000000
> nginx_plus_api_stream_upstreams,host=localhost,port=80,source=localhost,upstream=dns_udp_backends zombies=0i 1539163507000000000
> nginx_plus_api_stream_upstream_peers,host=localhost,id=0,port=80,source=localhost,upstream=dns_udp_backends,upstream_address=10.0.0.5:53 active=0i,backup=false,connect_time=0i,connections=64837i,downtime=0i,fails=0i,first_byte_time=17i,healthchecks_checks=34761i,healthchecks_fails=0i,healthchecks_last_passed=true,healthchecks_unhealthy=0i,received=10996616i,response_time=17i,sent=1791693i,state="up",unavail=0i,weight=2i 1539163507000000000
> nginx_plus_api_stream_upstream_peers,host=localhost,id=1,port=80,source=localhost,upstream=dns_udp_backends,upstream_address=10.0.0.2:53 active=0i,backup=false,connect_time=0i,connections=32418i,downtime=0i,fails=0i,first_byte_time=17i,healthchecks_checks=34761i,healthchecks_fails=0i,healthchecks_last_passed=true,healthchecks_unhealthy=0i,received=5569936i,response_time=17i,sent=907389i,state="up",unavail=0i,weight=1i 1539163507000000000
> nginx_plus_api_stream_upstream_peers,host=localhost,id=2,port=80,source=localhost,upstream=dns_udp_backends,upstream_address=10.0.0.7:53 active=0i,backup=false,connections=0i,downtime=0i,fails=0i,healthchecks_checks=0i,healthchecks_fails=0i,healthchecks_unhealthy=0i,received=0i,sent=0i,state="down",unavail=0i,weight=1i 1539163507000000000
> nginx_plus_api_stream_upstreams,host=localhost,port=80,source=localhost,upstream=unused_tcp_backends zombies=0i 1539163507000000000
> nginx_plus_api_stream_upstream_peers,host=localhost,id=1,port=80,source=localhost,upstream=unused_tcp_backends,upstream_address=95.211.80.227:80 active=0i,backup=false,connections=0i,downtime=0i,fails=0i,healthchecks_checks=0i,healthchecks_fails=0i,healthchecks_unhealthy=0i,received=0i,sent=0i,state="down",unavail=0i,weight=1i 1539163507000000000
> nginx_plus_api_stream_upstream_peers,host=localhost,id=2,port=80,source=localhost,upstream=unused_tcp_backends,upstream_address=206.251.255.63:80 active=0i,backup=false,connections=0i,downtime=0i,fails=0i,healthchecks_checks=0i,healthchecks_fails=0i,healthchecks_unhealthy=0i,received=0i,sent=0i,state="down",unavail=0i,weight=1i 1539163507000000000
> nginx_plus_api_stream_upstream_peers,host=localhost,id=3,port=80,source=localhost,upstream=unused_tcp_backends,upstream_address=[2001:1af8:4060:a004:21::e3]:80 active=0i,backup=false,connections=0i,downtime=0i,fails=0i,healthchecks_checks=0i,healthchecks_fails=0i,healthchecks_unhealthy=0i,received=0i,sent=0i,state="down",unavail=0i,weight=1i 1539163507000000000
> nginx_plus_api_stream_upstream_peers,host=localhost,id=4,port=80,source=localhost,upstream=unused_tcp_backends,upstream_address=[2606:7100:1:69::3f]:80 active=0i,backup=false,connections=0i,downtime=0i,fails=0i,healthchecks_checks=0i,healthchecks_fails=0i,healthchecks_unhealthy=0i,received=0i,sent=0i,state="down",unavail=0i,weight=1i 1539163507000000000
```
### Reference material
[api documentation](http://demo.nginx.com/swagger-ui/#/)

View File

@ -0,0 +1,115 @@
package nginx_plus_api
import (
"fmt"
"net/http"
"net/url"
"sync"
"time"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/plugins/inputs"
)
type NginxPlusApi struct {
Urls []string
ApiVersion int64
client *http.Client
ResponseTimeout internal.Duration
}
const (
// Default settings
defaultApiVersion = 3
// Paths
processesPath = "processes"
connectionsPath = "connections"
sslPath = "ssl"
httpRequestsPath = "http/requests"
httpServerZonesPath = "http/server_zones"
httpUpstreamsPath = "http/upstreams"
httpCachesPath = "http/caches"
streamServerZonesPath = "stream/server_zones"
streamUpstreamsPath = "stream/upstreams"
)
var sampleConfig = `
## An array of API URI to gather stats.
urls = ["http://localhost/api"]
# Nginx API version, default: 3
# api_version = 3
# HTTP response timeout (default: 5s)
response_timeout = "5s"
`
func (n *NginxPlusApi) SampleConfig() string {
return sampleConfig
}
func (n *NginxPlusApi) Description() string {
return "Read Nginx Plus Api documentation"
}
func (n *NginxPlusApi) Gather(acc telegraf.Accumulator) error {
var wg sync.WaitGroup
// Create an HTTP client that is re-used for each
// collection interval
if n.ApiVersion == 0 {
n.ApiVersion = defaultApiVersion
}
if n.client == nil {
client, err := n.createHttpClient()
if err != nil {
return err
}
n.client = client
}
for _, u := range n.Urls {
addr, err := url.Parse(u)
if err != nil {
acc.AddError(fmt.Errorf("Unable to parse address '%s': %s", u, err))
continue
}
wg.Add(1)
go func(addr *url.URL) {
defer wg.Done()
n.gatherMetrics(addr, acc)
}(addr)
}
wg.Wait()
return nil
}
func (n *NginxPlusApi) createHttpClient() (*http.Client, error) {
if n.ResponseTimeout.Duration < time.Second {
n.ResponseTimeout.Duration = time.Second * 5
}
client := &http.Client{
Transport: &http.Transport{},
Timeout: n.ResponseTimeout.Duration,
}
return client, nil
}
func init() {
inputs.Add("nginx_plus_api", func() telegraf.Input {
return &NginxPlusApi{}
})
}

View File

@ -0,0 +1,454 @@
package nginx_plus_api
import (
"encoding/json"
"fmt"
"io/ioutil"
"net"
"net/http"
"net/url"
"strconv"
"strings"
"github.com/influxdata/telegraf"
)
func (n *NginxPlusApi) gatherMetrics(addr *url.URL, acc telegraf.Accumulator) {
acc.AddError(n.gatherProcessesMetrics(addr, acc))
acc.AddError(n.gatherConnectionsMetrics(addr, acc))
acc.AddError(n.gatherSslMetrics(addr, acc))
acc.AddError(n.gatherHttpRequestsMetrics(addr, acc))
acc.AddError(n.gatherHttpServerZonesMetrics(addr, acc))
acc.AddError(n.gatherHttpUpstreamsMetrics(addr, acc))
acc.AddError(n.gatherHttpCachesMetrics(addr, acc))
acc.AddError(n.gatherStreamServerZonesMetrics(addr, acc))
acc.AddError(n.gatherStreamUpstreamsMetrics(addr, acc))
}
func (n *NginxPlusApi) gatherUrl(addr *url.URL, path string) ([]byte, error) {
url := fmt.Sprintf("%s/%d/%s", addr.String(), n.ApiVersion, path)
resp, err := n.client.Get(url)
if err != nil {
return nil, fmt.Errorf("error making HTTP request to %s: %s", addr.String(), err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("%s returned HTTP status %s", addr.String(), resp.Status)
}
contentType := strings.Split(resp.Header.Get("Content-Type"), ";")[0]
switch contentType {
case "application/json":
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return body, nil
default:
return nil, fmt.Errorf("%s returned unexpected content type %s", url, contentType)
}
}
func (n *NginxPlusApi) gatherProcessesMetrics(addr *url.URL, acc telegraf.Accumulator) error {
body, err := n.gatherUrl(addr, processesPath)
if err != nil {
return err
}
var processes = &Processes{}
if err := json.Unmarshal(body, processes); err != nil {
return err
}
acc.AddFields(
"nginx_plus_api_processes",
map[string]interface{}{
"respawned": processes.Respawned,
},
getTags(addr),
)
return nil
}
func (n *NginxPlusApi) gatherConnectionsMetrics(addr *url.URL, acc telegraf.Accumulator) error {
body, err := n.gatherUrl(addr, connectionsPath)
if err != nil {
return err
}
var connections = &Connections{}
if err := json.Unmarshal(body, connections); err != nil {
return err
}
acc.AddFields(
"nginx_plus_api_connections",
map[string]interface{}{
"accepted": connections.Accepted,
"dropped": connections.Dropped,
"active": connections.Active,
"idle": connections.Idle,
},
getTags(addr),
)
return nil
}
func (n *NginxPlusApi) gatherSslMetrics(addr *url.URL, acc telegraf.Accumulator) error {
body, err := n.gatherUrl(addr, sslPath)
if err != nil {
return err
}
var ssl = &Ssl{}
if err := json.Unmarshal(body, ssl); err != nil {
return err
}
acc.AddFields(
"nginx_plus_api_ssl",
map[string]interface{}{
"handshakes": ssl.Handshakes,
"handshakes_failed": ssl.HandshakesFailed,
"session_reuses": ssl.SessionReuses,
},
getTags(addr),
)
return nil
}
func (n *NginxPlusApi) gatherHttpRequestsMetrics(addr *url.URL, acc telegraf.Accumulator) error {
body, err := n.gatherUrl(addr, httpRequestsPath)
if err != nil {
return err
}
var httpRequests = &HttpRequests{}
if err := json.Unmarshal(body, httpRequests); err != nil {
return err
}
acc.AddFields(
"nginx_plus_api_http_requests",
map[string]interface{}{
"total": httpRequests.Total,
"current": httpRequests.Current,
},
getTags(addr),
)
return nil
}
func (n *NginxPlusApi) gatherHttpServerZonesMetrics(addr *url.URL, acc telegraf.Accumulator) error {
body, err := n.gatherUrl(addr, httpServerZonesPath)
if err != nil {
return err
}
var httpServerZones HttpServerZones
if err := json.Unmarshal(body, &httpServerZones); err != nil {
return err
}
tags := getTags(addr)
for zoneName, zone := range httpServerZones {
zoneTags := map[string]string{}
for k, v := range tags {
zoneTags[k] = v
}
zoneTags["zone"] = zoneName
acc.AddFields(
"nginx_plus_api_http_server_zones",
func() map[string]interface{} {
result := map[string]interface{}{
"processing": zone.Processing,
"requests": zone.Requests,
"responses_1xx": zone.Responses.Responses1xx,
"responses_2xx": zone.Responses.Responses2xx,
"responses_3xx": zone.Responses.Responses3xx,
"responses_4xx": zone.Responses.Responses4xx,
"responses_5xx": zone.Responses.Responses5xx,
"responses_total": zone.Responses.Total,
"received": zone.Received,
"sent": zone.Sent,
}
if zone.Discarded != nil {
result["discarded"] = *zone.Discarded
}
return result
}(),
zoneTags,
)
}
return nil
}
func (n *NginxPlusApi) gatherHttpUpstreamsMetrics(addr *url.URL, acc telegraf.Accumulator) error {
body, err := n.gatherUrl(addr, httpUpstreamsPath)
if err != nil {
return err
}
var httpUpstreams HttpUpstreams
if err := json.Unmarshal(body, &httpUpstreams); err != nil {
return err
}
tags := getTags(addr)
for upstreamName, upstream := range httpUpstreams {
upstreamTags := map[string]string{}
for k, v := range tags {
upstreamTags[k] = v
}
upstreamTags["upstream"] = upstreamName
upstreamFields := map[string]interface{}{
"keepalive": upstream.Keepalive,
"zombies": upstream.Zombies,
}
if upstream.Queue != nil {
upstreamFields["queue_size"] = upstream.Queue.Size
upstreamFields["queue_max_size"] = upstream.Queue.MaxSize
upstreamFields["queue_overflows"] = upstream.Queue.Overflows
}
acc.AddFields(
"nginx_plus_api_http_upstreams",
upstreamFields,
upstreamTags,
)
for _, peer := range upstream.Peers {
peerFields := map[string]interface{}{
"backup": peer.Backup,
"weight": peer.Weight,
"state": peer.State,
"active": peer.Active,
"requests": peer.Requests,
"responses_1xx": peer.Responses.Responses1xx,
"responses_2xx": peer.Responses.Responses2xx,
"responses_3xx": peer.Responses.Responses3xx,
"responses_4xx": peer.Responses.Responses4xx,
"responses_5xx": peer.Responses.Responses5xx,
"responses_total": peer.Responses.Total,
"sent": peer.Sent,
"received": peer.Received,
"fails": peer.Fails,
"unavail": peer.Unavail,
"healthchecks_checks": peer.HealthChecks.Checks,
"healthchecks_fails": peer.HealthChecks.Fails,
"healthchecks_unhealthy": peer.HealthChecks.Unhealthy,
"downtime": peer.Downtime,
//"selected": peer.Selected.toInt64,
//"downstart": peer.Downstart.toInt64,
}
if peer.HealthChecks.LastPassed != nil {
peerFields["healthchecks_last_passed"] = *peer.HealthChecks.LastPassed
}
if peer.HeaderTime != nil {
peerFields["header_time"] = *peer.HeaderTime
}
if peer.ResponseTime != nil {
peerFields["response_time"] = *peer.ResponseTime
}
if peer.MaxConns != nil {
peerFields["max_conns"] = *peer.MaxConns
}
peerTags := map[string]string{}
for k, v := range upstreamTags {
peerTags[k] = v
}
peerTags["upstream_address"] = peer.Server
if peer.ID != nil {
peerTags["id"] = strconv.Itoa(*peer.ID)
}
acc.AddFields("nginx_plus_api_http_upstream_peers", peerFields, peerTags)
}
}
return nil
}
func (n *NginxPlusApi) gatherHttpCachesMetrics(addr *url.URL, acc telegraf.Accumulator) error {
body, err := n.gatherUrl(addr, httpCachesPath)
if err != nil {
return err
}
var httpCaches HttpCaches
if err := json.Unmarshal(body, &httpCaches); err != nil {
return err
}
tags := getTags(addr)
for cacheName, cache := range httpCaches {
cacheTags := map[string]string{}
for k, v := range tags {
cacheTags[k] = v
}
cacheTags["cache"] = cacheName
acc.AddFields(
"nginx_plus_api_http_caches",
map[string]interface{}{
"size": cache.Size,
"max_size": cache.MaxSize,
"cold": cache.Cold,
"hit_responses": cache.Hit.Responses,
"hit_bytes": cache.Hit.Bytes,
"stale_responses": cache.Stale.Responses,
"stale_bytes": cache.Stale.Bytes,
"updating_responses": cache.Updating.Responses,
"updating_bytes": cache.Updating.Bytes,
"revalidated_responses": cache.Revalidated.Responses,
"revalidated_bytes": cache.Revalidated.Bytes,
"miss_responses": cache.Miss.Responses,
"miss_bytes": cache.Miss.Bytes,
"miss_responses_written": cache.Miss.ResponsesWritten,
"miss_bytes_written": cache.Miss.BytesWritten,
"expired_responses": cache.Expired.Responses,
"expired_bytes": cache.Expired.Bytes,
"expired_responses_written": cache.Expired.ResponsesWritten,
"expired_bytes_written": cache.Expired.BytesWritten,
"bypass_responses": cache.Bypass.Responses,
"bypass_bytes": cache.Bypass.Bytes,
"bypass_responses_written": cache.Bypass.ResponsesWritten,
"bypass_bytes_written": cache.Bypass.BytesWritten,
},
cacheTags,
)
}
return nil
}
func (n *NginxPlusApi) gatherStreamServerZonesMetrics(addr *url.URL, acc telegraf.Accumulator) error {
body, err := n.gatherUrl(addr, streamServerZonesPath)
if err != nil {
return err
}
var streamServerZones StreamServerZones
if err := json.Unmarshal(body, &streamServerZones); err != nil {
return err
}
tags := getTags(addr)
for zoneName, zone := range streamServerZones {
zoneTags := map[string]string{}
for k, v := range tags {
zoneTags[k] = v
}
zoneTags["zone"] = zoneName
acc.AddFields(
"nginx_plus_api_stream_server_zones",
map[string]interface{}{
"processing": zone.Processing,
"connections": zone.Connections,
"received": zone.Received,
"sent": zone.Sent,
},
zoneTags,
)
}
return nil
}
func (n *NginxPlusApi) gatherStreamUpstreamsMetrics(addr *url.URL, acc telegraf.Accumulator) error {
body, err := n.gatherUrl(addr, streamUpstreamsPath)
if err != nil {
return err
}
var streamUpstreams StreamUpstreams
if err := json.Unmarshal(body, &streamUpstreams); err != nil {
return err
}
tags := getTags(addr)
for upstreamName, upstream := range streamUpstreams {
upstreamTags := map[string]string{}
for k, v := range tags {
upstreamTags[k] = v
}
upstreamTags["upstream"] = upstreamName
acc.AddFields(
"nginx_plus_api_stream_upstreams",
map[string]interface{}{
"zombies": upstream.Zombies,
},
upstreamTags,
)
for _, peer := range upstream.Peers {
peerFields := map[string]interface{}{
"backup": peer.Backup,
"weight": peer.Weight,
"state": peer.State,
"active": peer.Active,
"connections": peer.Connections,
"sent": peer.Sent,
"received": peer.Received,
"fails": peer.Fails,
"unavail": peer.Unavail,
"healthchecks_checks": peer.HealthChecks.Checks,
"healthchecks_fails": peer.HealthChecks.Fails,
"healthchecks_unhealthy": peer.HealthChecks.Unhealthy,
"downtime": peer.Downtime,
}
if peer.HealthChecks.LastPassed != nil {
peerFields["healthchecks_last_passed"] = *peer.HealthChecks.LastPassed
}
if peer.ConnectTime != nil {
peerFields["connect_time"] = *peer.ConnectTime
}
if peer.FirstByteTime != nil {
peerFields["first_byte_time"] = *peer.FirstByteTime
}
if peer.ResponseTime != nil {
peerFields["response_time"] = *peer.ResponseTime
}
peerTags := map[string]string{}
for k, v := range upstreamTags {
peerTags[k] = v
}
peerTags["upstream_address"] = peer.Server
peerTags["id"] = strconv.Itoa(peer.ID)
acc.AddFields("nginx_plus_api_stream_upstream_peers", peerFields, peerTags)
}
}
return nil
}
func getTags(addr *url.URL) map[string]string {
h := addr.Host
host, port, err := net.SplitHostPort(h)
if err != nil {
host = addr.Host
if addr.Scheme == "http" {
port = "80"
} else if addr.Scheme == "https" {
port = "443"
} else {
port = ""
}
}
return map[string]string{"source": host, "port": port}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,133 @@
package nginx_plus_api
type Processes struct {
Respawned int `json:"respawned"`
}
type Connections struct {
Accepted int64 `json:"accepted"`
Dropped int64 `json:"dropped"`
Active int64 `json:"active"`
Idle int64 `json:"idle"`
}
type Ssl struct { // added in version 6
Handshakes int64 `json:"handshakes"`
HandshakesFailed int64 `json:"handshakes_failed"`
SessionReuses int64 `json:"session_reuses"`
}
type HttpRequests struct {
Total int64 `json:"total"`
Current int64 `json:"current"`
}
type ResponseStats struct {
Responses1xx int64 `json:"1xx"`
Responses2xx int64 `json:"2xx"`
Responses3xx int64 `json:"3xx"`
Responses4xx int64 `json:"4xx"`
Responses5xx int64 `json:"5xx"`
Total int64 `json:"total"`
}
type HttpServerZones map[string]struct {
Processing int `json:"processing"`
Requests int64 `json:"requests"`
Responses ResponseStats `json:"responses"`
Discarded *int64 `json:"discarded"` // added in version 6
Received int64 `json:"received"`
Sent int64 `json:"sent"`
}
type HealthCheckStats struct {
Checks int64 `json:"checks"`
Fails int64 `json:"fails"`
Unhealthy int64 `json:"unhealthy"`
LastPassed *bool `json:"last_passed"`
}
type HttpUpstreams map[string]struct {
Peers []struct {
ID *int `json:"id"` // added in version 3
Server string `json:"server"`
Backup bool `json:"backup"`
Weight int `json:"weight"`
State string `json:"state"`
Active int `json:"active"`
Keepalive *int `json:"keepalive"` // removed in version 5
MaxConns *int `json:"max_conns"` // added in version 3
Requests int64 `json:"requests"`
Responses ResponseStats `json:"responses"`
Sent int64 `json:"sent"`
Received int64 `json:"received"`
Fails int64 `json:"fails"`
Unavail int64 `json:"unavail"`
HealthChecks HealthCheckStats `json:"health_checks"`
Downtime int64 `json:"downtime"`
HeaderTime *int64 `json:"header_time"` // added in version 5
ResponseTime *int64 `json:"response_time"` // added in version 5
} `json:"peers"`
Keepalive int `json:"keepalive"`
Zombies int `json:"zombies"` // added in version 6
Queue *struct { // added in version 6
Size int `json:"size"`
MaxSize int `json:"max_size"`
Overflows int64 `json:"overflows"`
} `json:"queue"`
}
type StreamServerZones map[string]struct {
Processing int `json:"processing"`
Connections int `json:"connections"`
Sessions *ResponseStats `json:"sessions"`
Discarded *int64 `json:"discarded"` // added in version 7
Received int64 `json:"received"`
Sent int64 `json:"sent"`
}
type StreamUpstreams map[string]struct {
Peers []struct {
ID int `json:"id"`
Server string `json:"server"`
Backup bool `json:"backup"`
Weight int `json:"weight"`
State string `json:"state"`
Active int `json:"active"`
Connections int64 `json:"connections"`
ConnectTime *int `json:"connect_time"`
FirstByteTime *int `json:"first_byte_time"`
ResponseTime *int `json:"response_time"`
Sent int64 `json:"sent"`
Received int64 `json:"received"`
Fails int64 `json:"fails"`
Unavail int64 `json:"unavail"`
HealthChecks HealthCheckStats `json:"health_checks"`
Downtime int64 `json:"downtime"`
} `json:"peers"`
Zombies int `json:"zombies"`
}
type BasicHitStats struct {
Responses int64 `json:"responses"`
Bytes int64 `json:"bytes"`
}
type ExtendedHitStats struct {
BasicHitStats
ResponsesWritten int64 `json:"responses_written"`
BytesWritten int64 `json:"bytes_written"`
}
type HttpCaches map[string]struct { // added in version 2
Size int64 `json:"size"`
MaxSize int64 `json:"max_size"`
Cold bool `json:"cold"`
Hit BasicHitStats `json:"hit"`
Stale BasicHitStats `json:"stale"`
Updating BasicHitStats `json:"updating"`
Revalidated *BasicHitStats `json:"revalidated"` // added in version 3
Miss ExtendedHitStats `json:"miss"`
Expired ExtendedHitStats `json:"expired"`
Bypass ExtendedHitStats `json:"bypass"`
}