Add nginx-module-vts input plugin. (#3782)
This commit is contained in:
parent
2ff2d03389
commit
9a864d11d2
|
@ -210,6 +210,7 @@ For documentation on the latest development code see the [documentation index][d
|
|||
* [nginx_plus](./plugins/inputs/nginx_plus)
|
||||
* [nginx_plus_api](./plugins/inputs/nginx_plus_api)
|
||||
* [nsq_consumer](./plugins/inputs/nsq_consumer)
|
||||
* [nginx_vts](./plugins/inputs/nginx_vts)
|
||||
* [nsq](./plugins/inputs/nsq)
|
||||
* [nstat](./plugins/inputs/nstat)
|
||||
* [ntpq](./plugins/inputs/ntpq)
|
||||
|
|
|
@ -82,6 +82,7 @@ import (
|
|||
_ "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/nginx_vts"
|
||||
_ "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,121 @@
|
|||
# Telegraf Plugin: nginx_vts
|
||||
|
||||
This plugin gathers Nginx status using external virtual host traffic status module - https://github.com/vozlt/nginx-module-vts. This is an Nginx module that provides access to virtual host status information. It contains the current status such as servers, upstreams, caches. This is similar to the live activity monitoring of Nginx plus.
|
||||
For module configuration details please see its [documentation](https://github.com/vozlt/nginx-module-vts#synopsis).
|
||||
|
||||
### Configuration:
|
||||
|
||||
```
|
||||
# Read nginx status information using nginx-module-vts module
|
||||
[[inputs.nginx_vts]]
|
||||
## An array of Nginx status URIs to gather stats.
|
||||
urls = ["http://localhost/status"]
|
||||
```
|
||||
|
||||
### Measurements & Fields:
|
||||
|
||||
- nginx_vts_connections
|
||||
- active
|
||||
- reading
|
||||
- writing
|
||||
- waiting
|
||||
- accepted
|
||||
- handled
|
||||
- requests
|
||||
- nginx_vts_server, nginx_vts_filter
|
||||
- requests
|
||||
- request_time
|
||||
- in_bytes
|
||||
- out_bytes
|
||||
- response_1xx_count
|
||||
- response_2xx_count
|
||||
- response_3xx_count
|
||||
- response_4xx_count
|
||||
- response_5xx_count
|
||||
- cache_miss
|
||||
- cache_bypass
|
||||
- cache_expired
|
||||
- cache_stale
|
||||
- cache_updating
|
||||
- cache_revalidated
|
||||
- cache_hit
|
||||
- cache_scarce
|
||||
- nginx_vts_upstream
|
||||
- requests
|
||||
- request_time
|
||||
- response_time
|
||||
- in_bytes
|
||||
- out_bytes
|
||||
- response_1xx_count
|
||||
- response_2xx_count
|
||||
- response_3xx_count
|
||||
- response_4xx_count
|
||||
- response_5xx_count
|
||||
- weight
|
||||
- max_fails
|
||||
- fail_timeout
|
||||
- backup
|
||||
- down
|
||||
- nginx_vts_cache
|
||||
- max_bytes
|
||||
- used_bytes
|
||||
- in_bytes
|
||||
- out_bytes
|
||||
- miss
|
||||
- bypass
|
||||
- expired
|
||||
- stale
|
||||
- updating
|
||||
- revalidated
|
||||
- hit
|
||||
- scarce
|
||||
|
||||
|
||||
### Tags:
|
||||
|
||||
- nginx_vts_connections
|
||||
- server
|
||||
- port
|
||||
- nginx_vts_server
|
||||
- server
|
||||
- port
|
||||
- zone
|
||||
- nginx_vts_filter
|
||||
- server
|
||||
- port
|
||||
- filter_name
|
||||
- filter_key
|
||||
- nginx_vts_upstream
|
||||
- server
|
||||
- port
|
||||
- upstream
|
||||
- upstream_address
|
||||
- nginx_vts_cache
|
||||
- server
|
||||
- port
|
||||
- zone
|
||||
|
||||
|
||||
### Example Output:
|
||||
|
||||
Using this configuration:
|
||||
```
|
||||
[[inputs.nginx_vts]]
|
||||
## An array of Nginx status URIs to gather stats.
|
||||
urls = ["http://localhost/status"]
|
||||
```
|
||||
|
||||
When run with:
|
||||
```
|
||||
./telegraf -config telegraf.conf -input-filter nginx_vts -test
|
||||
```
|
||||
|
||||
It produces:
|
||||
```
|
||||
nginx_vts_connections,server=localhost,port=80,host=localhost waiting=30i,accepted=295333i,handled=295333i,requests=6833487i,active=33i,reading=0i,writing=3i 1518341521000000000
|
||||
nginx_vts_server,zone=example.com,port=80,host=localhost,server=localhost cache_hit=158915i,in_bytes=1935528964i,out_bytes=6531366419i,response_2xx_count=809994i,response_4xx_count=16664i,cache_bypass=0i,cache_stale=0i,cache_revalidated=0i,requests=2187977i,response_1xx_count=0i,response_3xx_count=1360390i,cache_miss=2249i,cache_updating=0i,cache_scarce=0i,request_time=13i,response_5xx_count=929i,cache_expired=0i 1518341521000000000
|
||||
nginx_vts_server,host=localhost,server=localhost,port=80,zone=* requests=6775284i,in_bytes=5003242389i,out_bytes=36858233827i,cache_expired=318881i,cache_updating=0i,request_time=51i,response_1xx_count=0i,response_2xx_count=4385916i,response_4xx_count=83680i,response_5xx_count=1186i,cache_bypass=0i,cache_revalidated=0i,cache_hit=1972222i,cache_scarce=0i,response_3xx_count=2304502i,cache_miss=408251i,cache_stale=0i 1518341521000000000
|
||||
nginx_vts_filter,filter_key=FI,filter_name=country,port=80,host=localhost,server=localhost request_time=0i,in_bytes=139701i,response_3xx_count=0i,out_bytes=2644495i,response_1xx_count=0i,cache_expired=0i,cache_scarce=0i,requests=179i,cache_miss=0i,cache_bypass=0i,cache_stale=0i,cache_updating=0i,cache_revalidated=0i,cache_hit=0i,response_2xx_count=177i,response_4xx_count=2i,response_5xx_count=0i 1518341521000000000
|
||||
nginx_vts_upstream,port=80,host=localhost,upstream=backend_cluster,upstream_address=127.0.0.1:6000,server=localhost fail_timeout=10i,backup=false,request_time=31i,response_5xx_count=1081i,response_2xx_count=1877498i,max_fails=1i,in_bytes=2763336289i,out_bytes=19470265071i,weight=1i,down=false,response_time=31i,response_1xx_count=0i,response_4xx_count=76125i,requests=3379232i,response_3xx_count=1424528i 1518341521000000000
|
||||
nginx_vts_cache,server=localhost,port=80,host=localhost,zone=example stale=0i,used_bytes=64334336i,miss=394573i,bypass=0i,expired=318788i,updating=0i,revalidated=0i,hit=689883i,scarce=0i,max_bytes=9223372036854775296i,in_bytes=1111161581i,out_bytes=19175548290i 1518341521000000000
|
||||
```
|
|
@ -0,0 +1,341 @@
|
|||
package nginx_vts
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/internal"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
type NginxVTS struct {
|
||||
Urls []string
|
||||
|
||||
client *http.Client
|
||||
|
||||
ResponseTimeout internal.Duration
|
||||
}
|
||||
|
||||
var sampleConfig = `
|
||||
## An array of ngx_http_status_module or status URI to gather stats.
|
||||
urls = ["http://localhost/status"]
|
||||
|
||||
## HTTP response timeout (default: 5s)
|
||||
response_timeout = "5s"
|
||||
`
|
||||
|
||||
func (n *NginxVTS) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
func (n *NginxVTS) Description() string {
|
||||
return "Read Nginx virtual host traffic status module information (nginx-module-vts)"
|
||||
}
|
||||
|
||||
func (n *NginxVTS) Gather(acc telegraf.Accumulator) error {
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// Create an HTTP client that is re-used for each
|
||||
// collection interval
|
||||
|
||||
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()
|
||||
acc.AddError(n.gatherURL(addr, acc))
|
||||
}(addr)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *NginxVTS) 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 (n *NginxVTS) gatherURL(addr *url.URL, acc telegraf.Accumulator) error {
|
||||
resp, err := n.client.Get(addr.String())
|
||||
if err != nil {
|
||||
return fmt.Errorf("error making HTTP request to %s: %s", addr.String(), err)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return 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":
|
||||
return gatherStatusURL(bufio.NewReader(resp.Body), getTags(addr), acc)
|
||||
default:
|
||||
return fmt.Errorf("%s returned unexpected content type %s", addr.String(), contentType)
|
||||
}
|
||||
}
|
||||
|
||||
type NginxVTSResponse struct {
|
||||
Connections struct {
|
||||
Active uint64 `json:"active"`
|
||||
Reading uint64 `json:"reading"`
|
||||
Writing uint64 `json:"writing"`
|
||||
Waiting uint64 `json:"waiting"`
|
||||
Accepted uint64 `json:"accepted"`
|
||||
Handled uint64 `json:"handled"`
|
||||
Requests uint64 `json:"requests"`
|
||||
} `json:"connections"`
|
||||
ServerZones map[string]Server `json:"serverZones"`
|
||||
FilterZones map[string]map[string]Server `json:"filterZones"`
|
||||
UpstreamZones map[string][]Upstream `json:"upstreamZones"`
|
||||
CacheZones map[string]Cache `json:"cacheZones"`
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
RequestCounter uint64 `json:"requestCounter"`
|
||||
InBytes uint64 `json:"inBytes"`
|
||||
OutBytes uint64 `json:"outBytes"`
|
||||
RequestMsec uint64 `json:"requestMsec"`
|
||||
Responses struct {
|
||||
OneXx uint64 `json:"1xx"`
|
||||
TwoXx uint64 `json:"2xx"`
|
||||
ThreeXx uint64 `json:"3xx"`
|
||||
FourXx uint64 `json:"4xx"`
|
||||
FiveXx uint64 `json:"5xx"`
|
||||
Miss uint64 `json:"miss"`
|
||||
Bypass uint64 `json:"bypass"`
|
||||
Expired uint64 `json:"expired"`
|
||||
Stale uint64 `json:"stale"`
|
||||
Updating uint64 `json:"updating"`
|
||||
Revalidated uint64 `json:"revalidated"`
|
||||
Hit uint64 `json:"hit"`
|
||||
Scarce uint64 `json:"scarce"`
|
||||
} `json:"responses"`
|
||||
}
|
||||
|
||||
type Upstream struct {
|
||||
Server string `json:"server"`
|
||||
RequestCounter uint64 `json:"requestCounter"`
|
||||
InBytes uint64 `json:"inBytes"`
|
||||
OutBytes uint64 `json:"outBytes"`
|
||||
Responses struct {
|
||||
OneXx uint64 `json:"1xx"`
|
||||
TwoXx uint64 `json:"2xx"`
|
||||
ThreeXx uint64 `json:"3xx"`
|
||||
FourXx uint64 `json:"4xx"`
|
||||
FiveXx uint64 `json:"5xx"`
|
||||
} `json:"responses"`
|
||||
ResponseMsec uint64 `json:"responseMsec"`
|
||||
RequestMsec uint64 `json:"requestMsec"`
|
||||
Weight uint64 `json:"weight"`
|
||||
MaxFails uint64 `json:"maxFails"`
|
||||
FailTimeout uint64 `json:"failTimeout"`
|
||||
Backup bool `json:"backup"`
|
||||
Down bool `json:"down"`
|
||||
}
|
||||
|
||||
type Cache struct {
|
||||
MaxSize uint64 `json:"maxSize"`
|
||||
UsedSize uint64 `json:"usedSize"`
|
||||
InBytes uint64 `json:"inBytes"`
|
||||
OutBytes uint64 `json:"outBytes"`
|
||||
Responses struct {
|
||||
Miss uint64 `json:"miss"`
|
||||
Bypass uint64 `json:"bypass"`
|
||||
Expired uint64 `json:"expired"`
|
||||
Stale uint64 `json:"stale"`
|
||||
Updating uint64 `json:"updating"`
|
||||
Revalidated uint64 `json:"revalidated"`
|
||||
Hit uint64 `json:"hit"`
|
||||
Scarce uint64 `json:"scarce"`
|
||||
} `json:"responses"`
|
||||
}
|
||||
|
||||
func gatherStatusURL(r *bufio.Reader, tags map[string]string, acc telegraf.Accumulator) error {
|
||||
dec := json.NewDecoder(r)
|
||||
status := &NginxVTSResponse{}
|
||||
if err := dec.Decode(status); err != nil {
|
||||
return fmt.Errorf("Error while decoding JSON response")
|
||||
}
|
||||
|
||||
acc.AddFields("nginx_vts_connections", map[string]interface{}{
|
||||
"active": status.Connections.Active,
|
||||
"reading": status.Connections.Reading,
|
||||
"writing": status.Connections.Writing,
|
||||
"waiting": status.Connections.Waiting,
|
||||
"accepted": status.Connections.Accepted,
|
||||
"handled": status.Connections.Handled,
|
||||
"requests": status.Connections.Requests,
|
||||
}, tags)
|
||||
|
||||
for zoneName, zone := range status.ServerZones {
|
||||
zoneTags := map[string]string{}
|
||||
for k, v := range tags {
|
||||
zoneTags[k] = v
|
||||
}
|
||||
zoneTags["zone"] = zoneName
|
||||
|
||||
acc.AddFields("nginx_vts_server", map[string]interface{}{
|
||||
"requests": zone.RequestCounter,
|
||||
"request_time": zone.RequestMsec,
|
||||
"in_bytes": zone.InBytes,
|
||||
"out_bytes": zone.OutBytes,
|
||||
|
||||
"response_1xx_count": zone.Responses.OneXx,
|
||||
"response_2xx_count": zone.Responses.TwoXx,
|
||||
"response_3xx_count": zone.Responses.ThreeXx,
|
||||
"response_4xx_count": zone.Responses.FourXx,
|
||||
"response_5xx_count": zone.Responses.FiveXx,
|
||||
|
||||
"cache_miss": zone.Responses.Miss,
|
||||
"cache_bypass": zone.Responses.Bypass,
|
||||
"cache_expired": zone.Responses.Expired,
|
||||
"cache_stale": zone.Responses.Stale,
|
||||
"cache_updating": zone.Responses.Updating,
|
||||
"cache_revalidated": zone.Responses.Revalidated,
|
||||
"cache_hit": zone.Responses.Hit,
|
||||
"cache_scarce": zone.Responses.Scarce,
|
||||
}, zoneTags)
|
||||
}
|
||||
|
||||
for filterName, filters := range status.FilterZones {
|
||||
for filterKey, upstream := range filters {
|
||||
filterTags := map[string]string{}
|
||||
for k, v := range tags {
|
||||
filterTags[k] = v
|
||||
}
|
||||
filterTags["filter_key"] = filterKey
|
||||
filterTags["filter_name"] = filterName
|
||||
|
||||
acc.AddFields("nginx_vts_filter", map[string]interface{}{
|
||||
"requests": upstream.RequestCounter,
|
||||
"request_time": upstream.RequestMsec,
|
||||
"in_bytes": upstream.InBytes,
|
||||
"out_bytes": upstream.OutBytes,
|
||||
|
||||
"response_1xx_count": upstream.Responses.OneXx,
|
||||
"response_2xx_count": upstream.Responses.TwoXx,
|
||||
"response_3xx_count": upstream.Responses.ThreeXx,
|
||||
"response_4xx_count": upstream.Responses.FourXx,
|
||||
"response_5xx_count": upstream.Responses.FiveXx,
|
||||
|
||||
"cache_miss": upstream.Responses.Miss,
|
||||
"cache_bypass": upstream.Responses.Bypass,
|
||||
"cache_expired": upstream.Responses.Expired,
|
||||
"cache_stale": upstream.Responses.Stale,
|
||||
"cache_updating": upstream.Responses.Updating,
|
||||
"cache_revalidated": upstream.Responses.Revalidated,
|
||||
"cache_hit": upstream.Responses.Hit,
|
||||
"cache_scarce": upstream.Responses.Scarce,
|
||||
}, filterTags)
|
||||
}
|
||||
}
|
||||
|
||||
for upstreamName, upstreams := range status.UpstreamZones {
|
||||
for _, upstream := range upstreams {
|
||||
upstreamServerTags := map[string]string{}
|
||||
for k, v := range tags {
|
||||
upstreamServerTags[k] = v
|
||||
}
|
||||
upstreamServerTags["upstream"] = upstreamName
|
||||
upstreamServerTags["upstream_address"] = upstream.Server
|
||||
acc.AddFields("nginx_vts_upstream", map[string]interface{}{
|
||||
"requests": upstream.RequestCounter,
|
||||
"request_time": upstream.RequestMsec,
|
||||
"response_time": upstream.ResponseMsec,
|
||||
"in_bytes": upstream.InBytes,
|
||||
"out_bytes": upstream.OutBytes,
|
||||
|
||||
"response_1xx_count": upstream.Responses.OneXx,
|
||||
"response_2xx_count": upstream.Responses.TwoXx,
|
||||
"response_3xx_count": upstream.Responses.ThreeXx,
|
||||
"response_4xx_count": upstream.Responses.FourXx,
|
||||
"response_5xx_count": upstream.Responses.FiveXx,
|
||||
|
||||
"weight": upstream.Weight,
|
||||
"max_fails": upstream.MaxFails,
|
||||
"fail_timeout": upstream.FailTimeout,
|
||||
"backup": upstream.Backup,
|
||||
"down": upstream.Down,
|
||||
}, upstreamServerTags)
|
||||
}
|
||||
}
|
||||
|
||||
for zoneName, zone := range status.CacheZones {
|
||||
zoneTags := map[string]string{}
|
||||
for k, v := range tags {
|
||||
zoneTags[k] = v
|
||||
}
|
||||
zoneTags["zone"] = zoneName
|
||||
|
||||
acc.AddFields("nginx_vts_cache", map[string]interface{}{
|
||||
"max_bytes": zone.MaxSize,
|
||||
"used_bytes": zone.UsedSize,
|
||||
"in_bytes": zone.InBytes,
|
||||
"out_bytes": zone.OutBytes,
|
||||
|
||||
"miss": zone.Responses.Miss,
|
||||
"bypass": zone.Responses.Bypass,
|
||||
"expired": zone.Responses.Expired,
|
||||
"stale": zone.Responses.Stale,
|
||||
"updating": zone.Responses.Updating,
|
||||
"revalidated": zone.Responses.Revalidated,
|
||||
"hit": zone.Responses.Hit,
|
||||
"scarce": zone.Responses.Scarce,
|
||||
}, zoneTags)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get tag(s) for the nginx plugin
|
||||
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}
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("nginx_vts", func() telegraf.Input {
|
||||
return &NginxVTS{}
|
||||
})
|
||||
}
|
|
@ -0,0 +1,486 @@
|
|||
package nginx_vts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const sampleStatusResponse = `
|
||||
{
|
||||
"hostName": "test.example.com",
|
||||
"nginxVersion": "1.12.2",
|
||||
"loadMsec": 1518180328331,
|
||||
"nowMsec": 1518256058416,
|
||||
"connections": {
|
||||
"active": 111,
|
||||
"reading": 222,
|
||||
"writing": 333,
|
||||
"waiting": 444,
|
||||
"accepted": 555,
|
||||
"handled": 666,
|
||||
"requests": 777
|
||||
},
|
||||
"serverZones": {
|
||||
"example.com": {
|
||||
"requestCounter": 1415887,
|
||||
"inBytes": 1296356607,
|
||||
"outBytes": 4404939605,
|
||||
"responses": {
|
||||
"1xx": 100,
|
||||
"2xx": 200,
|
||||
"3xx": 300,
|
||||
"4xx": 400,
|
||||
"5xx": 500,
|
||||
"miss": 14,
|
||||
"bypass": 15,
|
||||
"expired": 16,
|
||||
"stale": 17,
|
||||
"updating": 18,
|
||||
"revalidated": 19,
|
||||
"hit": 20,
|
||||
"scarce": 21
|
||||
},
|
||||
"requestMsec": 13
|
||||
},
|
||||
"other.example.com": {
|
||||
"requestCounter": 505,
|
||||
"inBytes": 171388,
|
||||
"outBytes": 1273382,
|
||||
"responses": {
|
||||
"1xx": 101,
|
||||
"2xx": 201,
|
||||
"3xx": 301,
|
||||
"4xx": 401,
|
||||
"5xx": 501,
|
||||
"miss": 22,
|
||||
"bypass": 23,
|
||||
"expired": 24,
|
||||
"stale": 25,
|
||||
"updating": 26,
|
||||
"revalidated": 27,
|
||||
"hit": 28,
|
||||
"scarce": 29
|
||||
},
|
||||
"requestMsec": 12
|
||||
}
|
||||
},
|
||||
"filterZones": {
|
||||
"country": {
|
||||
"FI": {
|
||||
"requestCounter": 60,
|
||||
"inBytes": 2570,
|
||||
"outBytes": 53597,
|
||||
"responses": {
|
||||
"1xx": 106,
|
||||
"2xx": 206,
|
||||
"3xx": 306,
|
||||
"4xx": 406,
|
||||
"5xx": 506,
|
||||
"miss": 61,
|
||||
"bypass": 62,
|
||||
"expired": 63,
|
||||
"stale": 64,
|
||||
"updating": 65,
|
||||
"revalidated": 66,
|
||||
"hit": 67,
|
||||
"scarce": 68
|
||||
},
|
||||
"requestMsec": 69
|
||||
}
|
||||
}
|
||||
},
|
||||
"upstreamZones": {
|
||||
"backend_cluster": [
|
||||
{
|
||||
"server": "127.0.0.1:6000",
|
||||
"requestCounter": 2103849,
|
||||
"inBytes": 1774680141,
|
||||
"outBytes": 11727669190,
|
||||
"responses": {
|
||||
"1xx": 103,
|
||||
"2xx": 203,
|
||||
"3xx": 303,
|
||||
"4xx": 403,
|
||||
"5xx": 503
|
||||
},
|
||||
"requestMsec": 30,
|
||||
"responseMsec": 31,
|
||||
"weight": 32,
|
||||
"maxFails": 33,
|
||||
"failTimeout": 34,
|
||||
"backup": false,
|
||||
"down": false
|
||||
}
|
||||
],
|
||||
"::nogroups": [
|
||||
{
|
||||
"server": "127.0.0.1:4433",
|
||||
"requestCounter": 8,
|
||||
"inBytes": 5013,
|
||||
"outBytes": 487585,
|
||||
"responses": {
|
||||
"1xx": 104,
|
||||
"2xx": 204,
|
||||
"3xx": 304,
|
||||
"4xx": 404,
|
||||
"5xx": 504
|
||||
},
|
||||
"requestMsec": 34,
|
||||
"responseMsec": 35,
|
||||
"weight": 36,
|
||||
"maxFails": 37,
|
||||
"failTimeout": 38,
|
||||
"backup": true,
|
||||
"down": false
|
||||
},
|
||||
{
|
||||
"server": "127.0.0.1:8080",
|
||||
"requestCounter": 7,
|
||||
"inBytes": 2926,
|
||||
"outBytes": 3846638,
|
||||
"responses": {
|
||||
"1xx": 105,
|
||||
"2xx": 205,
|
||||
"3xx": 305,
|
||||
"4xx": 405,
|
||||
"5xx": 505
|
||||
},
|
||||
"requestMsec": 39,
|
||||
"responseMsec": 40,
|
||||
"weight": 41,
|
||||
"maxFails": 42,
|
||||
"failTimeout": 43,
|
||||
"backup": true,
|
||||
"down": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"cacheZones": {
|
||||
"example": {
|
||||
"maxSize": 9223372036854776000,
|
||||
"usedSize": 68639232,
|
||||
"inBytes": 697138673,
|
||||
"outBytes": 11305044106,
|
||||
"responses": {
|
||||
"miss": 44,
|
||||
"bypass": 45,
|
||||
"expired": 46,
|
||||
"stale": 47,
|
||||
"updating": 48,
|
||||
"revalidated": 49,
|
||||
"hit": 50,
|
||||
"scarce": 51
|
||||
}
|
||||
},
|
||||
"static": {
|
||||
"maxSize": 9223372036854776000,
|
||||
"usedSize": 569856,
|
||||
"inBytes": 551652333,
|
||||
"outBytes": 1114889271,
|
||||
"responses": {
|
||||
"miss": 52,
|
||||
"bypass": 53,
|
||||
"expired": 54,
|
||||
"stale": 55,
|
||||
"updating": 56,
|
||||
"revalidated": 57,
|
||||
"hit": 58,
|
||||
"scarce": 59
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
func TestNginxPlusGeneratesMetrics(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
var rsp string
|
||||
|
||||
if r.URL.Path == "/status" {
|
||||
rsp = sampleStatusResponse
|
||||
w.Header()["Content-Type"] = []string{"application/json"}
|
||||
} else {
|
||||
panic("Cannot handle request")
|
||||
}
|
||||
|
||||
fmt.Fprintln(w, rsp)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
n := &NginxVTS{
|
||||
Urls: []string{fmt.Sprintf("%s/status", ts.URL)},
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
|
||||
err := n.Gather(&acc)
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
addr, err := url.Parse(ts.URL)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
host, port, err := net.SplitHostPort(addr.Host)
|
||||
if err != nil {
|
||||
host = addr.Host
|
||||
if addr.Scheme == "http" {
|
||||
port = "80"
|
||||
} else if addr.Scheme == "https" {
|
||||
port = "443"
|
||||
} else {
|
||||
port = ""
|
||||
}
|
||||
}
|
||||
|
||||
acc.AssertContainsTaggedFields(
|
||||
t,
|
||||
"nginx_vts_connections",
|
||||
map[string]interface{}{
|
||||
"accepted": uint64(555),
|
||||
"active": uint64(111),
|
||||
"handled": uint64(666),
|
||||
"reading": uint64(222),
|
||||
"requests": uint64(777),
|
||||
"waiting": uint64(444),
|
||||
"writing": uint64(333),
|
||||
},
|
||||
map[string]string{
|
||||
"source": host,
|
||||
"port": port,
|
||||
})
|
||||
|
||||
acc.AssertContainsTaggedFields(
|
||||
t,
|
||||
"nginx_vts_server",
|
||||
map[string]interface{}{
|
||||
"requests": uint64(1415887),
|
||||
"request_time": uint64(13),
|
||||
"in_bytes": uint64(1296356607),
|
||||
"out_bytes": uint64(4404939605),
|
||||
|
||||
"response_1xx_count": uint64(100),
|
||||
"response_2xx_count": uint64(200),
|
||||
"response_3xx_count": uint64(300),
|
||||
"response_4xx_count": uint64(400),
|
||||
"response_5xx_count": uint64(500),
|
||||
|
||||
"cache_miss": uint64(14),
|
||||
"cache_bypass": uint64(15),
|
||||
"cache_expired": uint64(16),
|
||||
"cache_stale": uint64(17),
|
||||
"cache_updating": uint64(18),
|
||||
"cache_revalidated": uint64(19),
|
||||
"cache_hit": uint64(20),
|
||||
"cache_scarce": uint64(21),
|
||||
},
|
||||
map[string]string{
|
||||
"source": host,
|
||||
"port": port,
|
||||
"zone": "example.com",
|
||||
})
|
||||
|
||||
acc.AssertContainsTaggedFields(
|
||||
t,
|
||||
"nginx_vts_filter",
|
||||
map[string]interface{}{
|
||||
"requests": uint64(60),
|
||||
"request_time": uint64(69),
|
||||
"in_bytes": uint64(2570),
|
||||
"out_bytes": uint64(53597),
|
||||
|
||||
"response_1xx_count": uint64(106),
|
||||
"response_2xx_count": uint64(206),
|
||||
"response_3xx_count": uint64(306),
|
||||
"response_4xx_count": uint64(406),
|
||||
"response_5xx_count": uint64(506),
|
||||
|
||||
"cache_miss": uint64(61),
|
||||
"cache_bypass": uint64(62),
|
||||
"cache_expired": uint64(63),
|
||||
"cache_stale": uint64(64),
|
||||
"cache_updating": uint64(65),
|
||||
"cache_revalidated": uint64(66),
|
||||
"cache_hit": uint64(67),
|
||||
"cache_scarce": uint64(68),
|
||||
},
|
||||
map[string]string{
|
||||
"source": host,
|
||||
"port": port,
|
||||
"filter_key": "FI",
|
||||
"filter_name": "country",
|
||||
})
|
||||
|
||||
acc.AssertContainsTaggedFields(
|
||||
t,
|
||||
"nginx_vts_server",
|
||||
map[string]interface{}{
|
||||
"requests": uint64(505),
|
||||
"request_time": uint64(12),
|
||||
"in_bytes": uint64(171388),
|
||||
"out_bytes": uint64(1273382),
|
||||
|
||||
"response_1xx_count": uint64(101),
|
||||
"response_2xx_count": uint64(201),
|
||||
"response_3xx_count": uint64(301),
|
||||
"response_4xx_count": uint64(401),
|
||||
"response_5xx_count": uint64(501),
|
||||
|
||||
"cache_miss": uint64(22),
|
||||
"cache_bypass": uint64(23),
|
||||
"cache_expired": uint64(24),
|
||||
"cache_stale": uint64(25),
|
||||
"cache_updating": uint64(26),
|
||||
"cache_revalidated": uint64(27),
|
||||
"cache_hit": uint64(28),
|
||||
"cache_scarce": uint64(29),
|
||||
},
|
||||
map[string]string{
|
||||
"source": host,
|
||||
"port": port,
|
||||
"zone": "other.example.com",
|
||||
})
|
||||
|
||||
acc.AssertContainsTaggedFields(
|
||||
t,
|
||||
"nginx_vts_upstream",
|
||||
map[string]interface{}{
|
||||
"requests": uint64(2103849),
|
||||
"request_time": uint64(30),
|
||||
"response_time": uint64(31),
|
||||
"in_bytes": uint64(1774680141),
|
||||
"out_bytes": uint64(11727669190),
|
||||
|
||||
"response_1xx_count": uint64(103),
|
||||
"response_2xx_count": uint64(203),
|
||||
"response_3xx_count": uint64(303),
|
||||
"response_4xx_count": uint64(403),
|
||||
"response_5xx_count": uint64(503),
|
||||
|
||||
"weight": uint64(32),
|
||||
"max_fails": uint64(33),
|
||||
"fail_timeout": uint64(34),
|
||||
"backup": bool(false),
|
||||
"down": bool(false),
|
||||
},
|
||||
map[string]string{
|
||||
"source": host,
|
||||
"port": port,
|
||||
"upstream": "backend_cluster",
|
||||
"upstream_address": "127.0.0.1:6000",
|
||||
})
|
||||
|
||||
acc.AssertContainsTaggedFields(
|
||||
t,
|
||||
"nginx_vts_upstream",
|
||||
map[string]interface{}{
|
||||
"requests": uint64(8),
|
||||
"request_time": uint64(34),
|
||||
"response_time": uint64(35),
|
||||
"in_bytes": uint64(5013),
|
||||
"out_bytes": uint64(487585),
|
||||
|
||||
"response_1xx_count": uint64(104),
|
||||
"response_2xx_count": uint64(204),
|
||||
"response_3xx_count": uint64(304),
|
||||
"response_4xx_count": uint64(404),
|
||||
"response_5xx_count": uint64(504),
|
||||
|
||||
"weight": uint64(36),
|
||||
"max_fails": uint64(37),
|
||||
"fail_timeout": uint64(38),
|
||||
"backup": bool(true),
|
||||
"down": bool(false),
|
||||
},
|
||||
map[string]string{
|
||||
"source": host,
|
||||
"port": port,
|
||||
"upstream": "::nogroups",
|
||||
"upstream_address": "127.0.0.1:4433",
|
||||
})
|
||||
|
||||
acc.AssertContainsTaggedFields(
|
||||
t,
|
||||
"nginx_vts_upstream",
|
||||
map[string]interface{}{
|
||||
"requests": uint64(7),
|
||||
"request_time": uint64(39),
|
||||
"response_time": uint64(40),
|
||||
"in_bytes": uint64(2926),
|
||||
"out_bytes": uint64(3846638),
|
||||
|
||||
"response_1xx_count": uint64(105),
|
||||
"response_2xx_count": uint64(205),
|
||||
"response_3xx_count": uint64(305),
|
||||
"response_4xx_count": uint64(405),
|
||||
"response_5xx_count": uint64(505),
|
||||
|
||||
"weight": uint64(41),
|
||||
"max_fails": uint64(42),
|
||||
"fail_timeout": uint64(43),
|
||||
"backup": bool(true),
|
||||
"down": bool(true),
|
||||
},
|
||||
map[string]string{
|
||||
"source": host,
|
||||
"port": port,
|
||||
"upstream": "::nogroups",
|
||||
"upstream_address": "127.0.0.1:8080",
|
||||
})
|
||||
|
||||
acc.AssertContainsTaggedFields(
|
||||
t,
|
||||
"nginx_vts_cache",
|
||||
map[string]interface{}{
|
||||
"max_bytes": uint64(9223372036854776000),
|
||||
"used_bytes": uint64(68639232),
|
||||
"in_bytes": uint64(697138673),
|
||||
"out_bytes": uint64(11305044106),
|
||||
|
||||
"miss": uint64(44),
|
||||
"bypass": uint64(45),
|
||||
"expired": uint64(46),
|
||||
"stale": uint64(47),
|
||||
"updating": uint64(48),
|
||||
"revalidated": uint64(49),
|
||||
"hit": uint64(50),
|
||||
"scarce": uint64(51),
|
||||
},
|
||||
map[string]string{
|
||||
"source": host,
|
||||
"port": port,
|
||||
"zone": "example",
|
||||
})
|
||||
|
||||
acc.AssertContainsTaggedFields(
|
||||
t,
|
||||
"nginx_vts_cache",
|
||||
map[string]interface{}{
|
||||
"max_bytes": uint64(9223372036854776000),
|
||||
"used_bytes": uint64(569856),
|
||||
"in_bytes": uint64(551652333),
|
||||
"out_bytes": uint64(1114889271),
|
||||
|
||||
"miss": uint64(52),
|
||||
"bypass": uint64(53),
|
||||
"expired": uint64(54),
|
||||
"stale": uint64(55),
|
||||
"updating": uint64(56),
|
||||
"revalidated": uint64(57),
|
||||
"hit": uint64(58),
|
||||
"scarce": uint64(59),
|
||||
},
|
||||
map[string]string{
|
||||
"source": host,
|
||||
"port": port,
|
||||
"zone": "static",
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue