github.com/sereiner/library@v0.0.0-20200518095232-1fa3e640cc5f/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  	// Gets an existing metric or registers the given one.
    33  	// The interface can be the metric to register if not found in registry,
    34  	// or a function returning the metric for lazy instantiation.
    35  	GetOrRegister(string, interface{}) interface{}
    36  
    37  	// Register the given metric under the given name.
    38  	Register(string, interface{}) error
    39  
    40  	// Run all registered healthchecks.
    41  	RunHealthchecks()
    42  
    43  	// Unregister the metric with the given name.
    44  	Unregister(string)
    45  
    46  	// Unregister all metrics.  (Mostly for testing.)
    47  	UnregisterAll()
    48  }
    49  
    50  // The standard implementation of a Registry is a mutex-protected map
    51  // of names to metrics.
    52  type StandardRegistry struct {
    53  	metrics map[string]interface{}
    54  	mutex   sync.Mutex
    55  }
    56  
    57  // Create a new registry.
    58  func NewRegistry() Registry {
    59  	return &StandardRegistry{metrics: make(map[string]interface{})}
    60  }
    61  
    62  // Call the given function for each registered metric.
    63  func (r *StandardRegistry) Each(f func(string, interface{})) {
    64  	for name, i := range r.registered() {
    65  		f(name, i)
    66  	}
    67  }
    68  
    69  // Get the metric by the given name or nil if none is registered.
    70  func (r *StandardRegistry) Get(name string) interface{} {
    71  	r.mutex.Lock()
    72  	defer r.mutex.Unlock()
    73  	return r.metrics[name]
    74  }
    75  
    76  // Gets an existing metric or creates and registers a new one. Threadsafe
    77  // alternative to calling Get and Register on failure.
    78  // The interface can be the metric to register if not found in registry,
    79  // or a function returning the metric for lazy instantiation.
    80  func (r *StandardRegistry) GetOrRegister(name string, i interface{}) interface{} {
    81  	r.mutex.Lock()
    82  	defer r.mutex.Unlock()
    83  	if metric, ok := r.metrics[name]; ok {
    84  		return metric
    85  	}
    86  	if v := reflect.ValueOf(i); v.Kind() == reflect.Func {
    87  		i = v.Call(nil)[0].Interface()
    88  	}
    89  	r.register(name, i)
    90  	return i
    91  }
    92  
    93  // Register the given metric under the given name.  Returns a DuplicateMetric
    94  // if a metric by the given name is already registered.
    95  func (r *StandardRegistry) Register(name string, i interface{}) error {
    96  	r.mutex.Lock()
    97  	defer r.mutex.Unlock()
    98  	return r.register(name, i)
    99  }
   100  
   101  // Run all registered healthchecks.
   102  func (r *StandardRegistry) RunHealthchecks() {
   103  	r.mutex.Lock()
   104  	defer r.mutex.Unlock()
   105  	for _, i := range r.metrics {
   106  		if h, ok := i.(Healthcheck); ok {
   107  			h.Check()
   108  		}
   109  	}
   110  }
   111  
   112  // Unregister the metric with the given name.
   113  func (r *StandardRegistry) Unregister(name string) {
   114  	r.mutex.Lock()
   115  	defer r.mutex.Unlock()
   116  	delete(r.metrics, name)
   117  }
   118  
   119  // Unregister all metrics.  (Mostly for testing.)
   120  func (r *StandardRegistry) UnregisterAll() {
   121  	r.mutex.Lock()
   122  	defer r.mutex.Unlock()
   123  	for name, _ := range r.metrics {
   124  		delete(r.metrics, name)
   125  	}
   126  }
   127  
   128  func (r *StandardRegistry) register(name string, i interface{}) error {
   129  	if _, ok := r.metrics[name]; ok {
   130  		return DuplicateMetric(name)
   131  	}
   132  	switch i.(type) {
   133  	case Counter, Gauge, GaugeFloat64, Healthcheck, Histogram, Meter, Timer, IQPS:
   134  		r.metrics[name] = i
   135  	}
   136  	return nil
   137  }
   138  
   139  func (r *StandardRegistry) registered() map[string]interface{} {
   140  	r.mutex.Lock()
   141  	defer r.mutex.Unlock()
   142  	metrics := make(map[string]interface{}, len(r.metrics))
   143  	for name, i := range r.metrics {
   144  		metrics[name] = i
   145  	}
   146  	return metrics
   147  }
   148  
   149  type PrefixedRegistry struct {
   150  	underlying Registry
   151  	prefix     string
   152  }
   153  
   154  func NewPrefixedRegistry(prefix string) Registry {
   155  	return &PrefixedRegistry{
   156  		underlying: NewRegistry(),
   157  		prefix:     prefix,
   158  	}
   159  }
   160  
   161  func NewPrefixedChildRegistry(parent Registry, prefix string) Registry {
   162  	return &PrefixedRegistry{
   163  		underlying: parent,
   164  		prefix:     prefix,
   165  	}
   166  }
   167  
   168  // Call the given function for each registered metric.
   169  func (r *PrefixedRegistry) Each(fn func(string, interface{})) {
   170  	wrappedFn := func(prefix string) func(string, interface{}) {
   171  		return func(name string, iface interface{}) {
   172  			if strings.HasPrefix(name, prefix) {
   173  				fn(name, iface)
   174  			} else {
   175  				return
   176  			}
   177  		}
   178  	}
   179  
   180  	baseRegistry, prefix := findPrefix(r, "")
   181  	baseRegistry.Each(wrappedFn(prefix))
   182  }
   183  
   184  func findPrefix(registry Registry, prefix string) (Registry, string) {
   185  	switch r := registry.(type) {
   186  	case *PrefixedRegistry:
   187  		return findPrefix(r.underlying, r.prefix+prefix)
   188  	case *StandardRegistry:
   189  		return r, prefix
   190  	}
   191  	return nil, ""
   192  }
   193  
   194  // Get the metric by the given name or nil if none is registered.
   195  func (r *PrefixedRegistry) Get(name string) interface{} {
   196  	realName := r.prefix + name
   197  	return r.underlying.Get(realName)
   198  }
   199  
   200  // Gets an existing metric or registers the given one.
   201  // The interface can be the metric to register if not found in registry,
   202  // or a function returning the metric for lazy instantiation.
   203  func (r *PrefixedRegistry) GetOrRegister(name string, metric interface{}) interface{} {
   204  	realName := r.prefix + name
   205  	return r.underlying.GetOrRegister(realName, metric)
   206  }
   207  
   208  // Register the given metric under the given name. The name will be prefixed.
   209  func (r *PrefixedRegistry) Register(name string, metric interface{}) error {
   210  	realName := r.prefix + name
   211  	return r.underlying.Register(realName, metric)
   212  }
   213  
   214  // Run all registered healthchecks.
   215  func (r *PrefixedRegistry) RunHealthchecks() {
   216  	r.underlying.RunHealthchecks()
   217  }
   218  
   219  // Unregister the metric with the given name. The name will be prefixed.
   220  func (r *PrefixedRegistry) Unregister(name string) {
   221  	realName := r.prefix + name
   222  	r.underlying.Unregister(realName)
   223  }
   224  
   225  // Unregister all metrics.  (Mostly for testing.)
   226  func (r *PrefixedRegistry) UnregisterAll() {
   227  	r.underlying.UnregisterAll()
   228  }
   229  
   230  var DefaultRegistry Registry = NewRegistry()
   231  
   232  // Call the given function for each registered metric.
   233  func Each(f func(string, interface{})) {
   234  	DefaultRegistry.Each(f)
   235  }
   236  
   237  // Get the metric by the given name or nil if none is registered.
   238  func Get(name string) interface{} {
   239  	return DefaultRegistry.Get(name)
   240  }
   241  
   242  // Gets an existing metric or creates and registers a new one. Threadsafe
   243  // alternative to calling Get and Register on failure.
   244  func GetOrRegister(name string, i interface{}) interface{} {
   245  	return DefaultRegistry.GetOrRegister(name, i)
   246  }
   247  
   248  // Register the given metric under the given name.  Returns a DuplicateMetric
   249  // if a metric by the given name is already registered.
   250  func Register(name string, i interface{}) error {
   251  	return DefaultRegistry.Register(name, i)
   252  }
   253  
   254  // Register the given metric under the given name.  Panics if a metric by the
   255  // given name is already registered.
   256  func MustRegister(name string, i interface{}) {
   257  	if err := Register(name, i); err != nil {
   258  		panic(err)
   259  	}
   260  }
   261  
   262  // Run all registered healthchecks.
   263  func RunHealthchecks() {
   264  	DefaultRegistry.RunHealthchecks()
   265  }
   266  
   267  // Unregister the metric with the given name.
   268  func Unregister(name string) {
   269  	DefaultRegistry.Unregister(name)
   270  }