github.com/wfusion/gofusion@v1.1.14/common/infra/metrics/sink.go (about)

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