github.com/theQRL/go-zond@v0.1.1/metrics/registry.go (about)

     1  package metrics
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"sort"
     7  	"strings"
     8  	"sync"
     9  )
    10  
    11  // DuplicateMetric is the error returned by Registry.Register when a metric
    12  // already exists.  If you mean to Register that metric you must first
    13  // Unregister the existing metric.
    14  type DuplicateMetric string
    15  
    16  func (err DuplicateMetric) Error() string {
    17  	return fmt.Sprintf("duplicate metric: %s", string(err))
    18  }
    19  
    20  // A Registry holds references to a set of metrics by name and can iterate
    21  // over them, calling callback functions provided by the user.
    22  //
    23  // This is an interface so as to encourage other structs to implement
    24  // the Registry API as appropriate.
    25  type Registry interface {
    26  
    27  	// Call the given function for each registered metric.
    28  	Each(func(string, interface{}))
    29  
    30  	// Get the metric by the given name or nil if none is registered.
    31  	Get(string) interface{}
    32  
    33  	// GetAll metrics in the Registry.
    34  	GetAll() map[string]map[string]interface{}
    35  
    36  	// Gets an existing metric or registers the given one.
    37  	// The interface can be the metric to register if not found in registry,
    38  	// or a function returning the metric for lazy instantiation.
    39  	GetOrRegister(string, interface{}) interface{}
    40  
    41  	// Register the given metric under the given name.
    42  	Register(string, interface{}) error
    43  
    44  	// Run all registered healthchecks.
    45  	RunHealthchecks()
    46  
    47  	// Unregister the metric with the given name.
    48  	Unregister(string)
    49  }
    50  
    51  type orderedRegistry struct {
    52  	StandardRegistry
    53  }
    54  
    55  // Call the given function for each registered metric.
    56  func (r *orderedRegistry) Each(f func(string, interface{})) {
    57  	var names []string
    58  	reg := r.registered()
    59  	for name := range reg {
    60  		names = append(names, name)
    61  	}
    62  	sort.Strings(names)
    63  	for _, name := range names {
    64  		f(name, reg[name])
    65  	}
    66  }
    67  
    68  // NewRegistry creates a new registry.
    69  func NewRegistry() Registry {
    70  	return new(StandardRegistry)
    71  }
    72  
    73  // NewOrderedRegistry creates a new ordered registry (for testing).
    74  func NewOrderedRegistry() Registry {
    75  	return new(orderedRegistry)
    76  }
    77  
    78  // The standard implementation of a Registry uses sync.map
    79  // of names to metrics.
    80  type StandardRegistry struct {
    81  	metrics sync.Map
    82  }
    83  
    84  // Call the given function for each registered metric.
    85  func (r *StandardRegistry) Each(f func(string, interface{})) {
    86  	for name, i := range r.registered() {
    87  		f(name, i)
    88  	}
    89  }
    90  
    91  // Get the metric by the given name or nil if none is registered.
    92  func (r *StandardRegistry) Get(name string) interface{} {
    93  	item, _ := r.metrics.Load(name)
    94  	return item
    95  }
    96  
    97  // Gets an existing metric or creates and registers a new one. Threadsafe
    98  // alternative to calling Get and Register on failure.
    99  // The interface can be the metric to register if not found in registry,
   100  // or a function returning the metric for lazy instantiation.
   101  func (r *StandardRegistry) GetOrRegister(name string, i interface{}) interface{} {
   102  	// fast path
   103  	cached, ok := r.metrics.Load(name)
   104  	if ok {
   105  		return cached
   106  	}
   107  	if v := reflect.ValueOf(i); v.Kind() == reflect.Func {
   108  		i = v.Call(nil)[0].Interface()
   109  	}
   110  	item, _, ok := r.loadOrRegister(name, i)
   111  	if !ok {
   112  		return i
   113  	}
   114  	return item
   115  }
   116  
   117  // Register the given metric under the given name.  Returns a DuplicateMetric
   118  // if a metric by the given name is already registered.
   119  func (r *StandardRegistry) Register(name string, i interface{}) error {
   120  	// fast path
   121  	_, ok := r.metrics.Load(name)
   122  	if ok {
   123  		return DuplicateMetric(name)
   124  	}
   125  
   126  	if v := reflect.ValueOf(i); v.Kind() == reflect.Func {
   127  		i = v.Call(nil)[0].Interface()
   128  	}
   129  	_, loaded, _ := r.loadOrRegister(name, i)
   130  	if loaded {
   131  		return DuplicateMetric(name)
   132  	}
   133  	return nil
   134  }
   135  
   136  // Run all registered healthchecks.
   137  func (r *StandardRegistry) RunHealthchecks() {
   138  	r.metrics.Range(func(key, value any) bool {
   139  		if h, ok := value.(Healthcheck); ok {
   140  			h.Check()
   141  		}
   142  		return true
   143  	})
   144  }
   145  
   146  // GetAll metrics in the Registry
   147  func (r *StandardRegistry) GetAll() map[string]map[string]interface{} {
   148  	data := make(map[string]map[string]interface{})
   149  	r.Each(func(name string, i interface{}) {
   150  		values := make(map[string]interface{})
   151  		switch metric := i.(type) {
   152  		case Counter:
   153  			values["count"] = metric.Snapshot().Count()
   154  		case CounterFloat64:
   155  			values["count"] = metric.Snapshot().Count()
   156  		case Gauge:
   157  			values["value"] = metric.Snapshot().Value()
   158  		case GaugeFloat64:
   159  			values["value"] = metric.Snapshot().Value()
   160  		case Healthcheck:
   161  			values["error"] = nil
   162  			metric.Check()
   163  			if err := metric.Error(); nil != err {
   164  				values["error"] = metric.Error().Error()
   165  			}
   166  		case Histogram:
   167  			h := metric.Snapshot()
   168  			ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
   169  			values["count"] = h.Count()
   170  			values["min"] = h.Min()
   171  			values["max"] = h.Max()
   172  			values["mean"] = h.Mean()
   173  			values["stddev"] = h.StdDev()
   174  			values["median"] = ps[0]
   175  			values["75%"] = ps[1]
   176  			values["95%"] = ps[2]
   177  			values["99%"] = ps[3]
   178  			values["99.9%"] = ps[4]
   179  		case Meter:
   180  			m := metric.Snapshot()
   181  			values["count"] = m.Count()
   182  			values["1m.rate"] = m.Rate1()
   183  			values["5m.rate"] = m.Rate5()
   184  			values["15m.rate"] = m.Rate15()
   185  			values["mean.rate"] = m.RateMean()
   186  		case Timer:
   187  			t := metric.Snapshot()
   188  			ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
   189  			values["count"] = t.Count()
   190  			values["min"] = t.Min()
   191  			values["max"] = t.Max()
   192  			values["mean"] = t.Mean()
   193  			values["stddev"] = t.StdDev()
   194  			values["median"] = ps[0]
   195  			values["75%"] = ps[1]
   196  			values["95%"] = ps[2]
   197  			values["99%"] = ps[3]
   198  			values["99.9%"] = ps[4]
   199  			values["1m.rate"] = t.Rate1()
   200  			values["5m.rate"] = t.Rate5()
   201  			values["15m.rate"] = t.Rate15()
   202  			values["mean.rate"] = t.RateMean()
   203  		}
   204  		data[name] = values
   205  	})
   206  	return data
   207  }
   208  
   209  // Unregister the metric with the given name.
   210  func (r *StandardRegistry) Unregister(name string) {
   211  	r.stop(name)
   212  	r.metrics.LoadAndDelete(name)
   213  }
   214  
   215  func (r *StandardRegistry) loadOrRegister(name string, i interface{}) (interface{}, bool, bool) {
   216  	switch i.(type) {
   217  	case Counter, CounterFloat64, Gauge, GaugeFloat64, GaugeInfo, Healthcheck, Histogram, Meter, Timer, ResettingTimer:
   218  	default:
   219  		return nil, false, false
   220  	}
   221  	item, loaded := r.metrics.LoadOrStore(name, i)
   222  	return item, loaded, true
   223  }
   224  
   225  func (r *StandardRegistry) registered() map[string]interface{} {
   226  	metrics := make(map[string]interface{})
   227  	r.metrics.Range(func(key, value any) bool {
   228  		metrics[key.(string)] = value
   229  		return true
   230  	})
   231  	return metrics
   232  }
   233  
   234  func (r *StandardRegistry) stop(name string) {
   235  	if i, ok := r.metrics.Load(name); ok {
   236  		if s, ok := i.(Stoppable); ok {
   237  			s.Stop()
   238  		}
   239  	}
   240  }
   241  
   242  // Stoppable defines the metrics which has to be stopped.
   243  type Stoppable interface {
   244  	Stop()
   245  }
   246  
   247  type PrefixedRegistry struct {
   248  	underlying Registry
   249  	prefix     string
   250  }
   251  
   252  func NewPrefixedRegistry(prefix string) Registry {
   253  	return &PrefixedRegistry{
   254  		underlying: NewRegistry(),
   255  		prefix:     prefix,
   256  	}
   257  }
   258  
   259  func NewPrefixedChildRegistry(parent Registry, prefix string) Registry {
   260  	return &PrefixedRegistry{
   261  		underlying: parent,
   262  		prefix:     prefix,
   263  	}
   264  }
   265  
   266  // Call the given function for each registered metric.
   267  func (r *PrefixedRegistry) Each(fn func(string, interface{})) {
   268  	wrappedFn := func(prefix string) func(string, interface{}) {
   269  		return func(name string, iface interface{}) {
   270  			if strings.HasPrefix(name, prefix) {
   271  				fn(name, iface)
   272  			} else {
   273  				return
   274  			}
   275  		}
   276  	}
   277  
   278  	baseRegistry, prefix := findPrefix(r, "")
   279  	baseRegistry.Each(wrappedFn(prefix))
   280  }
   281  
   282  func findPrefix(registry Registry, prefix string) (Registry, string) {
   283  	switch r := registry.(type) {
   284  	case *PrefixedRegistry:
   285  		return findPrefix(r.underlying, r.prefix+prefix)
   286  	case *StandardRegistry:
   287  		return r, prefix
   288  	}
   289  	return nil, ""
   290  }
   291  
   292  // Get the metric by the given name or nil if none is registered.
   293  func (r *PrefixedRegistry) Get(name string) interface{} {
   294  	realName := r.prefix + name
   295  	return r.underlying.Get(realName)
   296  }
   297  
   298  // Gets an existing metric or registers the given one.
   299  // The interface can be the metric to register if not found in registry,
   300  // or a function returning the metric for lazy instantiation.
   301  func (r *PrefixedRegistry) GetOrRegister(name string, metric interface{}) interface{} {
   302  	realName := r.prefix + name
   303  	return r.underlying.GetOrRegister(realName, metric)
   304  }
   305  
   306  // Register the given metric under the given name. The name will be prefixed.
   307  func (r *PrefixedRegistry) Register(name string, metric interface{}) error {
   308  	realName := r.prefix + name
   309  	return r.underlying.Register(realName, metric)
   310  }
   311  
   312  // Run all registered healthchecks.
   313  func (r *PrefixedRegistry) RunHealthchecks() {
   314  	r.underlying.RunHealthchecks()
   315  }
   316  
   317  // GetAll metrics in the Registry
   318  func (r *PrefixedRegistry) GetAll() map[string]map[string]interface{} {
   319  	return r.underlying.GetAll()
   320  }
   321  
   322  // Unregister the metric with the given name. The name will be prefixed.
   323  func (r *PrefixedRegistry) Unregister(name string) {
   324  	realName := r.prefix + name
   325  	r.underlying.Unregister(realName)
   326  }
   327  
   328  var (
   329  	DefaultRegistry    = NewRegistry()
   330  	EphemeralRegistry  = NewRegistry()
   331  	AccountingRegistry = NewRegistry() // registry used in swarm
   332  )
   333  
   334  // Call the given function for each registered metric.
   335  func Each(f func(string, interface{})) {
   336  	DefaultRegistry.Each(f)
   337  }
   338  
   339  // Get the metric by the given name or nil if none is registered.
   340  func Get(name string) interface{} {
   341  	return DefaultRegistry.Get(name)
   342  }
   343  
   344  // Gets an existing metric or creates and registers a new one. Threadsafe
   345  // alternative to calling Get and Register on failure.
   346  func GetOrRegister(name string, i interface{}) interface{} {
   347  	return DefaultRegistry.GetOrRegister(name, i)
   348  }
   349  
   350  // Register the given metric under the given name.  Returns a DuplicateMetric
   351  // if a metric by the given name is already registered.
   352  func Register(name string, i interface{}) error {
   353  	return DefaultRegistry.Register(name, i)
   354  }
   355  
   356  // Register the given metric under the given name.  Panics if a metric by the
   357  // given name is already registered.
   358  func MustRegister(name string, i interface{}) {
   359  	if err := Register(name, i); err != nil {
   360  		panic(err)
   361  	}
   362  }
   363  
   364  // Run all registered healthchecks.
   365  func RunHealthchecks() {
   366  	DefaultRegistry.RunHealthchecks()
   367  }
   368  
   369  // Unregister the metric with the given name.
   370  func Unregister(name string) {
   371  	DefaultRegistry.Unregister(name)
   372  }