github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/metrics/registry.go (about)

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