text: 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)
  }
  