-
Notifications
You must be signed in to change notification settings - Fork 5.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NATS Monitoring Input Plugin #3186
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# NATS Monitoring Input Plugin | ||
|
||
The [NATS](http://www.nats.io/about/) monitoring plugin reads from | ||
specified NATS instance and submits metrics to InfluxDB. | ||
|
||
## Configuration | ||
|
||
```toml | ||
[[inputs.nats]] | ||
## The address of the monitoring end-point of the NATS server | ||
server = "http://localhost:8222" | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package nats | ||
|
||
import ( | ||
"fmt" | ||
"io/ioutil" | ||
"net/http" | ||
"time" | ||
|
||
"encoding/json" | ||
|
||
"github.com/influxdata/telegraf" | ||
"github.com/influxdata/telegraf/plugins/inputs" | ||
|
||
gnatsd "github.com/nats-io/gnatsd/server" | ||
) | ||
|
||
type Nats struct { | ||
Server string | ||
} | ||
|
||
var sampleConfig = ` | ||
## The address of the monitoring end-point of the NATS server | ||
server = "http://localhost:1337" | ||
` | ||
|
||
func (n *Nats) SampleConfig() string { | ||
return sampleConfig | ||
} | ||
|
||
func (n *Nats) Description() string { | ||
return "Provides metrics about the state of a NATS server" | ||
} | ||
|
||
func (n *Nats) Gather(acc telegraf.Accumulator) error { | ||
theServer := fmt.Sprintf("%s/varz", n.Server) | ||
|
||
/* download the page we are intereted in */ | ||
resp, err := http.Get(theServer) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add in a custom transport for this plugin? The best example to follow is the apache input. You don't have to add SSL support or user configurable timeouts, but make sure there is a timeout on the http.Client of 5 seconds. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done (exposed the timeout as an option too) |
||
if err != nil { | ||
return err | ||
} | ||
defer resp.Body.Close() | ||
|
||
bytes, err := ioutil.ReadAll(resp.Body) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
var stats = new(gnatsd.Varz) | ||
|
||
err = json.Unmarshal([]byte(bytes), &stats) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
acc.AddFields("nats", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we call the measurement There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not add in the missing numeric values from the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good idea: slow_consumers, routes, cores, and remotes added. None of the other fields in |
||
map[string]interface{}{ | ||
"in_msgs": stats.InMsgs, | ||
"out_msgs": stats.OutMsgs, | ||
"uptime": time.Since(stats.Start).Seconds(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's store this in nanoseconds There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. I've also made this more correct by using |
||
"connections": stats.Connections, | ||
"total_connections": stats.TotalConnections, | ||
"in_bytes": stats.InBytes, | ||
"cpu_usage": stats.CPU, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't this the number of cpu's used? If so I would call it either There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
"out_bytes": stats.OutBytes, | ||
"mem": stats.Mem, | ||
"subscriptions": stats.Subscriptions, | ||
}, nil, time.Now()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a tag for the server using the url in the configuration, this will allow the plugin to be used multiple times if needed without conflicts. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
|
||
return nil | ||
} | ||
|
||
func init() { | ||
inputs.Add("nats", func() telegraf.Input { | ||
return &Nats{ | ||
Server: "http://localhost:8222", | ||
} | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
package nats | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
|
||
"github.com/influxdata/telegraf/testutil" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
var sampleVarz = ` | ||
{ | ||
"server_id": "n2afhLHLl64Gcaj7S7jaNa", | ||
"version": "1.0.0", | ||
"go": "go1.8", | ||
"host": "0.0.0.0", | ||
"auth_required": false, | ||
"ssl_required": false, | ||
"tls_required": false, | ||
"tls_verify": false, | ||
"addr": "0.0.0.0", | ||
"max_connections": 65536, | ||
"ping_interval": 120000000000, | ||
"ping_max": 2, | ||
"http_host": "0.0.0.0", | ||
"http_port": 1337, | ||
"https_port": 0, | ||
"auth_timeout": 1, | ||
"max_control_line": 1024, | ||
"cluster": { | ||
"addr": "0.0.0.0", | ||
"cluster_port": 0, | ||
"auth_timeout": 1 | ||
}, | ||
"tls_timeout": 0.5, | ||
"port": 4222, | ||
"max_payload": 1048576, | ||
"start": "1861-04-12T10:15:26.841483489-05:00", | ||
"now": "2011-10-05T15:24:23.722084098-07:00", | ||
"uptime": "150y5md237h8m57s", | ||
"mem": 15581184, | ||
"cores": 48, | ||
"cpu": 9, | ||
"connections": 2, | ||
"total_connections": 109, | ||
"routes": 0, | ||
"remotes": 0, | ||
"in_msgs": 74148556, | ||
"out_msgs": 68863261, | ||
"in_bytes": 946267004717, | ||
"out_bytes": 948110960598, | ||
"slow_consumers": 0, | ||
"subscriptions": 1, | ||
"http_req_stats": { | ||
"/": 1, | ||
"/connz": 100847, | ||
"/routez": 0, | ||
"/subsz": 1, | ||
"/varz": 205785 | ||
}, | ||
"config_load_time": "2017-07-24T10:15:26.841483489-05:00" | ||
} | ||
` | ||
|
||
func TestMetricsCorrect(t *testing.T) { | ||
var acc testutil.Accumulator | ||
|
||
srv := newTestNatsServer() | ||
defer srv.Close() | ||
|
||
n := &Nats{Server: srv.URL} | ||
err := n.Gather(&acc) | ||
require.NoError(t, err) | ||
|
||
/* | ||
* we get the measurement, and override it, this is neccessary | ||
* because we can't "equal" the uptime value reliably, as it is | ||
* calculated via Time.Now() and the Start value in Varz | ||
*/ | ||
s, f := acc.Get("nats") | ||
assert.Equal(t, true, f, "nats measurement must be found") | ||
|
||
fields := make(map[string]interface{}) | ||
fields["uptime"] = s.Fields["uptime"] | ||
fields["in_msgs"] = int64(74148556) | ||
fields["out_msgs"] = int64(68863261) | ||
fields["connections"] = int(2) | ||
fields["total_connections"] = uint64(109) | ||
fields["in_bytes"] = int64(946267004717) | ||
fields["out_bytes"] = int64(948110960598) | ||
fields["cpu_usage"] = float64(9) | ||
fields["mem"] = int64(15581184) | ||
fields["subscriptions"] = uint32(1) | ||
|
||
acc.AssertContainsFields(t, "nats", fields) | ||
} | ||
|
||
func newTestNatsServer() *httptest.Server { | ||
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
var rsp string | ||
|
||
switch r.URL.Path { | ||
case "/varz": | ||
rsp = sampleVarz | ||
default: | ||
panic("Cannot handle request") | ||
} | ||
|
||
fmt.Fprintln(w, rsp) | ||
})) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you also add this to
docs/LICENSE_OF_DEPENDENCIES.md
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done