Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e393c3af3f
commit
4978089aab
4963 changed files with 677545 additions and 0 deletions
153
plugins/inputs/nginx_vts/README.md
Normal file
153
plugins/inputs/nginx_vts/README.md
Normal file
|
@ -0,0 +1,153 @@
|
|||
# Nginx Virtual Host Traffic Input Plugin
|
||||
|
||||
This plugin gathers metrics from the [Nginx web server][nginx] using the
|
||||
[external virtual host traffic status module][vhts_module]. This module provides
|
||||
access to virtual host status information containing the current status of
|
||||
servers, upstreams and caches, similar to the live activity monitoring of
|
||||
Nginx plus. For module configuration details please see the
|
||||
[module documentation][module_doc].
|
||||
|
||||
⭐ Telegraf v1.9.0
|
||||
🏷️ server, web
|
||||
💻 all
|
||||
|
||||
[nginx]: https://www.nginx.com
|
||||
[vhts_module]: https://github.com/vozlt/nginx-module-vts
|
||||
[module_doc]: https://github.com/vozlt/nginx-module-vts#synopsis
|
||||
|
||||
## Global configuration options <!-- @/docs/includes/plugin_config.md -->
|
||||
|
||||
In addition to the plugin-specific configuration settings, plugins support
|
||||
additional global and plugin configuration settings. These settings are used to
|
||||
modify metrics, tags, and field or create aliases and configure ordering, etc.
|
||||
See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
|
||||
|
||||
[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins
|
||||
|
||||
## Configuration
|
||||
|
||||
```toml @sample.conf
|
||||
# Read Nginx virtual host traffic status module information (nginx-module-vts)
|
||||
[[inputs.nginx_vts]]
|
||||
## 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"
|
||||
|
||||
## Optional TLS Config
|
||||
# tls_ca = "/etc/telegraf/ca.pem"
|
||||
# tls_cert = "/etc/telegraf/cert.pem"
|
||||
# tls_key = "/etc/telegraf/key.pem"
|
||||
## Use TLS but skip chain & host verification
|
||||
# insecure_skip_verify = false
|
||||
```
|
||||
|
||||
## Metrics
|
||||
|
||||
- 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
|
||||
- source
|
||||
- port
|
||||
- nginx_vts_server
|
||||
- source
|
||||
- port
|
||||
- zone
|
||||
- nginx_vts_filter
|
||||
- source
|
||||
- port
|
||||
- filter_name
|
||||
- filter_key
|
||||
- nginx_vts_upstream
|
||||
- source
|
||||
- port
|
||||
- upstream
|
||||
- upstream_address
|
||||
- nginx_vts_cache
|
||||
- source
|
||||
- port
|
||||
- zone
|
||||
|
||||
## Example Output
|
||||
|
||||
Using this configuration:
|
||||
|
||||
```toml
|
||||
[[inputs.nginx_vts]]
|
||||
## An array of Nginx status URIs to gather stats.
|
||||
urls = ["http://localhost/status"]
|
||||
```
|
||||
|
||||
When run with:
|
||||
|
||||
```sh
|
||||
./telegraf -config telegraf.conf -input-filter nginx_vts -test
|
||||
```
|
||||
|
||||
It produces:
|
||||
|
||||
```shell
|
||||
nginx_vts_connections,source=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,source=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,source=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,source=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,source=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,source=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
|
||||
```
|
343
plugins/inputs/nginx_vts/nginx_vts.go
Normal file
343
plugins/inputs/nginx_vts/nginx_vts.go
Normal file
|
@ -0,0 +1,343 @@
|
|||
//go:generate ../../../tools/readme_config_includer/generator
|
||||
package nginx_vts
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/config"
|
||||
"github.com/influxdata/telegraf/plugins/common/tls"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
//go:embed sample.conf
|
||||
var sampleConfig string
|
||||
|
||||
type NginxVTS struct {
|
||||
Urls []string `toml:"urls"`
|
||||
ResponseTimeout config.Duration `toml:"response_timeout"`
|
||||
tls.ClientConfig
|
||||
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
func (*NginxVTS) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
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 %q: %w", 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 < config.Duration(time.Second) {
|
||||
n.ResponseTimeout = config.Duration(time.Second * 5)
|
||||
}
|
||||
|
||||
tlsConfig, err := n.ClientConfig.TLSConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: tlsConfig,
|
||||
},
|
||||
Timeout: time.Duration(n.ResponseTimeout),
|
||||
}
|
||||
|
||||
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 %q: %w", 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 errors.New("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 := make(map[string]string, len(tags)+1)
|
||||
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 := make(map[string]string, len(tags)+2)
|
||||
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 := make(map[string]string, len(tags)+2)
|
||||
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 := make(map[string]string, len(tags)+1)
|
||||
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{}
|
||||
})
|
||||
}
|
485
plugins/inputs/nginx_vts/nginx_vts_test.go
Normal file
485
plugins/inputs/nginx_vts/nginx_vts_test.go
Normal file
|
@ -0,0 +1,485 @@
|
|||
package nginx_vts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
)
|
||||
|
||||
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) {
|
||||
if r.URL.Path != "/status" {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Errorf("Cannot handle request, expected: %q, actual: %q", "/status", r.URL.Path)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header()["Content-Type"] = []string{"application/json"}
|
||||
if _, err := fmt.Fprintln(w, sampleStatusResponse); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
n := &NginxVTS{
|
||||
Urls: []string{ts.URL + "/status"},
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
|
||||
err := n.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
addr, err := url.Parse(ts.URL)
|
||||
require.NoError(t, 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",
|
||||
})
|
||||
}
|
14
plugins/inputs/nginx_vts/sample.conf
Normal file
14
plugins/inputs/nginx_vts/sample.conf
Normal file
|
@ -0,0 +1,14 @@
|
|||
# Read Nginx virtual host traffic status module information (nginx-module-vts)
|
||||
[[inputs.nginx_vts]]
|
||||
## 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"
|
||||
|
||||
## Optional TLS Config
|
||||
# tls_ca = "/etc/telegraf/ca.pem"
|
||||
# tls_cert = "/etc/telegraf/cert.pem"
|
||||
# tls_key = "/etc/telegraf/key.pem"
|
||||
## Use TLS but skip chain & host verification
|
||||
# insecure_skip_verify = false
|
Loading…
Add table
Add a link
Reference in a new issue