resetting_timer.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. package metrics
  2. import (
  3. "math"
  4. "sort"
  5. "sync"
  6. "time"
  7. )
  8. // Initial slice capacity for the values stored in a ResettingTimer
  9. const InitialResettingTimerSliceCap = 10
  10. // ResettingTimer is used for storing aggregated values for timers, which are reset on every flush interval.
  11. type ResettingTimer interface {
  12. Values() []int64
  13. Snapshot() ResettingTimer
  14. Percentiles([]float64) []int64
  15. Mean() float64
  16. Time(func())
  17. Update(time.Duration)
  18. UpdateSince(time.Time)
  19. }
  20. // GetOrRegisterResettingTimer returns an existing ResettingTimer or constructs and registers a
  21. // new StandardResettingTimer.
  22. func GetOrRegisterResettingTimer(name string, r Registry) ResettingTimer {
  23. if nil == r {
  24. r = DefaultRegistry
  25. }
  26. return r.GetOrRegister(name, NewResettingTimer).(ResettingTimer)
  27. }
  28. // NewRegisteredResettingTimer constructs and registers a new StandardResettingTimer.
  29. func NewRegisteredResettingTimer(name string, r Registry) ResettingTimer {
  30. c := NewResettingTimer()
  31. if nil == r {
  32. r = DefaultRegistry
  33. }
  34. r.Register(name, c)
  35. return c
  36. }
  37. // NewResettingTimer constructs a new StandardResettingTimer
  38. func NewResettingTimer() ResettingTimer {
  39. if !Enabled {
  40. return NilResettingTimer{}
  41. }
  42. return &StandardResettingTimer{
  43. values: make([]int64, 0, InitialResettingTimerSliceCap),
  44. }
  45. }
  46. // NilResettingTimer is a no-op ResettingTimer.
  47. type NilResettingTimer struct {
  48. }
  49. // Values is a no-op.
  50. func (NilResettingTimer) Values() []int64 { return nil }
  51. // Snapshot is a no-op.
  52. func (NilResettingTimer) Snapshot() ResettingTimer {
  53. return &ResettingTimerSnapshot{
  54. values: []int64{},
  55. }
  56. }
  57. // Time is a no-op.
  58. func (NilResettingTimer) Time(func()) {}
  59. // Update is a no-op.
  60. func (NilResettingTimer) Update(time.Duration) {}
  61. // Percentiles panics.
  62. func (NilResettingTimer) Percentiles([]float64) []int64 {
  63. panic("Percentiles called on a NilResettingTimer")
  64. }
  65. // Mean panics.
  66. func (NilResettingTimer) Mean() float64 {
  67. panic("Mean called on a NilResettingTimer")
  68. }
  69. // UpdateSince is a no-op.
  70. func (NilResettingTimer) UpdateSince(time.Time) {}
  71. // StandardResettingTimer is the standard implementation of a ResettingTimer.
  72. // and Meter.
  73. type StandardResettingTimer struct {
  74. values []int64
  75. mutex sync.Mutex
  76. }
  77. // Values returns a slice with all measurements.
  78. func (t *StandardResettingTimer) Values() []int64 {
  79. return t.values
  80. }
  81. // Snapshot resets the timer and returns a read-only copy of its contents.
  82. func (t *StandardResettingTimer) Snapshot() ResettingTimer {
  83. t.mutex.Lock()
  84. defer t.mutex.Unlock()
  85. currentValues := t.values
  86. t.values = make([]int64, 0, InitialResettingTimerSliceCap)
  87. return &ResettingTimerSnapshot{
  88. values: currentValues,
  89. }
  90. }
  91. // Percentiles panics.
  92. func (t *StandardResettingTimer) Percentiles([]float64) []int64 {
  93. panic("Percentiles called on a StandardResettingTimer")
  94. }
  95. // Mean panics.
  96. func (t *StandardResettingTimer) Mean() float64 {
  97. panic("Mean called on a StandardResettingTimer")
  98. }
  99. // Record the duration of the execution of the given function.
  100. func (t *StandardResettingTimer) Time(f func()) {
  101. ts := time.Now()
  102. f()
  103. t.Update(time.Since(ts))
  104. }
  105. // Record the duration of an event.
  106. func (t *StandardResettingTimer) Update(d time.Duration) {
  107. t.mutex.Lock()
  108. defer t.mutex.Unlock()
  109. t.values = append(t.values, int64(d))
  110. }
  111. // Record the duration of an event that started at a time and ends now.
  112. func (t *StandardResettingTimer) UpdateSince(ts time.Time) {
  113. t.mutex.Lock()
  114. defer t.mutex.Unlock()
  115. t.values = append(t.values, int64(time.Since(ts)))
  116. }
  117. // ResettingTimerSnapshot is a point-in-time copy of another ResettingTimer.
  118. type ResettingTimerSnapshot struct {
  119. values []int64
  120. mean float64
  121. thresholdBoundaries []int64
  122. calculated bool
  123. }
  124. // Snapshot returns the snapshot.
  125. func (t *ResettingTimerSnapshot) Snapshot() ResettingTimer { return t }
  126. // Time panics.
  127. func (*ResettingTimerSnapshot) Time(func()) {
  128. panic("Time called on a ResettingTimerSnapshot")
  129. }
  130. // Update panics.
  131. func (*ResettingTimerSnapshot) Update(time.Duration) {
  132. panic("Update called on a ResettingTimerSnapshot")
  133. }
  134. // UpdateSince panics.
  135. func (*ResettingTimerSnapshot) UpdateSince(time.Time) {
  136. panic("UpdateSince called on a ResettingTimerSnapshot")
  137. }
  138. // Values returns all values from snapshot.
  139. func (t *ResettingTimerSnapshot) Values() []int64 {
  140. return t.values
  141. }
  142. // Percentiles returns the boundaries for the input percentiles.
  143. func (t *ResettingTimerSnapshot) Percentiles(percentiles []float64) []int64 {
  144. t.calc(percentiles)
  145. return t.thresholdBoundaries
  146. }
  147. // Mean returns the mean of the snapshotted values
  148. func (t *ResettingTimerSnapshot) Mean() float64 {
  149. if !t.calculated {
  150. t.calc([]float64{})
  151. }
  152. return t.mean
  153. }
  154. func (t *ResettingTimerSnapshot) calc(percentiles []float64) {
  155. sort.Sort(Int64Slice(t.values))
  156. count := len(t.values)
  157. if count > 0 {
  158. min := t.values[0]
  159. max := t.values[count-1]
  160. cumulativeValues := make([]int64, count)
  161. cumulativeValues[0] = min
  162. for i := 1; i < count; i++ {
  163. cumulativeValues[i] = t.values[i] + cumulativeValues[i-1]
  164. }
  165. t.thresholdBoundaries = make([]int64, len(percentiles))
  166. thresholdBoundary := max
  167. for i, pct := range percentiles {
  168. if count > 1 {
  169. var abs float64
  170. if pct >= 0 {
  171. abs = pct
  172. } else {
  173. abs = 100 + pct
  174. }
  175. // poor man's math.Round(x):
  176. // math.Floor(x + 0.5)
  177. indexOfPerc := int(math.Floor(((abs / 100.0) * float64(count)) + 0.5))
  178. if pct >= 0 && indexOfPerc > 0 {
  179. indexOfPerc -= 1 // index offset=0
  180. }
  181. thresholdBoundary = t.values[indexOfPerc]
  182. }
  183. t.thresholdBoundaries[i] = thresholdBoundary
  184. }
  185. sum := cumulativeValues[count-1]
  186. t.mean = float64(sum) / float64(count)
  187. } else {
  188. t.thresholdBoundaries = make([]int64, len(percentiles))
  189. t.mean = 0
  190. }
  191. t.calculated = true
  192. }
  193. // Int64Slice attaches the methods of sort.Interface to []int64, sorting in increasing order.
  194. type Int64Slice []int64
  195. func (s Int64Slice) Len() int { return len(s) }
  196. func (s Int64Slice) Less(i, j int) bool { return s[i] < s[j] }
  197. func (s Int64Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }