package metrics import ( "fmt" "net/url" ) // The MetricSink interface is used to transmit metrics information // to an external system type MetricSink interface { // A Gauge should retain the last value it is set to SetGauge(key []string, val float32) SetGaugeWithLabels(key []string, val float32, labels []Label) // Should emit a Key/Value pair for each call EmitKey(key []string, val float32) // Counters should accumulate values IncrCounter(key []string, val float32) IncrCounterWithLabels(key []string, val float32, labels []Label) // Samples are for timing information, where quantiles are used AddSample(key []string, val float32) AddSampleWithLabels(key []string, val float32, labels []Label) } // BlackholeSink is used to just blackhole messages type BlackholeSink struct{} func (*BlackholeSink) SetGauge(key []string, val float32) {} func (*BlackholeSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {} func (*BlackholeSink) EmitKey(key []string, val float32) {} func (*BlackholeSink) IncrCounter(key []string, val float32) {} func (*BlackholeSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {} func (*BlackholeSink) AddSample(key []string, val float32) {} func (*BlackholeSink) AddSampleWithLabels(key []string, val float32, labels []Label) {} // FanoutSink is used to sink to fanout values to multiple sinks type FanoutSink []MetricSink func (fh FanoutSink) SetGauge(key []string, val float32) { fh.SetGaugeWithLabels(key, val, nil) } func (fh FanoutSink) SetGaugeWithLabels(key []string, val float32, labels []Label) { for _, s := range fh { s.SetGaugeWithLabels(key, val, labels) } } func (fh FanoutSink) EmitKey(key []string, val float32) { for _, s := range fh { s.EmitKey(key, val) } } func (fh FanoutSink) IncrCounter(key []string, val float32) { fh.IncrCounterWithLabels(key, val, nil) } func (fh FanoutSink) IncrCounterWithLabels(key []string, val float32, labels []Label) { for _, s := range fh { s.IncrCounterWithLabels(key, val, labels) } } func (fh FanoutSink) AddSample(key []string, val float32) { fh.AddSampleWithLabels(key, val, nil) } func (fh FanoutSink) AddSampleWithLabels(key []string, val float32, labels []Label) { for _, s := range fh { s.AddSampleWithLabels(key, val, labels) } } // sinkURLFactoryFunc is an generic interface around the *SinkFromURL() function provided // by each sink type type sinkURLFactoryFunc func(*url.URL) (MetricSink, error) // sinkRegistry supports the generic NewMetricSink function by mapping URL // schemes to metric sink factory functions var sinkRegistry = map[string]sinkURLFactoryFunc{ "statsd": NewStatsdSinkFromURL, "statsite": NewStatsiteSinkFromURL, "inmem": NewInmemSinkFromURL, } // NewMetricSinkFromURL allows a generic URL input to configure any of the // supported sinks. The scheme of the URL identifies the type of the sink, the // and query parameters are used to set options. // // "statsd://" - Initializes a StatsdSink. The host and port are passed through // as the "addr" of the sink // // "statsite://" - Initializes a StatsiteSink. The host and port become the // "addr" of the sink // // "inmem://" - Initializes an InmemSink. The host and port are ignored. The // "interval" and "duration" query parameters must be specified with valid // durations, see NewInmemSink for details. func NewMetricSinkFromURL(urlStr string) (MetricSink, error) { u, err := url.Parse(urlStr) if err != nil { return nil, err } sinkURLFactoryFunc := sinkRegistry[u.Scheme] if sinkURLFactoryFunc == nil { return nil, fmt.Errorf( "cannot create metric sink, unrecognized sink name: %q", u.Scheme) } return sinkURLFactoryFunc(u) }