Add Nginx Plus API input (#4837)
This commit is contained in:
parent
2f7450ec04
commit
ff98ad710b
|
@ -80,6 +80,7 @@ import (
|
|||
_ "github.com/influxdata/telegraf/plugins/inputs/net_response"
|
||||
_ "github.com/influxdata/telegraf/plugins/inputs/nginx"
|
||||
_ "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_consumer"
|
||||
_ "github.com/influxdata/telegraf/plugins/inputs/nstat"
|
||||
|
|
|
@ -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/#/)
|
|
@ -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{}
|
||||
})
|
||||
}
|
|
@ -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
|
@ -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"`
|
||||
}
|
Loading…
Reference in New Issue