diff --git a/plugins/inputs/uwsgi/uwsgi.go b/plugins/inputs/uwsgi/uwsgi.go index 505e29614..5e6f53c10 100644 --- a/plugins/inputs/uwsgi/uwsgi.go +++ b/plugins/inputs/uwsgi/uwsgi.go @@ -1,3 +1,5 @@ +// Package uwsgi implements a telegraf plugin for +// collecting uwsgi stats from the uwsgi stats server. package uwsgi import ( @@ -15,14 +17,53 @@ import ( var timeout = 5 * time.Second +// uWSGI Server struct type Uwsgi struct { Servers []string `toml:"server"` } +// Errors is a list of errors accumulated during an interval. +type Errors []error + +func (errs Errors) Error() string { + s := "" + for _, err := range errs { + if s == "" { + s = err.Error() + } else { + s = s + ". " + err.Error() + } + } + return s +} + +// NestedError wraps an error returned from deeper in the code. +type NestedError struct { + // Err is the error from where the NestedError was constructed. + Err error + // NestedError is the error that was passed back from the called function. + NestedErr error +} + +// Error returns a concatenated string of all the nested errors. +func (ne NestedError) Error() string { + return ne.Err.Error() + ": " + ne.NestedErr.Error() +} + +// Errorf is a convenience function for constructing a NestedError. +func Errorf(err error, msg string, format ...interface{}) error { + return NestedError{ + NestedErr: err, + Err: fmt.Errorf(msg, format...), + } +} + +// Description returns the plugin description func (u *Uwsgi) Description() string { return "Read uWSGI metrics." } +// SampleConfig returns the sample configuration func (u *Uwsgi) SampleConfig() string { return ` ## List with urls of uWSGI Stats servers. Url must match pattern: @@ -34,17 +75,20 @@ func (u *Uwsgi) SampleConfig() string { ` } +// Gather collect data from uWSGI Server func (u *Uwsgi) Gather(acc telegraf.Accumulator) error { + var errs Errors for _, s := range u.Servers { n, err := url.Parse(s) if err != nil { return fmt.Errorf("Could not parse uWSGI Stats Server url '%s': %s", s, err) } - - u.gatherServer(acc, n) + if err := u.gatherServer(acc, n); err != nil { + errs = append(errs, Errorf(err, "server %s", s)) + } } - return nil + return errs } func (u *Uwsgi) gatherServer(acc telegraf.Accumulator, url *url.URL) error { @@ -59,7 +103,7 @@ func (u *Uwsgi) gatherServer(acc telegraf.Accumulator, url *url.URL) error { case "http": resp, err := http.Get(url.String()) if err != nil { - return fmt.Errorf("Could not connect to uWSGI Stats Server '%s': %s", url.String(), err) + return Errorf(err, "Could not connect to uWSGI Stats Server '%s'", url.String()) } r = resp.Body default: @@ -67,7 +111,7 @@ func (u *Uwsgi) gatherServer(acc telegraf.Accumulator, url *url.URL) error { } if err != nil { - return fmt.Errorf("Could not connect to uWSGI Stats Server '%s': %s", url.String(), err) + return Errorf(err, "Could not connect to uWSGI Stats Server '%s'", url.String()) } defer r.Close() @@ -75,11 +119,13 @@ func (u *Uwsgi) gatherServer(acc telegraf.Accumulator, url *url.URL) error { s.Url = url.String() dec := json.NewDecoder(r) - dec.Decode(&s) + if err := dec.Decode(&s); err != nil { + return Errorf(err, "Could not decode json payload from server '%s'", url.String()) + } u.gatherStatServer(acc, &s) - return nil + return err } func (u *Uwsgi) gatherStatServer(acc telegraf.Accumulator, s *StatsServer) { diff --git a/plugins/inputs/uwsgi/uwsgi_test.go b/plugins/inputs/uwsgi/uwsgi_test.go index 9b1eb074e..59052bbe1 100644 --- a/plugins/inputs/uwsgi/uwsgi_test.go +++ b/plugins/inputs/uwsgi/uwsgi_test.go @@ -123,3 +123,57 @@ func TestBasic(t *testing.T) { var acc testutil.Accumulator require.NoError(t, plugin.Gather(&acc)) } + +func TestInvalidJason(t *testing.T) { + js := ` +{ + "version":"2.0.12", + "listen_queue":0, + "listen_queue_errors":0, + "signal_queue":0, + "load":0, + "pid:28372 + "uid":10 +} +` + + fakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/" { + _, _ = w.Write([]byte(js)) + } else { + w.WriteHeader(http.StatusNotFound) + } + })) + + defer fakeServer.Close() + + plugin := &uwsgi.Uwsgi{ + Servers: []string{fakeServer.URL + "/"}, + } + var acc testutil.Accumulator + require.Error(t, plugin.Gather(&acc)) +} + +func TestHttpError(t *testing.T) { + plugin := &uwsgi.Uwsgi{ + Servers: []string{"http://novalidurladress/"}, + } + var acc testutil.Accumulator + require.Error(t, plugin.Gather(&acc)) +} + +func TestTcpError(t *testing.T) { + plugin := &uwsgi.Uwsgi{ + Servers: []string{"tcp://novalidtcpadress/"}, + } + var acc testutil.Accumulator + require.Error(t, plugin.Gather(&acc)) +} + +func TestUnixSocketError(t *testing.T) { + plugin := &uwsgi.Uwsgi{ + Servers: []string{"unix:///novalidunixsocket"}, + } + var acc testutil.Accumulator + require.Error(t, plugin.Gather(&acc)) +}