github.com/hashicorp/go-metrics@v0.5.3/circonus/circonus.go (about)

     1  // Circonus Metrics Sink
     2  
     3  package circonus
     4  
     5  import (
     6  	"strings"
     7  
     8  	cgm "github.com/circonus-labs/circonus-gometrics"
     9  	"github.com/hashicorp/go-metrics"
    10  )
    11  
    12  // CirconusSink provides an interface to forward metrics to Circonus with
    13  // automatic check creation and metric management
    14  type CirconusSink struct {
    15  	metrics *cgm.CirconusMetrics
    16  }
    17  
    18  // Config options for CirconusSink
    19  // See https://github.com/circonus-labs/circonus-gometrics for configuration options
    20  type Config cgm.Config
    21  
    22  // NewCirconusSink - create new metric sink for circonus
    23  //
    24  // one of the following must be supplied:
    25  //   - API Token - search for an existing check or create a new check
    26  //   - API Token + Check Id - the check identified by check id will be used
    27  //   - API Token + Check Submission URL - the check identified by the submission url will be used
    28  //   - Check Submission URL - the check identified by the submission url will be used
    29  //     metric management will be *disabled*
    30  //
    31  // Note: If submission url is supplied w/o an api token, the public circonus ca cert will be used
    32  // to verify the broker for metrics submission.
    33  func NewCirconusSink(cc *Config) (*CirconusSink, error) {
    34  	cfg := cgm.Config{}
    35  	if cc != nil {
    36  		cfg = cgm.Config(*cc)
    37  	}
    38  
    39  	metrics, err := cgm.NewCirconusMetrics(&cfg)
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  
    44  	return &CirconusSink{
    45  		metrics: metrics,
    46  	}, nil
    47  }
    48  
    49  // Start submitting metrics to Circonus (flush every SubmitInterval)
    50  func (s *CirconusSink) Start() {
    51  	s.metrics.Start()
    52  }
    53  
    54  // Flush manually triggers metric submission to Circonus
    55  func (s *CirconusSink) Flush() {
    56  	s.metrics.Flush()
    57  }
    58  
    59  // SetGauge sets value for a gauge metric
    60  func (s *CirconusSink) SetGauge(key []string, val float32) {
    61  	flatKey := s.flattenKey(key)
    62  	s.metrics.SetGauge(flatKey, int64(val))
    63  }
    64  
    65  // SetGaugeWithLabels sets value for a gauge metric with the given labels
    66  func (s *CirconusSink) SetGaugeWithLabels(key []string, val float32, labels []metrics.Label) {
    67  	flatKey := s.flattenKeyLabels(key, labels)
    68  	s.metrics.SetGauge(flatKey, int64(val))
    69  }
    70  
    71  // SetPrecisionGauge sets value for a gauge metric with float64 precision
    72  func (s *CirconusSink) SetPrecisionGauge(key []string, val float64) {
    73  	flatKey := s.flattenKey(key)
    74  	s.metrics.SetGauge(flatKey, val)
    75  }
    76  
    77  // SetPrecisionGaugeWithLabels sets value for a gauge metric with the given labels with float64 precision
    78  func (s *CirconusSink) SetPrecisionGaugeWithLabels(key []string, val float64, labels []metrics.Label) {
    79  	flatKey := s.flattenKeyLabels(key, labels)
    80  	s.metrics.SetGauge(flatKey, val)
    81  }
    82  
    83  // EmitKey is not implemented in circonus
    84  func (s *CirconusSink) EmitKey(key []string, val float32) {
    85  	// NOP
    86  }
    87  
    88  // IncrCounter increments a counter metric
    89  func (s *CirconusSink) IncrCounter(key []string, val float32) {
    90  	flatKey := s.flattenKey(key)
    91  	s.metrics.IncrementByValue(flatKey, uint64(val))
    92  }
    93  
    94  // IncrCounterWithLabels increments a counter metric with the given labels
    95  func (s *CirconusSink) IncrCounterWithLabels(key []string, val float32, labels []metrics.Label) {
    96  	flatKey := s.flattenKeyLabels(key, labels)
    97  	s.metrics.IncrementByValue(flatKey, uint64(val))
    98  }
    99  
   100  // AddSample adds a sample to a histogram metric
   101  func (s *CirconusSink) AddSample(key []string, val float32) {
   102  	flatKey := s.flattenKey(key)
   103  	s.metrics.RecordValue(flatKey, float64(val))
   104  }
   105  
   106  // AddSampleWithLabels adds a sample to a histogram metric with the given labels
   107  func (s *CirconusSink) AddSampleWithLabels(key []string, val float32, labels []metrics.Label) {
   108  	flatKey := s.flattenKeyLabels(key, labels)
   109  	s.metrics.RecordValue(flatKey, float64(val))
   110  }
   111  
   112  // Shutdown blocks while flushing metrics to the backend.
   113  func (s *CirconusSink) Shutdown() {
   114  	// The version of circonus metrics in go.mod (v2.3.1), and the current
   115  	// version (v3.4.6) do not support a shutdown operation. Instead we call
   116  	// Flush which blocks until metrics are submitted to storage, and then exit
   117  	// as the README examples do.
   118  	s.metrics.Flush()
   119  }
   120  
   121  // Flattens key to Circonus metric name
   122  func (s *CirconusSink) flattenKey(parts []string) string {
   123  	joined := strings.Join(parts, "`")
   124  	return strings.Map(func(r rune) rune {
   125  		switch r {
   126  		case ' ':
   127  			return '_'
   128  		default:
   129  			return r
   130  		}
   131  	}, joined)
   132  }
   133  
   134  // Flattens the key along with labels for formatting, removes spaces
   135  func (s *CirconusSink) flattenKeyLabels(parts []string, labels []metrics.Label) string {
   136  	for _, label := range labels {
   137  		parts = append(parts, label.Value)
   138  	}
   139  	return s.flattenKey(parts)
   140  }