2016-07-19 23:40:41 +00:00
|
|
|
// Circonus Metrics Sink
|
|
|
|
|
|
|
|
package circonus
|
|
|
|
|
|
|
|
import (
|
|
|
|
"strings"
|
|
|
|
|
2017-08-07 23:37:52 +00:00
|
|
|
"github.com/armon/go-metrics"
|
2016-07-19 23:40:41 +00:00
|
|
|
cgm "github.com/circonus-labs/circonus-gometrics"
|
|
|
|
)
|
|
|
|
|
|
|
|
// CirconusSink provides an interface to forward metrics to Circonus with
|
|
|
|
// automatic check creation and metric management
|
|
|
|
type CirconusSink struct {
|
|
|
|
metrics *cgm.CirconusMetrics
|
|
|
|
}
|
|
|
|
|
|
|
|
// Config options for CirconusSink
|
|
|
|
// See https://github.com/circonus-labs/circonus-gometrics for configuration options
|
|
|
|
type Config cgm.Config
|
|
|
|
|
|
|
|
// NewCirconusSink - create new metric sink for circonus
|
|
|
|
//
|
|
|
|
// one of the following must be supplied:
|
|
|
|
// - API Token - search for an existing check or create a new check
|
|
|
|
// - API Token + Check Id - the check identified by check id will be used
|
|
|
|
// - API Token + Check Submission URL - the check identified by the submission url will be used
|
|
|
|
// - Check Submission URL - the check identified by the submission url will be used
|
|
|
|
// metric management will be *disabled*
|
|
|
|
//
|
|
|
|
// Note: If submission url is supplied w/o an api token, the public circonus ca cert will be used
|
|
|
|
// to verify the broker for metrics submission.
|
|
|
|
func NewCirconusSink(cc *Config) (*CirconusSink, error) {
|
|
|
|
cfg := cgm.Config{}
|
|
|
|
if cc != nil {
|
|
|
|
cfg = cgm.Config(*cc)
|
|
|
|
}
|
|
|
|
|
|
|
|
metrics, err := cgm.NewCirconusMetrics(&cfg)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &CirconusSink{
|
|
|
|
metrics: metrics,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start submitting metrics to Circonus (flush every SubmitInterval)
|
|
|
|
func (s *CirconusSink) Start() {
|
|
|
|
s.metrics.Start()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Flush manually triggers metric submission to Circonus
|
|
|
|
func (s *CirconusSink) Flush() {
|
|
|
|
s.metrics.Flush()
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetGauge sets value for a gauge metric
|
|
|
|
func (s *CirconusSink) SetGauge(key []string, val float32) {
|
|
|
|
flatKey := s.flattenKey(key)
|
|
|
|
s.metrics.SetGauge(flatKey, int64(val))
|
|
|
|
}
|
|
|
|
|
2017-08-07 23:37:52 +00:00
|
|
|
// SetGaugeWithLabels sets value for a gauge metric with the given labels
|
|
|
|
func (s *CirconusSink) SetGaugeWithLabels(key []string, val float32, labels []metrics.Label) {
|
|
|
|
flatKey := s.flattenKeyLabels(key, labels)
|
|
|
|
s.metrics.SetGauge(flatKey, int64(val))
|
|
|
|
}
|
|
|
|
|
2016-07-19 23:40:41 +00:00
|
|
|
// EmitKey is not implemented in circonus
|
|
|
|
func (s *CirconusSink) EmitKey(key []string, val float32) {
|
|
|
|
// NOP
|
|
|
|
}
|
|
|
|
|
|
|
|
// IncrCounter increments a counter metric
|
|
|
|
func (s *CirconusSink) IncrCounter(key []string, val float32) {
|
|
|
|
flatKey := s.flattenKey(key)
|
|
|
|
s.metrics.IncrementByValue(flatKey, uint64(val))
|
|
|
|
}
|
|
|
|
|
2017-08-07 23:37:52 +00:00
|
|
|
// IncrCounterWithLabels increments a counter metric with the given labels
|
|
|
|
func (s *CirconusSink) IncrCounterWithLabels(key []string, val float32, labels []metrics.Label) {
|
|
|
|
flatKey := s.flattenKeyLabels(key, labels)
|
|
|
|
s.metrics.IncrementByValue(flatKey, uint64(val))
|
|
|
|
}
|
|
|
|
|
2016-07-19 23:40:41 +00:00
|
|
|
// AddSample adds a sample to a histogram metric
|
|
|
|
func (s *CirconusSink) AddSample(key []string, val float32) {
|
|
|
|
flatKey := s.flattenKey(key)
|
|
|
|
s.metrics.RecordValue(flatKey, float64(val))
|
|
|
|
}
|
|
|
|
|
2017-08-07 23:37:52 +00:00
|
|
|
// AddSampleWithLabels adds a sample to a histogram metric with the given labels
|
|
|
|
func (s *CirconusSink) AddSampleWithLabels(key []string, val float32, labels []metrics.Label) {
|
|
|
|
flatKey := s.flattenKeyLabels(key, labels)
|
|
|
|
s.metrics.RecordValue(flatKey, float64(val))
|
|
|
|
}
|
|
|
|
|
2016-07-19 23:40:41 +00:00
|
|
|
// Flattens key to Circonus metric name
|
|
|
|
func (s *CirconusSink) flattenKey(parts []string) string {
|
|
|
|
joined := strings.Join(parts, "`")
|
|
|
|
return strings.Map(func(r rune) rune {
|
|
|
|
switch r {
|
|
|
|
case ' ':
|
|
|
|
return '_'
|
|
|
|
default:
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
}, joined)
|
|
|
|
}
|
2017-08-07 23:37:52 +00:00
|
|
|
|
|
|
|
// Flattens the key along with labels for formatting, removes spaces
|
|
|
|
func (s *CirconusSink) flattenKeyLabels(parts []string, labels []metrics.Label) string {
|
|
|
|
for _, label := range labels {
|
|
|
|
parts = append(parts, label.Value)
|
|
|
|
}
|
|
|
|
return s.flattenKey(parts)
|
|
|
|
}
|