Skip 404 error reporting in nginx_plus_api input (#6015)
This commit is contained in:
parent
8d04cb76fd
commit
104db7c503
|
@ -2,6 +2,7 @@ package nginx_plus_api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
|
@ -13,16 +14,33 @@ import (
|
||||||
"github.com/influxdata/telegraf"
|
"github.com/influxdata/telegraf"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// errNotFound signals that the NGINX API routes does not exist.
|
||||||
|
errNotFound = errors.New("not found")
|
||||||
|
)
|
||||||
|
|
||||||
func (n *NginxPlusApi) gatherMetrics(addr *url.URL, acc telegraf.Accumulator) {
|
func (n *NginxPlusApi) gatherMetrics(addr *url.URL, acc telegraf.Accumulator) {
|
||||||
acc.AddError(n.gatherProcessesMetrics(addr, acc))
|
addError(acc, n.gatherProcessesMetrics(addr, acc))
|
||||||
acc.AddError(n.gatherConnectionsMetrics(addr, acc))
|
addError(acc, n.gatherConnectionsMetrics(addr, acc))
|
||||||
acc.AddError(n.gatherSslMetrics(addr, acc))
|
addError(acc, n.gatherSslMetrics(addr, acc))
|
||||||
acc.AddError(n.gatherHttpRequestsMetrics(addr, acc))
|
addError(acc, n.gatherHttpRequestsMetrics(addr, acc))
|
||||||
acc.AddError(n.gatherHttpServerZonesMetrics(addr, acc))
|
addError(acc, n.gatherHttpServerZonesMetrics(addr, acc))
|
||||||
acc.AddError(n.gatherHttpUpstreamsMetrics(addr, acc))
|
addError(acc, n.gatherHttpUpstreamsMetrics(addr, acc))
|
||||||
acc.AddError(n.gatherHttpCachesMetrics(addr, acc))
|
addError(acc, n.gatherHttpCachesMetrics(addr, acc))
|
||||||
acc.AddError(n.gatherStreamServerZonesMetrics(addr, acc))
|
addError(acc, n.gatherStreamServerZonesMetrics(addr, acc))
|
||||||
acc.AddError(n.gatherStreamUpstreamsMetrics(addr, acc))
|
addError(acc, n.gatherStreamUpstreamsMetrics(addr, acc))
|
||||||
|
}
|
||||||
|
|
||||||
|
func addError(acc telegraf.Accumulator, err error) {
|
||||||
|
// This plugin has hardcoded API resource paths it checks that may not
|
||||||
|
// be in the nginx.conf. Currently, this is to prevent logging of
|
||||||
|
// paths that are not configured.
|
||||||
|
//
|
||||||
|
// The correct solution is to do a GET to /api to get the available paths
|
||||||
|
// on the server rather than simply ignore.
|
||||||
|
if err != errNotFound {
|
||||||
|
acc.AddError(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NginxPlusApi) gatherUrl(addr *url.URL, path string) ([]byte, error) {
|
func (n *NginxPlusApi) gatherUrl(addr *url.URL, path string) ([]byte, error) {
|
||||||
|
@ -33,9 +51,17 @@ func (n *NginxPlusApi) gatherUrl(addr *url.URL, path string) ([]byte, error) {
|
||||||
return nil, fmt.Errorf("error making HTTP request to %s: %s", url, err)
|
return nil, fmt.Errorf("error making HTTP request to %s: %s", url, err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
|
switch resp.StatusCode {
|
||||||
|
case http.StatusOK:
|
||||||
|
case http.StatusNotFound:
|
||||||
|
// format as special error to catch and ignore as some nginx API
|
||||||
|
// features are either optional, or only available in some versions
|
||||||
|
return nil, errNotFound
|
||||||
|
default:
|
||||||
return nil, fmt.Errorf("%s returned HTTP status %s", url, resp.Status)
|
return nil, fmt.Errorf("%s returned HTTP status %s", url, resp.Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
contentType := strings.Split(resp.Header.Get("Content-Type"), ";")[0]
|
contentType := strings.Split(resp.Header.Get("Content-Type"), ";")[0]
|
||||||
switch contentType {
|
switch contentType {
|
||||||
case "application/json":
|
case "application/json":
|
||||||
|
|
|
@ -448,11 +448,11 @@ const streamServerZonesPayload = `
|
||||||
`
|
`
|
||||||
|
|
||||||
func TestGatherProcessesMetrics(t *testing.T) {
|
func TestGatherProcessesMetrics(t *testing.T) {
|
||||||
ts, n := prepareEndpoint(processesPath, defaultApiVersion, processesPayload)
|
ts, n := prepareEndpoint(t, processesPath, defaultApiVersion, processesPayload)
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
var acc testutil.Accumulator
|
var acc testutil.Accumulator
|
||||||
addr, host, port := prepareAddr(ts)
|
addr, host, port := prepareAddr(t, ts)
|
||||||
|
|
||||||
require.NoError(t, n.gatherProcessesMetrics(addr, &acc))
|
require.NoError(t, n.gatherProcessesMetrics(addr, &acc))
|
||||||
|
|
||||||
|
@ -468,12 +468,12 @@ func TestGatherProcessesMetrics(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGatherConnectioinsMetrics(t *testing.T) {
|
func TestGatherConnectionsMetrics(t *testing.T) {
|
||||||
ts, n := prepareEndpoint(connectionsPath, defaultApiVersion, connectionsPayload)
|
ts, n := prepareEndpoint(t, connectionsPath, defaultApiVersion, connectionsPayload)
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
var acc testutil.Accumulator
|
var acc testutil.Accumulator
|
||||||
addr, host, port := prepareAddr(ts)
|
addr, host, port := prepareAddr(t, ts)
|
||||||
|
|
||||||
require.NoError(t, n.gatherConnectionsMetrics(addr, &acc))
|
require.NoError(t, n.gatherConnectionsMetrics(addr, &acc))
|
||||||
|
|
||||||
|
@ -493,11 +493,11 @@ func TestGatherConnectioinsMetrics(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGatherSslMetrics(t *testing.T) {
|
func TestGatherSslMetrics(t *testing.T) {
|
||||||
ts, n := prepareEndpoint(sslPath, defaultApiVersion, sslPayload)
|
ts, n := prepareEndpoint(t, sslPath, defaultApiVersion, sslPayload)
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
var acc testutil.Accumulator
|
var acc testutil.Accumulator
|
||||||
addr, host, port := prepareAddr(ts)
|
addr, host, port := prepareAddr(t, ts)
|
||||||
|
|
||||||
require.NoError(t, n.gatherSslMetrics(addr, &acc))
|
require.NoError(t, n.gatherSslMetrics(addr, &acc))
|
||||||
|
|
||||||
|
@ -516,11 +516,11 @@ func TestGatherSslMetrics(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGatherHttpRequestsMetrics(t *testing.T) {
|
func TestGatherHttpRequestsMetrics(t *testing.T) {
|
||||||
ts, n := prepareEndpoint(httpRequestsPath, defaultApiVersion, httpRequestsPayload)
|
ts, n := prepareEndpoint(t, httpRequestsPath, defaultApiVersion, httpRequestsPayload)
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
var acc testutil.Accumulator
|
var acc testutil.Accumulator
|
||||||
addr, host, port := prepareAddr(ts)
|
addr, host, port := prepareAddr(t, ts)
|
||||||
|
|
||||||
require.NoError(t, n.gatherHttpRequestsMetrics(addr, &acc))
|
require.NoError(t, n.gatherHttpRequestsMetrics(addr, &acc))
|
||||||
|
|
||||||
|
@ -538,11 +538,11 @@ func TestGatherHttpRequestsMetrics(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGatherHttpServerZonesMetrics(t *testing.T) {
|
func TestGatherHttpServerZonesMetrics(t *testing.T) {
|
||||||
ts, n := prepareEndpoint(httpServerZonesPath, defaultApiVersion, httpServerZonesPayload)
|
ts, n := prepareEndpoint(t, httpServerZonesPath, defaultApiVersion, httpServerZonesPayload)
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
var acc testutil.Accumulator
|
var acc testutil.Accumulator
|
||||||
addr, host, port := prepareAddr(ts)
|
addr, host, port := prepareAddr(t, ts)
|
||||||
|
|
||||||
require.NoError(t, n.gatherHttpServerZonesMetrics(addr, &acc))
|
require.NoError(t, n.gatherHttpServerZonesMetrics(addr, &acc))
|
||||||
|
|
||||||
|
@ -592,11 +592,11 @@ func TestGatherHttpServerZonesMetrics(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHatherHttpUpstreamsMetrics(t *testing.T) {
|
func TestHatherHttpUpstreamsMetrics(t *testing.T) {
|
||||||
ts, n := prepareEndpoint(httpUpstreamsPath, defaultApiVersion, httpUpstreamsPayload)
|
ts, n := prepareEndpoint(t, httpUpstreamsPath, defaultApiVersion, httpUpstreamsPayload)
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
var acc testutil.Accumulator
|
var acc testutil.Accumulator
|
||||||
addr, host, port := prepareAddr(ts)
|
addr, host, port := prepareAddr(t, ts)
|
||||||
|
|
||||||
require.NoError(t, n.gatherHttpUpstreamsMetrics(addr, &acc))
|
require.NoError(t, n.gatherHttpUpstreamsMetrics(addr, &acc))
|
||||||
|
|
||||||
|
@ -764,11 +764,11 @@ func TestHatherHttpUpstreamsMetrics(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGatherHttpCachesMetrics(t *testing.T) {
|
func TestGatherHttpCachesMetrics(t *testing.T) {
|
||||||
ts, n := prepareEndpoint(httpCachesPath, defaultApiVersion, httpCachesPayload)
|
ts, n := prepareEndpoint(t, httpCachesPath, defaultApiVersion, httpCachesPayload)
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
var acc testutil.Accumulator
|
var acc testutil.Accumulator
|
||||||
addr, host, port := prepareAddr(ts)
|
addr, host, port := prepareAddr(t, ts)
|
||||||
|
|
||||||
require.NoError(t, n.gatherHttpCachesMetrics(addr, &acc))
|
require.NoError(t, n.gatherHttpCachesMetrics(addr, &acc))
|
||||||
|
|
||||||
|
@ -842,11 +842,11 @@ func TestGatherHttpCachesMetrics(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGatherStreamUpstreams(t *testing.T) {
|
func TestGatherStreamUpstreams(t *testing.T) {
|
||||||
ts, n := prepareEndpoint(streamUpstreamsPath, defaultApiVersion, streamUpstreamsPayload)
|
ts, n := prepareEndpoint(t, streamUpstreamsPath, defaultApiVersion, streamUpstreamsPayload)
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
var acc testutil.Accumulator
|
var acc testutil.Accumulator
|
||||||
addr, host, port := prepareAddr(ts)
|
addr, host, port := prepareAddr(t, ts)
|
||||||
|
|
||||||
require.NoError(t, n.gatherStreamUpstreamsMetrics(addr, &acc))
|
require.NoError(t, n.gatherStreamUpstreamsMetrics(addr, &acc))
|
||||||
|
|
||||||
|
@ -984,12 +984,12 @@ func TestGatherStreamUpstreams(t *testing.T) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGatherStreamServerZonesMatrics(t *testing.T) {
|
func TestGatherStreamServerZonesMetrics(t *testing.T) {
|
||||||
ts, n := prepareEndpoint(streamServerZonesPath, defaultApiVersion, streamServerZonesPayload)
|
ts, n := prepareEndpoint(t, streamServerZonesPath, defaultApiVersion, streamServerZonesPayload)
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
var acc testutil.Accumulator
|
var acc testutil.Accumulator
|
||||||
addr, host, port := prepareAddr(ts)
|
addr, host, port := prepareAddr(t, ts)
|
||||||
|
|
||||||
require.NoError(t, n.gatherStreamServerZonesMetrics(addr, &acc))
|
require.NoError(t, n.gatherStreamServerZonesMetrics(addr, &acc))
|
||||||
|
|
||||||
|
@ -1023,11 +1023,92 @@ func TestGatherStreamServerZonesMatrics(t *testing.T) {
|
||||||
"zone": "dns",
|
"zone": "dns",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
func TestUnavailableEndpoints(t *testing.T) {
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusNotFound)
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
func prepareAddr(ts *httptest.Server) (*url.URL, string, string) {
|
n := &NginxPlusApi{
|
||||||
|
client: ts.Client(),
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err := url.Parse(ts.URL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var acc testutil.Accumulator
|
||||||
|
n.gatherMetrics(addr, &acc)
|
||||||
|
require.NoError(t, acc.FirstError())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServerError(t *testing.T) {
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
n := &NginxPlusApi{
|
||||||
|
client: ts.Client(),
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err := url.Parse(ts.URL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var acc testutil.Accumulator
|
||||||
|
n.gatherMetrics(addr, &acc)
|
||||||
|
require.Error(t, acc.FirstError())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMalformedJSON(t *testing.T) {
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
|
fmt.Fprintln(w, "this is not JSON")
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
n := &NginxPlusApi{
|
||||||
|
client: ts.Client(),
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err := url.Parse(ts.URL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var acc testutil.Accumulator
|
||||||
|
n.gatherMetrics(addr, &acc)
|
||||||
|
require.Error(t, acc.FirstError())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnknownContentType(t *testing.T) {
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "text/plain")
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
n := &NginxPlusApi{
|
||||||
|
client: ts.Client(),
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err := url.Parse(ts.URL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var acc testutil.Accumulator
|
||||||
|
n.gatherMetrics(addr, &acc)
|
||||||
|
require.Error(t, acc.FirstError())
|
||||||
|
}
|
||||||
|
|
||||||
|
func prepareAddr(t *testing.T, ts *httptest.Server) (*url.URL, string, string) {
|
||||||
|
t.Helper()
|
||||||
addr, err := url.Parse(fmt.Sprintf("%s/api", ts.URL))
|
addr, err := url.Parse(fmt.Sprintf("%s/api", ts.URL))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
host, port, err := net.SplitHostPort(addr.Host)
|
host, port, err := net.SplitHostPort(addr.Host)
|
||||||
|
@ -1046,7 +1127,7 @@ func prepareAddr(ts *httptest.Server) (*url.URL, string, string) {
|
||||||
return addr, host, port
|
return addr, host, port
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareEndpoint(path string, apiVersion int64, payload string) (*httptest.Server, *NginxPlusApi) {
|
func prepareEndpoint(t *testing.T, path string, apiVersion int64, payload string) (*httptest.Server, *NginxPlusApi) {
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
var rsp string
|
var rsp string
|
||||||
|
|
||||||
|
@ -1054,7 +1135,7 @@ func prepareEndpoint(path string, apiVersion int64, payload string) (*httptest.S
|
||||||
rsp = payload
|
rsp = payload
|
||||||
w.Header()["Content-Type"] = []string{"application/json"}
|
w.Header()["Content-Type"] = []string{"application/json"}
|
||||||
} else {
|
} else {
|
||||||
panic("Cannot handle request")
|
t.Errorf("unknown request path")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintln(w, rsp)
|
fmt.Fprintln(w, rsp)
|
||||||
|
@ -1067,7 +1148,7 @@ func prepareEndpoint(path string, apiVersion int64, payload string) (*httptest.S
|
||||||
|
|
||||||
client, err := n.createHttpClient()
|
client, err := n.createHttpClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
n.client = client
|
n.client = client
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue