mirror of https://github.com/status-im/consul.git
Add Circonus support for Telemetry metrics
This commit is contained in:
parent
548fb6eb3f
commit
fb76256c26
|
@ -15,6 +15,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/armon/go-metrics"
|
||||
"github.com/armon/go-metrics/circonus"
|
||||
"github.com/armon/go-metrics/datadog"
|
||||
"github.com/hashicorp/consul/lib"
|
||||
"github.com/hashicorp/consul/watch"
|
||||
|
@ -716,6 +717,37 @@ func (c *Command) Run(args []string) int {
|
|||
fanout = append(fanout, sink)
|
||||
}
|
||||
|
||||
if config.Telemetry.CirconusAPIToken != "" || config.Telemetry.CirconusCheckSubmissionURL != "" {
|
||||
cfg := &circonus.Config{}
|
||||
cfg.Interval = config.Telemetry.CirconusSubmitInterval
|
||||
cfg.CheckManager.API.TokenKey = config.Telemetry.CirconusAPIToken
|
||||
cfg.CheckManager.API.TokenApp = config.Telemetry.CirconusAPIApp
|
||||
cfg.CheckManager.API.URL = config.Telemetry.CirconusAPIURL
|
||||
cfg.CheckManager.Check.SubmissionURL = config.Telemetry.CirconusCheckSubmissionURL
|
||||
cfg.CheckManager.Check.ID = config.Telemetry.CirconusCheckID
|
||||
cfg.CheckManager.Check.ForceMetricActivation = config.Telemetry.CirconusCheckForceMetricActivation
|
||||
cfg.CheckManager.Check.InstanceID = config.Telemetry.CirconusCheckInstanceID
|
||||
cfg.CheckManager.Check.SearchTag = config.Telemetry.CirconusCheckSearchTag
|
||||
cfg.CheckManager.Broker.ID = config.Telemetry.CirconusBrokerID
|
||||
cfg.CheckManager.Broker.SelectTag = config.Telemetry.CirconusBrokerSelectTag
|
||||
|
||||
if cfg.CheckManager.Check.InstanceID == "" {
|
||||
cfg.CheckManager.Check.InstanceID = fmt.Sprintf("%s:%s", config.NodeName, config.Datacenter)
|
||||
}
|
||||
|
||||
if cfg.CheckManager.Check.SearchTag == "" {
|
||||
cfg.CheckManager.Check.SearchTag = "service:consul"
|
||||
}
|
||||
|
||||
sink, err := circonus.NewCirconusSink(cfg)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to start Circonus sink. Got: %s", err))
|
||||
return 1
|
||||
}
|
||||
sink.Start()
|
||||
fanout = append(fanout, sink)
|
||||
}
|
||||
|
||||
// Initialize the global sink
|
||||
if len(fanout) > 0 {
|
||||
fanout = append(fanout, inm)
|
||||
|
|
|
@ -130,6 +130,70 @@ type Telemetry struct {
|
|||
// DogStatsdTags are the global tags that should be sent with each packet to dogstatsd
|
||||
// It is a list of strings, where each string looks like "my_tag_name:my_tag_value"
|
||||
DogStatsdTags []string `mapstructure:"dogstatsd_tags"`
|
||||
|
||||
// Circonus: see https://github.com/circonus-labs/circonus-gometrics
|
||||
// for more details on the various configuration options.
|
||||
// Valid configuration combinations:
|
||||
// - CirconusAPIToken
|
||||
// metric management enabled (search for existing check or create a new one)
|
||||
// - CirconusSubmissionUrl
|
||||
// metric management disabled (use check with specified submission_url,
|
||||
// broker must be using a public SSL certificate)
|
||||
// - CirconusAPIToken + CirconusCheckSubmissionURL
|
||||
// metric management enabled (use check with specified submission_url)
|
||||
// - CirconusAPIToken + CirconusCheckID
|
||||
// metric management enabled (use check with specified id)
|
||||
|
||||
// CirconusAPIToken is a valid API Token used to create/manage check. If provided,
|
||||
// metric management is enabled.
|
||||
// Default: none
|
||||
CirconusAPIToken string `mapstructure:"circonus_api_token"`
|
||||
// CirconusAPIApp is an app name associated with API token.
|
||||
// Default: "circonus-gometrics"
|
||||
CirconusAPIApp string `mapstructure:"circonus_api_app"`
|
||||
// CirconusAPIURL is the base URL to use for contacting the Circonus API.
|
||||
// Default: "https://api.circonus.com/v2"
|
||||
CirconusAPIURL string `mapstructure:"circonus_api_url"`
|
||||
// CirconusSubmitInterval is the interval at which metrics are submitted to Circonus.
|
||||
// Default: 10s
|
||||
CirconusSubmitInterval string `mapstructure:"circonus_submission_interval"`
|
||||
// CirconusCheckSubmissionURL is the check.config.submission_url field from a
|
||||
// previously created HTTPTRAP check.
|
||||
// Default: none
|
||||
CirconusCheckSubmissionURL string `mapstructure:"circonus_submission_url"`
|
||||
// CirconusCheckID is the check id (not check bundle id) from a previously created
|
||||
// HTTPTRAP check. The numeric portion of the check._cid field.
|
||||
// Default: none
|
||||
CirconusCheckID string `mapstructure:"circonus_check_id"`
|
||||
// CirconusCheckForceMetricActivation will force enabling metrics, as they are encountered,
|
||||
// if the metric already exists and is NOT active. If check management is enabled, the default
|
||||
// behavior is to add new metrics as they are encoutered. If the metric already exists in the
|
||||
// check, it will *NOT* be activated. This setting overrides that behavior.
|
||||
// Default: "false"
|
||||
CirconusCheckForceMetricActivation string `mapstructure:"circonus_check_force_metric_activation"`
|
||||
// CirconusCheckInstanceID serves to uniquely identify the metrics comming from this "instance".
|
||||
// It can be used to maintain metric continuity with transient or ephemeral instances as
|
||||
// they move around within an infrastructure.
|
||||
// Default: hostname:app
|
||||
CirconusCheckInstanceID string `mapstructure:"circonus_check_instance_id"`
|
||||
// CirconusCheckSearchTag is a special tag which, when coupeled with the instance id, helps to
|
||||
// narrow down the search results when neither a Submission URL or Check ID is provided.
|
||||
// Default: service:app (e.g. service:consul)
|
||||
CirconusCheckSearchTag string `mapstructure:"circonus_check_search_tag"`
|
||||
// CirconusBrokerID is an explicit broker to use when creating a new check. The numeric portion
|
||||
// of broker._cid. If metric management is enabled and neither a Submission URL nor Check ID
|
||||
// is provided, an attempt will be made to search for an existing check using Instance ID and
|
||||
// Search Tag. If one is not found, a new HTTPTRAP check will be created.
|
||||
// Default: use Select Tag if provided, otherwise, a random Enterprise Broker associated
|
||||
// with the specified API token or the default Circonus Broker.
|
||||
// Default: none
|
||||
CirconusBrokerID string `mapstructure:"circonus_broker_id"`
|
||||
// CirconusBrokerSelectTag is a special tag which will be used to select a broker when
|
||||
// a Broker ID is not provided. The best use of this is to as a hint for which broker
|
||||
// should be used based on *where* this particular instance is running.
|
||||
// (e.g. a specific geo location or datacenter, dc:sfo)
|
||||
// Default: none
|
||||
CirconusBrokerSelectTag string `mapstructure:"circonus_broker_search_tag"`
|
||||
}
|
||||
|
||||
// Config is the configuration that can be set for an Agent.
|
||||
|
@ -690,6 +754,47 @@ func DecodeConfig(r io.Reader) (*Config, error) {
|
|||
result.Telemetry.DogStatsdTags[i] = sub[i].(string)
|
||||
}
|
||||
}
|
||||
|
||||
if sub, ok := obj["circonus_api_token"]; ok && result.Telemetry.CirconusAPIToken == "" {
|
||||
result.Telemetry.CirconusAPIToken = sub.(string)
|
||||
}
|
||||
|
||||
if sub, ok := obj["circonus_api_app"]; ok && result.Telemetry.CirconusAPIApp == "" {
|
||||
result.Telemetry.CirconusAPIApp = sub.(string)
|
||||
}
|
||||
|
||||
if sub, ok := obj["circonus_api_url"]; ok && result.Telemetry.CirconusAPIURL == "" {
|
||||
result.Telemetry.CirconusAPIURL = sub.(string)
|
||||
}
|
||||
|
||||
if sub, ok := obj["circonus_submission_url"]; ok && result.Telemetry.CirconusCheckSubmissionURL == "" {
|
||||
result.Telemetry.CirconusCheckSubmissionURL = sub.(string)
|
||||
}
|
||||
|
||||
if sub, ok := obj["circonus_submit_interval"]; ok && result.Telemetry.CirconusSubmitInterval == "" {
|
||||
result.Telemetry.CirconusSubmitInterval = sub.(string)
|
||||
}
|
||||
|
||||
if sub, ok := obj["circonus_check_id"]; ok && result.Telemetry.CirconusCheckID == "" {
|
||||
result.Telemetry.CirconusCheckID = sub.(string)
|
||||
}
|
||||
if sub, ok := obj["circonus_check_force_metric_activation"]; ok && result.Telemetry.CirconusCheckForceMetricActivation == "" {
|
||||
result.Telemetry.CirconusCheckForceMetricActivation = sub.(string)
|
||||
}
|
||||
if sub, ok := obj["circonus_check_instance_id"]; ok && result.Telemetry.CirconusCheckInstanceID == "" {
|
||||
result.Telemetry.CirconusCheckInstanceID = sub.(string)
|
||||
}
|
||||
if sub, ok := obj["circonus_check_search_tag"]; ok && result.Telemetry.CirconusCheckSearchTag == "" {
|
||||
result.Telemetry.CirconusCheckSearchTag = sub.(string)
|
||||
}
|
||||
|
||||
if sub, ok := obj["circonus_broker_id"]; ok && result.Telemetry.CirconusBrokerID == "" {
|
||||
result.Telemetry.CirconusBrokerID = sub.(string)
|
||||
}
|
||||
|
||||
if sub, ok := obj["circonus_broker_select_tag"]; ok && result.Telemetry.CirconusBrokerSelectTag == "" {
|
||||
result.Telemetry.CirconusBrokerSelectTag = sub.(string)
|
||||
}
|
||||
}
|
||||
|
||||
// Decode
|
||||
|
@ -711,7 +816,10 @@ func DecodeConfig(r io.Reader) (*Config, error) {
|
|||
// use mapstructure decoding, so we need to account for those as well.
|
||||
allowedKeys := []string{
|
||||
"service", "services", "check", "checks", "statsd_addr", "statsite_addr", "statsite_prefix",
|
||||
"dogstatsd_addr", "dogstatsd_tags",
|
||||
"dogstatsd_addr", "dogstatsd_tags", "circonus_api_token", "circonus_api_app",
|
||||
"circonus_api_url", "circonus_submission_url", "circonus_submit_interval",
|
||||
"circonus_check_id", "circonus_check_force_metric_activation", "circonus_check_instance_id",
|
||||
"circonus_check_search_tag", "circonus_broker_id", "circonus_broker_select_tag",
|
||||
}
|
||||
|
||||
var unused []string
|
||||
|
@ -1071,6 +1179,39 @@ func MergeConfig(a, b *Config) *Config {
|
|||
if b.Telemetry.DogStatsdTags != nil {
|
||||
result.Telemetry.DogStatsdTags = b.Telemetry.DogStatsdTags
|
||||
}
|
||||
if b.Telemetry.CirconusAPIToken != "" {
|
||||
result.Telemetry.CirconusAPIToken = b.Telemetry.CirconusAPIToken
|
||||
}
|
||||
if b.Telemetry.CirconusAPIApp != "" {
|
||||
result.Telemetry.CirconusAPIApp = b.Telemetry.CirconusAPIApp
|
||||
}
|
||||
if b.Telemetry.CirconusAPIURL != "" {
|
||||
result.Telemetry.CirconusAPIURL = b.Telemetry.CirconusAPIURL
|
||||
}
|
||||
if b.Telemetry.CirconusCheckSubmissionURL != "" {
|
||||
result.Telemetry.CirconusCheckSubmissionURL = b.Telemetry.CirconusCheckSubmissionURL
|
||||
}
|
||||
if b.Telemetry.CirconusSubmitInterval != "" {
|
||||
result.Telemetry.CirconusSubmitInterval = b.Telemetry.CirconusSubmitInterval
|
||||
}
|
||||
if b.Telemetry.CirconusCheckID != "" {
|
||||
result.Telemetry.CirconusCheckID = b.Telemetry.CirconusCheckID
|
||||
}
|
||||
if b.Telemetry.CirconusCheckForceMetricActivation != "" {
|
||||
result.Telemetry.CirconusCheckForceMetricActivation = b.Telemetry.CirconusCheckForceMetricActivation
|
||||
}
|
||||
if b.Telemetry.CirconusCheckInstanceID != "" {
|
||||
result.Telemetry.CirconusCheckInstanceID = b.Telemetry.CirconusCheckInstanceID
|
||||
}
|
||||
if b.Telemetry.CirconusCheckSearchTag != "" {
|
||||
result.Telemetry.CirconusCheckSearchTag = b.Telemetry.CirconusCheckSearchTag
|
||||
}
|
||||
if b.Telemetry.CirconusBrokerID != "" {
|
||||
result.Telemetry.CirconusBrokerID = b.Telemetry.CirconusBrokerID
|
||||
}
|
||||
if b.Telemetry.CirconusBrokerSelectTag != "" {
|
||||
result.Telemetry.CirconusBrokerSelectTag = b.Telemetry.CirconusBrokerSelectTag
|
||||
}
|
||||
if b.EnableDebug {
|
||||
result.EnableDebug = true
|
||||
}
|
||||
|
|
|
@ -725,6 +725,51 @@ func TestDecodeConfig(t *testing.T) {
|
|||
t.Fatalf("bad: %#v", config)
|
||||
}
|
||||
|
||||
// Circonus settings
|
||||
input = `{"circonus_api_token": "12345678-1234-1234-12345678", "circonus_api_app": "testApp",
|
||||
"circonus_api_url": "https://api.host.foo/v2", "circonus_submit_interval": "15s",
|
||||
"circonus_submission_url": "https://submit.host.bar:123/one/two/three",
|
||||
"circonus_check_id": "12345", "circonus_check_force_metric_activation": "true",
|
||||
"circonus_check_instance_id": "a:b", "circonus_check_search_tag": "c:d",
|
||||
"circonus_broker_id": "6789", "circonus_broker_select_tag": "e:f"}`
|
||||
config, err = DecodeConfig(bytes.NewReader([]byte(input)))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if config.Telemetry.CirconusAPIToken != "12345678-1234-1234-12345678" {
|
||||
t.Fatalf("bad: %#v", config)
|
||||
}
|
||||
if config.Telemetry.CirconusAPIApp != "testApp" {
|
||||
t.Fatalf("bad: %#v", config)
|
||||
}
|
||||
if config.Telemetry.CirconusAPIURL != "https://api.host.foo/v2" {
|
||||
t.Fatalf("bad: %#v", config)
|
||||
}
|
||||
if config.Telemetry.CirconusSubmitInterval != "15s" {
|
||||
t.Fatalf("bad: %#v", config)
|
||||
}
|
||||
if config.Telemetry.CirconusCheckSubmissionURL != "https://submit.host.bar:123/one/two/three" {
|
||||
t.Fatalf("bad: %#v", config)
|
||||
}
|
||||
if config.Telemetry.CirconusCheckID != "12345" {
|
||||
t.Fatalf("bad: %#v", config)
|
||||
}
|
||||
if config.Telemetry.CirconusCheckForceMetricActivation != "true" {
|
||||
t.Fatalf("bad: %#v", config)
|
||||
}
|
||||
if config.Telemetry.CirconusCheckInstanceID != "a:b" {
|
||||
t.Fatalf("bad: %#v", config)
|
||||
}
|
||||
if config.Telemetry.CirconusCheckSearchTag != "c:d" {
|
||||
t.Fatalf("bad: %#v", config)
|
||||
}
|
||||
if config.Telemetry.CirconusBrokerID != "6789" {
|
||||
t.Fatalf("bad: %#v", config)
|
||||
}
|
||||
if config.Telemetry.CirconusBrokerSelectTag != "e:f" {
|
||||
t.Fatalf("bad: %#v", config)
|
||||
}
|
||||
|
||||
// New telemetry
|
||||
input = `{"telemetry": { "statsite_prefix": "my_prefix", "statsite_address": "127.0.0.1:7250", "statsd_address":"127.0.0.1:7251", "disable_hostname": true, "dogstatsd_addr": "1.1.1.1:111", "dogstatsd_tags": [ "tag_1:val_1" ] } }`
|
||||
config, err = DecodeConfig(bytes.NewReader([]byte(input)))
|
||||
|
|
Loading…
Reference in New Issue