github.com/amazechain/amc@v0.1.3/internal/metrics/prometheus/registry.go (about)

     1  package prometheus
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"sync"
     7  
     8  	metrics2 "github.com/VictoriaMetrics/metrics"
     9  	"github.com/ledgerwatch/log/v3"
    10  )
    11  
    12  // DuplicateMetric is the error returned by Registry.Register when a metric
    13  // already exists.  If you mean to Register that metric you must first
    14  // Unregister the existing metric.
    15  type DuplicateMetric string
    16  
    17  func (err DuplicateMetric) Error() string {
    18  	return fmt.Sprintf("duplicate metric: %s", string(err))
    19  }
    20  
    21  // A Registry holds references to a set of metrics by name and can iterate
    22  // over them, calling callback functions provided by the user.
    23  //
    24  // This is an interface so as to encourage other structs to implement
    25  // the Registry API as appropriate.
    26  type Registry interface {
    27  
    28  	// Call the given function for each registered metric.
    29  	Each(func(string, interface{}))
    30  
    31  	// Get the metric by the given name or nil if none is registered.
    32  	Get(string) interface{}
    33  
    34  	// Gets an existing metric or registers the given one.
    35  	// The interface can be the metric to register if not found in registry,
    36  	// or a function returning the metric for lazy instantiation.
    37  	GetOrRegister(string, interface{}) interface{}
    38  
    39  	// Register the given metric under the given name.
    40  	Register(string, interface{}) error
    41  
    42  	// Unregister the metric with the given name.
    43  	Unregister(string)
    44  
    45  	// Unregister all metrics.  (Mostly for testing.)
    46  	UnregisterAll()
    47  }
    48  
    49  // The standard implementation of a Registry is a mutex-protected map
    50  // of names to metrics.
    51  type StandardRegistry struct {
    52  	metrics map[string]interface{}
    53  	mutex   sync.Mutex
    54  }
    55  
    56  // Create a new registry.
    57  func NewRegistry() Registry {
    58  	return &StandardRegistry{metrics: make(map[string]interface{})}
    59  }
    60  
    61  // Call the given function for each registered metric.
    62  func (r *StandardRegistry) Each(f func(string, interface{})) {
    63  	for name, i := range r.registered() {
    64  		f(name, i)
    65  	}
    66  }
    67  
    68  // Get the metric by the given name or nil if none is registered.
    69  func (r *StandardRegistry) Get(name string) interface{} {
    70  	r.mutex.Lock()
    71  	defer r.mutex.Unlock()
    72  	return r.metrics[name]
    73  }
    74  
    75  // Gets an existing metric or creates and registers a new one. Threadsafe
    76  // alternative to calling Get and Register on failure.
    77  // The interface can be the metric to register if not found in registry,
    78  // or a function returning the metric for lazy instantiation.
    79  func (r *StandardRegistry) GetOrRegister(name string, i interface{}) interface{} {
    80  	r.mutex.Lock()
    81  	defer r.mutex.Unlock()
    82  	if metric, ok := r.metrics[name]; ok {
    83  		return metric
    84  	}
    85  	if v := reflect.ValueOf(i); v.Kind() == reflect.Func {
    86  		i = v.Call(nil)[0].Interface()
    87  	}
    88  	r.register(name, i)
    89  	return i
    90  }
    91  
    92  // Register the given metric under the given name.  Returns a DuplicateMetric
    93  // if a metric by the given name is already registered.
    94  func (r *StandardRegistry) Register(name string, i interface{}) error {
    95  	r.mutex.Lock()
    96  	defer r.mutex.Unlock()
    97  	return r.register(name, i)
    98  }
    99  
   100  // Unregister the metric with the given name.
   101  func (r *StandardRegistry) Unregister(name string) {
   102  	r.mutex.Lock()
   103  	defer r.mutex.Unlock()
   104  	r.stop(name)
   105  	delete(r.metrics, name)
   106  }
   107  
   108  // Unregister all metrics.  (Mostly for testing.)
   109  func (r *StandardRegistry) UnregisterAll() {
   110  	r.mutex.Lock()
   111  	defer r.mutex.Unlock()
   112  	for name := range r.metrics {
   113  		r.stop(name)
   114  		delete(r.metrics, name)
   115  	}
   116  }
   117  
   118  func (r *StandardRegistry) register(name string, i interface{}) error {
   119  	if _, ok := r.metrics[name]; ok {
   120  		return DuplicateMetric(name)
   121  	}
   122  	switch i.(type) {
   123  	case *metrics2.Counter, *metrics2.Gauge, *metrics2.FloatCounter, *metrics2.Histogram, *metrics2.Summary:
   124  		r.metrics[name] = i
   125  	default:
   126  		log.Info("Type not registered(metrics won't show): ", reflect.TypeOf(i))
   127  	}
   128  	return nil
   129  }
   130  
   131  func (r *StandardRegistry) registered() map[string]interface{} {
   132  	r.mutex.Lock()
   133  	defer r.mutex.Unlock()
   134  	metrics := make(map[string]interface{}, len(r.metrics))
   135  	for name, i := range r.metrics {
   136  		metrics[name] = i
   137  	}
   138  	return metrics
   139  }
   140  
   141  func (r *StandardRegistry) stop(name string) {
   142  	if i, ok := r.metrics[name]; ok {
   143  		if s, ok := i.(Stoppable); ok {
   144  			s.Stop()
   145  		}
   146  	}
   147  }
   148  
   149  // Stoppable defines the metrics which has to be stopped.
   150  type Stoppable interface {
   151  	Stop()
   152  }
   153  
   154  var (
   155  	DefaultRegistry    = NewRegistry()
   156  	EphemeralRegistry  = NewRegistry()
   157  	AccountingRegistry = NewRegistry() // registry used in swarm
   158  )
   159  
   160  // Get the metric by the given name or nil if none is registered.
   161  func Get(name string) interface{} {
   162  	return DefaultRegistry.Get(name)
   163  }