github.com/ManabuSeki/goa-v1@v1.4.3/metrics.go (about)

     1  // +build !js,!appengine
     2  
     3  package goa
     4  
     5  import (
     6  	"regexp"
     7  	"strings"
     8  	"sync"
     9  	"time"
    10  
    11  	metrics "github.com/armon/go-metrics"
    12  )
    13  
    14  const (
    15  	allMatcher      string = "*/*"
    16  	allReplacement  string = "all"
    17  	normalizedToken string = "_"
    18  )
    19  
    20  var (
    21  	// metriks contains current collector
    22  	metriks Collector
    23  
    24  	// metriksMu is mutex for metriks variable
    25  	metriksMu sync.Mutex
    26  
    27  	// invalidCharactersRE is the invert match of validCharactersRE
    28  	invalidCharactersRE = regexp.MustCompile(`[\*/]`)
    29  
    30  	// Taken from https://github.com/prometheus/client_golang/blob/66058aac3a83021948e5fb12f1f408ff556b9037/prometheus/desc.go
    31  	validCharactersRE = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_:]*$`)
    32  )
    33  
    34  // Collector is the interface used for collecting metrics.
    35  type Collector interface {
    36  	AddSample(key []string, val float32)
    37  	EmitKey(key []string, val float32)
    38  	IncrCounter(key []string, val float32)
    39  	MeasureSince(key []string, start time.Time)
    40  	SetGauge(key []string, val float32)
    41  }
    42  
    43  func init() {
    44  	SetMetrics(NewNoOpCollector())
    45  }
    46  
    47  // newNoOpCollecter implements Collector, but provides no collection.
    48  type noOpCollecter struct{}
    49  
    50  func (*noOpCollecter) AddSample(key []string, val float32)        {}
    51  func (*noOpCollecter) EmitKey(key []string, val float32)          {}
    52  func (*noOpCollecter) IncrCounter(key []string, val float32)      {}
    53  func (*noOpCollecter) MeasureSince(key []string, start time.Time) {}
    54  func (*noOpCollecter) SetGauge(key []string, val float32)         {}
    55  
    56  // NewNoOpCollector returns a Collector that does no collection.
    57  func NewNoOpCollector() Collector {
    58  	return &noOpCollecter{}
    59  }
    60  
    61  // NewNoOpSink returns a NOOP sink.
    62  func NewNoOpSink() metrics.MetricSink {
    63  	return &NoOpSink{}
    64  }
    65  
    66  // NoOpSink default NOOP metrics recorder
    67  type NoOpSink struct{}
    68  
    69  func (*NoOpSink) SetGauge(key []string, val float32)                                      {}
    70  func (*NoOpSink) SetGaugeWithLabels(key []string, val float32, labels []metrics.Label)    {}
    71  func (*NoOpSink) EmitKey(key []string, val float32)                                       {}
    72  func (*NoOpSink) IncrCounter(key []string, val float32)                                   {}
    73  func (*NoOpSink) IncrCounterWithLabels(key []string, val float32, labels []metrics.Label) {}
    74  func (*NoOpSink) AddSample(key []string, val float32)                                     {}
    75  func (*NoOpSink) AddSampleWithLabels(key []string, val float32, labels []metrics.Label)   {}
    76  
    77  // NewMetrics initializes goa's metrics instance with the supplied
    78  // configuration and metrics sink
    79  // This method is deprecated and SetMetrics should be used instead.
    80  func NewMetrics(conf *metrics.Config, sink metrics.MetricSink) (err error) {
    81  	m, err := metrics.NewGlobal(conf, sink)
    82  	SetMetrics(m)
    83  
    84  	return nil
    85  }
    86  
    87  // SetMetrics initializes goa's metrics instance with the supplied metrics adapter interface.
    88  func SetMetrics(m Collector) {
    89  	metriksMu.Lock()
    90  	metriks = m
    91  	metriksMu.Unlock()
    92  }
    93  
    94  // GetMetrics returns goa's metrics collector adapter interface.
    95  func GetMetrics() Collector {
    96  	metriksMu.Lock()
    97  	m := metriks
    98  	metriksMu.Unlock()
    99  	return m
   100  }
   101  
   102  // AddSample adds a sample to an aggregated metric
   103  // reporting count, min, max, mean, and std deviation
   104  // Usage:
   105  //     AddSample([]string{"my","namespace","key"}, 15.0)
   106  func AddSample(key []string, val float32) {
   107  	normalizeKeys(key)
   108  
   109  	GetMetrics().AddSample(key, val)
   110  }
   111  
   112  // EmitKey emits a key/value pair
   113  // Usage:
   114  //     EmitKey([]string{"my","namespace","key"}, 15.0)
   115  func EmitKey(key []string, val float32) {
   116  	normalizeKeys(key)
   117  
   118  	GetMetrics().EmitKey(key, val)
   119  }
   120  
   121  // IncrCounter increments the counter named by `key`
   122  // Usage:
   123  //     IncrCounter([]key{"my","namespace","counter"}, 1.0)
   124  func IncrCounter(key []string, val float32) {
   125  	normalizeKeys(key)
   126  
   127  	GetMetrics().IncrCounter(key, val)
   128  }
   129  
   130  // MeasureSince creates a timing metric that records
   131  // the duration of elapsed time since `start`
   132  // Usage:
   133  //     MeasureSince([]string{"my","namespace","action}, time.Now())
   134  // Frequently used in a defer:
   135  //    defer MeasureSince([]string{"my","namespace","action}, time.Now())
   136  func MeasureSince(key []string, start time.Time) {
   137  	normalizeKeys(key)
   138  
   139  	GetMetrics().MeasureSince(key, start)
   140  }
   141  
   142  // SetGauge sets the named gauge to the specified value
   143  // Usage:
   144  //     SetGauge([]string{"my","namespace"}, 2.0)
   145  func SetGauge(key []string, val float32) {
   146  	normalizeKeys(key)
   147  
   148  	GetMetrics().SetGauge(key, val)
   149  }
   150  
   151  // This function is used to make metric names safe for all metric services. Specifically, prometheus does
   152  // not support * or / in metric names.
   153  func normalizeKeys(key []string) {
   154  	for i, k := range key {
   155  		if !validCharactersRE.MatchString(k) {
   156  			// first replace */* with all
   157  			k = strings.Replace(k, allMatcher, allReplacement, -1)
   158  
   159  			// now replace all other invalid characters with a safe one.
   160  			key[i] = invalidCharactersRE.ReplaceAllString(k, normalizedToken)
   161  		}
   162  	}
   163  }