github.com/rcrowley/go-metrics@v0.0.0-20201227073835-cf1acfcdf475/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.RWMutex
    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  	metrics := r.registered()
    68  	for i := range metrics {
    69  		kv := &metrics[i]
    70  		f(kv.name, kv.value)
    71  	}
    72  }
    73  
    74  // Get the metric by the given name or nil if none is registered.
    75  func (r *StandardRegistry) Get(name string) interface{} {
    76  	r.mutex.RLock()
    77  	defer r.mutex.RUnlock()
    78  	return r.metrics[name]
    79  }
    80  
    81  // Gets an existing metric or creates and registers a new one. Threadsafe
    82  // alternative to calling Get and Register on failure.
    83  // The interface can be the metric to register if not found in registry,
    84  // or a function returning the metric for lazy instantiation.
    85  func (r *StandardRegistry) GetOrRegister(name string, i interface{}) interface{} {
    86  	// access the read lock first which should be re-entrant
    87  	r.mutex.RLock()
    88  	metric, ok := r.metrics[name]
    89  	r.mutex.RUnlock()
    90  	if ok {
    91  		return metric
    92  	}
    93  
    94  	// only take the write lock if we'll be modifying the metrics map
    95  	r.mutex.Lock()
    96  	defer r.mutex.Unlock()
    97  	if metric, ok := r.metrics[name]; ok {
    98  		return metric
    99  	}
   100  	if v := reflect.ValueOf(i); v.Kind() == reflect.Func {
   101  		i = v.Call(nil)[0].Interface()
   102  	}
   103  	r.register(name, i)
   104  	return i
   105  }
   106  
   107  // Register the given metric under the given name.  Returns a DuplicateMetric
   108  // if a metric by the given name is already registered.
   109  func (r *StandardRegistry) Register(name string, i interface{}) error {
   110  	r.mutex.Lock()
   111  	defer r.mutex.Unlock()
   112  	return r.register(name, i)
   113  }
   114  
   115  // Run all registered healthchecks.
   116  func (r *StandardRegistry) RunHealthchecks() {
   117  	r.mutex.RLock()
   118  	defer r.mutex.RUnlock()
   119  	for _, i := range r.metrics {
   120  		if h, ok := i.(Healthcheck); ok {
   121  			h.Check()
   122  		}
   123  	}
   124  }
   125  
   126  // GetAll metrics in the Registry
   127  func (r *StandardRegistry) GetAll() map[string]map[string]interface{} {
   128  	data := make(map[string]map[string]interface{})
   129  	r.Each(func(name string, i interface{}) {
   130  		values := make(map[string]interface{})
   131  		switch metric := i.(type) {
   132  		case Counter:
   133  			values["count"] = metric.Count()
   134  		case Gauge:
   135  			values["value"] = metric.Value()
   136  		case GaugeFloat64:
   137  			values["value"] = metric.Value()
   138  		case Healthcheck:
   139  			values["error"] = nil
   140  			metric.Check()
   141  			if err := metric.Error(); nil != err {
   142  				values["error"] = metric.Error().Error()
   143  			}
   144  		case Histogram:
   145  			h := metric.Snapshot()
   146  			ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
   147  			values["count"] = h.Count()
   148  			values["min"] = h.Min()
   149  			values["max"] = h.Max()
   150  			values["mean"] = h.Mean()
   151  			values["stddev"] = h.StdDev()
   152  			values["median"] = ps[0]
   153  			values["75%"] = ps[1]
   154  			values["95%"] = ps[2]
   155  			values["99%"] = ps[3]
   156  			values["99.9%"] = ps[4]
   157  		case Meter:
   158  			m := metric.Snapshot()
   159  			values["count"] = m.Count()
   160  			values["1m.rate"] = m.Rate1()
   161  			values["5m.rate"] = m.Rate5()
   162  			values["15m.rate"] = m.Rate15()
   163  			values["mean.rate"] = m.RateMean()
   164  		case Timer:
   165  			t := metric.Snapshot()
   166  			ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
   167  			values["count"] = t.Count()
   168  			values["min"] = t.Min()
   169  			values["max"] = t.Max()
   170  			values["mean"] = t.Mean()
   171  			values["stddev"] = t.StdDev()
   172  			values["median"] = ps[0]
   173  			values["75%"] = ps[1]
   174  			values["95%"] = ps[2]
   175  			values["99%"] = ps[3]
   176  			values["99.9%"] = ps[4]
   177  			values["1m.rate"] = t.Rate1()
   178  			values["5m.rate"] = t.Rate5()
   179  			values["15m.rate"] = t.Rate15()
   180  			values["mean.rate"] = t.RateMean()
   181  		}
   182  		data[name] = values
   183  	})
   184  	return data
   185  }
   186  
   187  // Unregister the metric with the given name.
   188  func (r *StandardRegistry) Unregister(name string) {
   189  	r.mutex.Lock()
   190  	defer r.mutex.Unlock()
   191  	r.stop(name)
   192  	delete(r.metrics, name)
   193  }
   194  
   195  // Unregister all metrics.  (Mostly for testing.)
   196  func (r *StandardRegistry) UnregisterAll() {
   197  	r.mutex.Lock()
   198  	defer r.mutex.Unlock()
   199  	for name, _ := range r.metrics {
   200  		r.stop(name)
   201  		delete(r.metrics, name)
   202  	}
   203  }
   204  
   205  func (r *StandardRegistry) register(name string, i interface{}) error {
   206  	if _, ok := r.metrics[name]; ok {
   207  		return DuplicateMetric(name)
   208  	}
   209  	switch i.(type) {
   210  	case Counter, Gauge, GaugeFloat64, Healthcheck, Histogram, Meter, Timer:
   211  		r.metrics[name] = i
   212  	}
   213  	return nil
   214  }
   215  
   216  type metricKV struct {
   217  	name  string
   218  	value interface{}
   219  }
   220  
   221  func (r *StandardRegistry) registered() []metricKV {
   222  	r.mutex.RLock()
   223  	defer r.mutex.RUnlock()
   224  	metrics := make([]metricKV, 0, len(r.metrics))
   225  	for name, i := range r.metrics {
   226  		metrics = append(metrics, metricKV{
   227  			name:  name,
   228  			value: i,
   229  		})
   230  	}
   231  	return metrics
   232  }
   233  
   234  func (r *StandardRegistry) stop(name string) {
   235  	if i, ok := r.metrics[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  // Unregister all metrics.  (Mostly for testing.)
   329  func (r *PrefixedRegistry) UnregisterAll() {
   330  	r.underlying.UnregisterAll()
   331  }
   332  
   333  var DefaultRegistry Registry = NewRegistry()
   334  
   335  // Call the given function for each registered metric.
   336  func Each(f func(string, interface{})) {
   337  	DefaultRegistry.Each(f)
   338  }
   339  
   340  // Get the metric by the given name or nil if none is registered.
   341  func Get(name string) interface{} {
   342  	return DefaultRegistry.Get(name)
   343  }
   344  
   345  // Gets an existing metric or creates and registers a new one. Threadsafe
   346  // alternative to calling Get and Register on failure.
   347  func GetOrRegister(name string, i interface{}) interface{} {
   348  	return DefaultRegistry.GetOrRegister(name, i)
   349  }
   350  
   351  // Register the given metric under the given name.  Returns a DuplicateMetric
   352  // if a metric by the given name is already registered.
   353  func Register(name string, i interface{}) error {
   354  	return DefaultRegistry.Register(name, i)
   355  }
   356  
   357  // Register the given metric under the given name.  Panics if a metric by the
   358  // given name is already registered.
   359  func MustRegister(name string, i interface{}) {
   360  	if err := Register(name, i); err != nil {
   361  		panic(err)
   362  	}
   363  }
   364  
   365  // Run all registered healthchecks.
   366  func RunHealthchecks() {
   367  	DefaultRegistry.RunHealthchecks()
   368  }
   369  
   370  // Unregister the metric with the given name.
   371  func Unregister(name string) {
   372  	DefaultRegistry.Unregister(name)
   373  }