-
Notifications
You must be signed in to change notification settings - Fork 5.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added Consul health checks state monitoring.
- Loading branch information
Showing
7 changed files
with
228 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# Telegraf Input Plugin: Consul | ||
|
||
This plugin will collect statistics about all helath checks registered in the Consul. It uses [Consul API](https://www.consul.io/docs/agent/http/health.html#health_state) | ||
to query the data. It will not report the [telemetry](https://www.consul.io/docs/agent/telemetry.html) but Consul can report those stats already using StatsD protocol if needed. | ||
|
||
## Configuration: | ||
|
||
``` | ||
# Gather health check statuses from services registered in Consul | ||
[[inputs.consul]] | ||
## Most of these values defaults to the one configured on a Consul's agent level. | ||
## Optional Consul server address (default: "") | ||
# address = "" | ||
## Optional URI scheme for the Consul server (default: "") | ||
# scheme = "" | ||
## Optional ACL token used in every request (default: "") | ||
# token = "" | ||
## Optional username used for request HTTP Basic Authentication (default: "") | ||
# username = "" | ||
## Optional password used for HTTP Basic Authentication (default: "") | ||
# password = "" | ||
## Optional data centre to query the health checks from (default: "") | ||
# datacentre = "" | ||
``` | ||
|
||
## Measurements: | ||
|
||
### Consul: | ||
Tags: | ||
- node: on which node check/service is registered on | ||
- service_name: name of the service (this is the service name not the service ID) | ||
|
||
Fields: | ||
- check_id | ||
- check_name | ||
- service_id | ||
- status | ||
|
||
## Example output | ||
|
||
``` | ||
$ telegraf --config ./telegraf.conf -input-filter consul -test | ||
* Plugin: consul, Collection 1 | ||
> consul_health_checks,host=wolfpit,node=consul-server-node check_id="serfHealth",check_name="Serf Health Status",service_id="",status="passing" 1464698464486439902 | ||
> consul_health_checks,host=wolfpit,node=consul-server-node,service_name=www.example.com check_id="service:www-example-com.test01",check_name="Service 'www.example.com' check",service_id="www-example-com.test01",status="critical" 1464698464486519036 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
package consul | ||
|
||
import ( | ||
"net/http" | ||
|
||
"github.com/hashicorp/consul/api" | ||
"github.com/influxdata/telegraf" | ||
"github.com/influxdata/telegraf/internal" | ||
"github.com/influxdata/telegraf/plugins/inputs" | ||
) | ||
|
||
type Consul struct { | ||
Address string | ||
Scheme string | ||
Token string | ||
Username string | ||
Password string | ||
Datacentre string | ||
|
||
// Path to CA file | ||
SSLCA string `toml:"ssl_ca"` | ||
// Path to host cert file | ||
SSLCert string `toml:"ssl_cert"` | ||
// Path to cert key file | ||
SSLKey string `toml:"ssl_key"` | ||
// Use SSL but skip chain & host verification | ||
InsecureSkipVerify bool | ||
|
||
// client used to connect to Consul agnet | ||
client *api.Client | ||
} | ||
|
||
var sampleConfig = ` | ||
## Most of these values defaults to the one configured on a Consul's agent level. | ||
## Optional Consul server address (default: "localhost") | ||
# address = "localhost" | ||
## Optional URI scheme for the Consul server (default: "http") | ||
# scheme = "http" | ||
## Optional ACL token used in every request (default: "") | ||
# token = "" | ||
## Optional username used for request HTTP Basic Authentication (default: "") | ||
# username = "" | ||
## Optional password used for HTTP Basic Authentication (default: "") | ||
# password = "" | ||
## Optional data centre to query the health checks from (default: "") | ||
# datacentre = "" | ||
` | ||
|
||
func (c *Consul) Description() string { | ||
return "Gather health check statuses from services registered in Consul" | ||
} | ||
|
||
func (c *Consul) SampleConfig() string { | ||
return sampleConfig | ||
} | ||
|
||
func (c *Consul) createAPIClient() (*api.Client, error) { | ||
config := api.DefaultConfig() | ||
|
||
if c.Address != "" { | ||
config.Address = c.Address | ||
} | ||
|
||
if c.Scheme != "" { | ||
config.Scheme = c.Scheme | ||
} | ||
|
||
if c.Datacentre != "" { | ||
config.Datacenter = c.Datacentre | ||
} | ||
|
||
if c.Username != "" { | ||
config.HttpAuth = &api.HttpBasicAuth{ | ||
Username: c.Username, | ||
Password: c.Password, | ||
} | ||
} | ||
|
||
tlsCfg, err := internal.GetTLSConfig( | ||
c.SSLCert, c.SSLKey, c.SSLCA, c.InsecureSkipVerify) | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
config.HttpClient.Transport = &http.Transport{ | ||
TLSClientConfig: tlsCfg, | ||
} | ||
|
||
return api.NewClient(config) | ||
} | ||
|
||
func (c *Consul) GatherHealthCheck(acc telegraf.Accumulator, checks []*api.HealthCheck) { | ||
for _, check := range checks { | ||
record := make(map[string]interface{}) | ||
tags := make(map[string]string) | ||
|
||
record["check_id"] = check.CheckID | ||
record["check_name"] = check.Name | ||
record["service_id"] = check.ServiceID | ||
record["status"] = check.Status | ||
|
||
tags["node"] = check.Node | ||
tags["service_name"] = check.ServiceName | ||
|
||
acc.AddFields("consul_health_checks", record, tags) | ||
} | ||
} | ||
|
||
func (c *Consul) Gather(acc telegraf.Accumulator) error { | ||
if c.client == nil { | ||
newClient, err := c.createAPIClient() | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
c.client = newClient | ||
} | ||
|
||
checks, _, err := c.client.Health().State("any", nil) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
c.GatherHealthCheck(acc, checks) | ||
|
||
return nil | ||
} | ||
|
||
func init() { | ||
inputs.Add("consul", func() telegraf.Input { | ||
return &Consul{} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package consul | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/hashicorp/consul/api" | ||
"github.com/influxdata/telegraf/testutil" | ||
) | ||
|
||
var sampleChecks = []*api.HealthCheck{ | ||
&api.HealthCheck{ | ||
Node: "localhost", | ||
CheckID: "foo.health123", | ||
Name: "foo.health", | ||
Status: "passing", | ||
Notes: "lorem ipsum", | ||
Output: "OK", | ||
ServiceID: "foo.123", | ||
ServiceName: "foo", | ||
}, | ||
} | ||
|
||
func TestGatherHealtCheck(t *testing.T) { | ||
expectedFields := map[string]interface{}{ | ||
"check_id": "foo.health123", | ||
"check_name": "foo.health", | ||
"status": "passing", | ||
"service_id": "foo.123", | ||
} | ||
|
||
expectedTags := map[string]string{ | ||
"node": "localhost", | ||
"service_name": "foo", | ||
} | ||
|
||
var acc testutil.Accumulator | ||
|
||
consul := &Consul{} | ||
consul.GatherHealthCheck(&acc, sampleChecks) | ||
|
||
acc.AssertContainsTaggedFields(t, "consul_health_checks", expectedFields, expectedTags) | ||
} |