github.com/core-coin/go-core/v2@v2.1.9/metrics/registry.go (about)

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