github.com/theQRL/go-zond@v0.1.1/metrics/resetting_timer.go (about)

     1  package metrics
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  )
     7  
     8  // Initial slice capacity for the values stored in a ResettingTimer
     9  const InitialResettingTimerSliceCap = 10
    10  
    11  type ResettingTimerSnapshot interface {
    12  	Count() int
    13  	Mean() float64
    14  	Max() int64
    15  	Min() int64
    16  	Percentiles([]float64) []float64
    17  }
    18  
    19  // ResettingTimer is used for storing aggregated values for timers, which are reset on every flush interval.
    20  type ResettingTimer interface {
    21  	Snapshot() ResettingTimerSnapshot
    22  	Time(func())
    23  	Update(time.Duration)
    24  	UpdateSince(time.Time)
    25  }
    26  
    27  // GetOrRegisterResettingTimer returns an existing ResettingTimer or constructs and registers a
    28  // new StandardResettingTimer.
    29  func GetOrRegisterResettingTimer(name string, r Registry) ResettingTimer {
    30  	if nil == r {
    31  		r = DefaultRegistry
    32  	}
    33  	return r.GetOrRegister(name, NewResettingTimer).(ResettingTimer)
    34  }
    35  
    36  // NewRegisteredResettingTimer constructs and registers a new StandardResettingTimer.
    37  func NewRegisteredResettingTimer(name string, r Registry) ResettingTimer {
    38  	c := NewResettingTimer()
    39  	if nil == r {
    40  		r = DefaultRegistry
    41  	}
    42  	r.Register(name, c)
    43  	return c
    44  }
    45  
    46  // NewResettingTimer constructs a new StandardResettingTimer
    47  func NewResettingTimer() ResettingTimer {
    48  	if !Enabled {
    49  		return NilResettingTimer{}
    50  	}
    51  	return &StandardResettingTimer{
    52  		values: make([]int64, 0, InitialResettingTimerSliceCap),
    53  	}
    54  }
    55  
    56  // NilResettingTimer is a no-op ResettingTimer.
    57  type NilResettingTimer struct{}
    58  
    59  func (NilResettingTimer) Values() []int64                    { return nil }
    60  func (n NilResettingTimer) Snapshot() ResettingTimerSnapshot { return n }
    61  func (NilResettingTimer) Time(f func())                      { f() }
    62  func (NilResettingTimer) Update(time.Duration)               {}
    63  func (NilResettingTimer) Percentiles([]float64) []float64    { return nil }
    64  func (NilResettingTimer) Mean() float64                      { return 0.0 }
    65  func (NilResettingTimer) Max() int64                         { return 0 }
    66  func (NilResettingTimer) Min() int64                         { return 0 }
    67  func (NilResettingTimer) UpdateSince(time.Time)              {}
    68  func (NilResettingTimer) Count() int                         { return 0 }
    69  
    70  // StandardResettingTimer is the standard implementation of a ResettingTimer.
    71  // and Meter.
    72  type StandardResettingTimer struct {
    73  	values []int64
    74  	sum    int64 // sum is a running count of the total sum, used later to calculate mean
    75  
    76  	mutex sync.Mutex
    77  }
    78  
    79  // Snapshot resets the timer and returns a read-only copy of its contents.
    80  func (t *StandardResettingTimer) Snapshot() ResettingTimerSnapshot {
    81  	t.mutex.Lock()
    82  	defer t.mutex.Unlock()
    83  	snapshot := &resettingTimerSnapshot{}
    84  	if len(t.values) > 0 {
    85  		snapshot.mean = float64(t.sum) / float64(len(t.values))
    86  		snapshot.values = t.values
    87  		t.values = make([]int64, 0, InitialResettingTimerSliceCap)
    88  	}
    89  	t.sum = 0
    90  	return snapshot
    91  }
    92  
    93  // Record the duration of the execution of the given function.
    94  func (t *StandardResettingTimer) Time(f func()) {
    95  	ts := time.Now()
    96  	f()
    97  	t.Update(time.Since(ts))
    98  }
    99  
   100  // Record the duration of an event.
   101  func (t *StandardResettingTimer) Update(d time.Duration) {
   102  	t.mutex.Lock()
   103  	defer t.mutex.Unlock()
   104  	t.values = append(t.values, int64(d))
   105  	t.sum += int64(d)
   106  }
   107  
   108  // Record the duration of an event that started at a time and ends now.
   109  func (t *StandardResettingTimer) UpdateSince(ts time.Time) {
   110  	t.Update(time.Since(ts))
   111  }
   112  
   113  // resettingTimerSnapshot is a point-in-time copy of another ResettingTimer.
   114  type resettingTimerSnapshot struct {
   115  	values              []int64
   116  	mean                float64
   117  	max                 int64
   118  	min                 int64
   119  	thresholdBoundaries []float64
   120  	calculated          bool
   121  }
   122  
   123  // Count return the length of the values from snapshot.
   124  func (t *resettingTimerSnapshot) Count() int {
   125  	return len(t.values)
   126  }
   127  
   128  // Percentiles returns the boundaries for the input percentiles.
   129  // note: this method is not thread safe
   130  func (t *resettingTimerSnapshot) Percentiles(percentiles []float64) []float64 {
   131  	t.calc(percentiles)
   132  	return t.thresholdBoundaries
   133  }
   134  
   135  // Mean returns the mean of the snapshotted values
   136  // note: this method is not thread safe
   137  func (t *resettingTimerSnapshot) Mean() float64 {
   138  	if !t.calculated {
   139  		t.calc(nil)
   140  	}
   141  
   142  	return t.mean
   143  }
   144  
   145  // Max returns the max of the snapshotted values
   146  // note: this method is not thread safe
   147  func (t *resettingTimerSnapshot) Max() int64 {
   148  	if !t.calculated {
   149  		t.calc(nil)
   150  	}
   151  	return t.max
   152  }
   153  
   154  // Min returns the min of the snapshotted values
   155  // note: this method is not thread safe
   156  func (t *resettingTimerSnapshot) Min() int64 {
   157  	if !t.calculated {
   158  		t.calc(nil)
   159  	}
   160  	return t.min
   161  }
   162  
   163  func (t *resettingTimerSnapshot) calc(percentiles []float64) {
   164  	scores := CalculatePercentiles(t.values, percentiles)
   165  	t.thresholdBoundaries = scores
   166  	if len(t.values) == 0 {
   167  		return
   168  	}
   169  	t.min = t.values[0]
   170  	t.max = t.values[len(t.values)-1]
   171  }