package consul import ( "net/http" "strings" "github.com/hashicorp/consul/api" "github.com/influxdata/telegraf" "github.com/influxdata/telegraf/internal/tls" "github.com/influxdata/telegraf/plugins/inputs" ) type Consul struct { Address string Scheme string Token string Username string Password string Datacentre string // deprecated in 1.10; use Datacenter Datacenter string tls.ClientConfig TagDelimiter string // client used to connect to Consul agnet client *api.Client } var sampleConfig = ` ## Consul server address # address = "localhost" ## URI scheme for the Consul server, one of "http", "https" # scheme = "http" ## ACL token used in every request # token = "" ## HTTP Basic Authentication username and password. # username = "" # password = "" ## Data center to query the health checks from # datacenter = "" ## 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 = true ## Consul checks' tag splitting # When tags are formatted like "key:value" with ":" as a delimiter then # they will be splitted and reported as proper key:value in Telegraf # tag_delimiter = ":" ` 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.Datacenter != "" { config.Datacenter = c.Datacenter } if c.Token != "" { config.Token = c.Token } if c.Username != "" { config.HttpAuth = &api.HttpBasicAuth{ Username: c.Username, Password: c.Password, } } tlsCfg, err := c.ClientConfig.TLSConfig() if err != nil { return nil, err } config.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_name"] = check.Name record["service_id"] = check.ServiceID record["status"] = check.Status record["passing"] = 0 record["critical"] = 0 record["warning"] = 0 record[check.Status] = 1 tags["node"] = check.Node tags["service_name"] = check.ServiceName tags["check_id"] = check.CheckID for _, checkTag := range check.ServiceTags { if c.TagDelimiter != "" { splittedTag := strings.SplitN(checkTag, c.TagDelimiter, 2) if len(splittedTag) == 1 { tags[checkTag] = checkTag } else if len(splittedTag) == 2 { tags[splittedTag[0]] = splittedTag[1] } } else { tags[checkTag] = checkTag } } 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{} }) }