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

     1  package metrics
     2  
     3  import (
     4  	"fmt"
     5  	"net/url"
     6  )
     7  
     8  // The MetricSink interface is used to transmit metrics information
     9  // to an external system
    10  type MetricSink interface {
    11  	// A Gauge should retain the last value it is set to
    12  	SetGauge(key []string, val float32)
    13  	SetGaugeWithLabels(key []string, val float32, labels []Label)
    14  
    15  	// Should emit a Key/Value pair for each call
    16  	EmitKey(key []string, val float32)
    17  
    18  	// Counters should accumulate values
    19  	IncrCounter(key []string, val float32)
    20  	IncrCounterWithLabels(key []string, val float32, labels []Label)
    21  
    22  	// Samples are for timing information, where quantiles are used
    23  	AddSample(key []string, val float32)
    24  	AddSampleWithLabels(key []string, val float32, labels []Label)
    25  }
    26  
    27  // PrecisionGaugeMetricSink interfae is used to support 64 bit precisions for Sinks, if needed.
    28  type PrecisionGaugeMetricSink interface {
    29  	SetPrecisionGauge(key []string, val float64)
    30  	SetPrecisionGaugeWithLabels(key []string, val float64, labels []Label)
    31  }
    32  
    33  type ShutdownSink interface {
    34  	MetricSink
    35  
    36  	// Shutdown the metric sink, flush metrics to storage, and cleanup resources.
    37  	// Called immediately prior to application exit. Implementations must block
    38  	// until metrics are flushed to storage.
    39  	Shutdown()
    40  }
    41  
    42  // BlackholeSink is used to just blackhole messages
    43  type BlackholeSink struct{}
    44  
    45  func (*BlackholeSink) SetGauge(key []string, val float32)                                    {}
    46  func (*BlackholeSink) SetGaugeWithLabels(key []string, val float32, labels []Label)          {}
    47  func (*BlackholeSink) SetPrecisionGauge(key []string, val float64)                           {}
    48  func (*BlackholeSink) SetPrecisionGaugeWithLabels(key []string, val float64, labels []Label) {}
    49  func (*BlackholeSink) EmitKey(key []string, val float32)                                     {}
    50  func (*BlackholeSink) IncrCounter(key []string, val float32)                                 {}
    51  func (*BlackholeSink) IncrCounterWithLabels(key []string, val float32, labels []Label)       {}
    52  func (*BlackholeSink) AddSample(key []string, val float32)                                   {}
    53  func (*BlackholeSink) AddSampleWithLabels(key []string, val float32, labels []Label)         {}
    54  
    55  // FanoutSink is used to sink to fanout values to multiple sinks
    56  type FanoutSink []MetricSink
    57  
    58  func (fh FanoutSink) SetGauge(key []string, val float32) {
    59  	fh.SetGaugeWithLabels(key, val, nil)
    60  }
    61  
    62  func (fh FanoutSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {
    63  	for _, s := range fh {
    64  		s.SetGaugeWithLabels(key, val, labels)
    65  	}
    66  }
    67  
    68  func (fh FanoutSink) SetPrecisionGauge(key []string, val float64) {
    69  	fh.SetPrecisionGaugeWithLabels(key, val, nil)
    70  }
    71  
    72  func (fh FanoutSink) SetPrecisionGaugeWithLabels(key []string, val float64, labels []Label) {
    73  	for _, s := range fh {
    74  		// The Sink needs to implement PrecisionGaugeMetricSink, in case it doesn't, the metric value won't be set and ingored instead
    75  		if s64, ok := s.(PrecisionGaugeMetricSink); ok {
    76  			s64.SetPrecisionGaugeWithLabels(key, val, labels)
    77  		}
    78  	}
    79  }
    80  
    81  func (fh FanoutSink) EmitKey(key []string, val float32) {
    82  	for _, s := range fh {
    83  		s.EmitKey(key, val)
    84  	}
    85  }
    86  
    87  func (fh FanoutSink) IncrCounter(key []string, val float32) {
    88  	fh.IncrCounterWithLabels(key, val, nil)
    89  }
    90  
    91  func (fh FanoutSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {
    92  	for _, s := range fh {
    93  		s.IncrCounterWithLabels(key, val, labels)
    94  	}
    95  }
    96  
    97  func (fh FanoutSink) AddSample(key []string, val float32) {
    98  	fh.AddSampleWithLabels(key, val, nil)
    99  }
   100  
   101  func (fh FanoutSink) AddSampleWithLabels(key []string, val float32, labels []Label) {
   102  	for _, s := range fh {
   103  		s.AddSampleWithLabels(key, val, labels)
   104  	}
   105  }
   106  
   107  func (fh FanoutSink) Shutdown() {
   108  	for _, s := range fh {
   109  		if ss, ok := s.(ShutdownSink); ok {
   110  			ss.Shutdown()
   111  		}
   112  	}
   113  }
   114  
   115  // sinkURLFactoryFunc is an generic interface around the *SinkFromURL() function provided
   116  // by each sink type
   117  type sinkURLFactoryFunc func(*url.URL) (MetricSink, error)
   118  
   119  // sinkRegistry supports the generic NewMetricSink function by mapping URL
   120  // schemes to metric sink factory functions
   121  var sinkRegistry = map[string]sinkURLFactoryFunc{
   122  	"statsd":   NewStatsdSinkFromURL,
   123  	"statsite": NewStatsiteSinkFromURL,
   124  	"inmem":    NewInmemSinkFromURL,
   125  }
   126  
   127  // NewMetricSinkFromURL allows a generic URL input to configure any of the
   128  // supported sinks. The scheme of the URL identifies the type of the sink, the
   129  // and query parameters are used to set options.
   130  //
   131  // "statsd://" - Initializes a StatsdSink. The host and port are passed through
   132  // as the "addr" of the sink
   133  //
   134  // "statsite://" - Initializes a StatsiteSink. The host and port become the
   135  // "addr" of the sink
   136  //
   137  // "inmem://" - Initializes an InmemSink. The host and port are ignored. The
   138  // "interval" and "duration" query parameters must be specified with valid
   139  // durations, see NewInmemSink for details.
   140  func NewMetricSinkFromURL(urlStr string) (MetricSink, error) {
   141  	u, err := url.Parse(urlStr)
   142  	if err != nil {
   143  		return nil, err
   144  	}
   145  
   146  	sinkURLFactoryFunc := sinkRegistry[u.Scheme]
   147  	if sinkURLFactoryFunc == nil {
   148  		return nil, fmt.Errorf(
   149  			"cannot create metric sink, unrecognized sink name: %q", u.Scheme)
   150  	}
   151  
   152  	return sinkURLFactoryFunc(u)
   153  }