github.com/deanMdreon/kafka-go@v0.4.32/stats.go (about)

     1  package kafka
     2  
     3  import (
     4  	"sync/atomic"
     5  	"time"
     6  )
     7  
     8  // SummaryStats is a data structure that carries a summary of observed values.
     9  // The average, minimum, and maximum are reported.
    10  type SummaryStats struct {
    11  	Avg int64 `metric:"avg" type:"gauge"`
    12  	Min int64 `metric:"min" type:"gauge"`
    13  	Max int64 `metric:"max" type:"gauge"`
    14  }
    15  
    16  // DurationStats is a data structure that carries a summary of observed duration
    17  // values. The average, minimum, and maximum are reported.
    18  type DurationStats struct {
    19  	Avg time.Duration `metric:"avg" type:"gauge"`
    20  	Min time.Duration `metric:"min" type:"gauge"`
    21  	Max time.Duration `metric:"max" type:"gauge"`
    22  }
    23  
    24  // counter is an atomic incrementing counter which gets reset on snapshot.
    25  //
    26  // Since atomic is used to mutate the statistic the value must be 64-bit aligned.
    27  // See https://golang.org/pkg/sync/atomic/#pkg-note-BUG
    28  type counter int64
    29  
    30  func (c *counter) ptr() *int64 {
    31  	return (*int64)(c)
    32  }
    33  
    34  func (c *counter) observe(v int64) {
    35  	atomic.AddInt64(c.ptr(), v)
    36  }
    37  
    38  func (c *counter) snapshot() int64 {
    39  	return atomic.SwapInt64(c.ptr(), 0)
    40  }
    41  
    42  // gauge is an atomic integer that may be set to any arbitrary value, the value
    43  // does not change after a snapshot.
    44  //
    45  // Since atomic is used to mutate the statistic the value must be 64-bit aligned.
    46  // See https://golang.org/pkg/sync/atomic/#pkg-note-BUG
    47  type gauge int64
    48  
    49  func (g *gauge) ptr() *int64 {
    50  	return (*int64)(g)
    51  }
    52  
    53  func (g *gauge) observe(v int64) {
    54  	atomic.StoreInt64(g.ptr(), v)
    55  }
    56  
    57  func (g *gauge) snapshot() int64 {
    58  	return atomic.LoadInt64(g.ptr())
    59  }
    60  
    61  // minimum is an atomic integral type that keeps track of the minimum of all
    62  // values that it observed between snapshots.
    63  //
    64  // Since atomic is used to mutate the statistic the value must be 64-bit aligned.
    65  // See https://golang.org/pkg/sync/atomic/#pkg-note-BUG
    66  type minimum int64
    67  
    68  func (m *minimum) ptr() *int64 {
    69  	return (*int64)(m)
    70  }
    71  
    72  func (m *minimum) observe(v int64) {
    73  	for {
    74  		ptr := m.ptr()
    75  		min := atomic.LoadInt64(ptr)
    76  
    77  		if min >= 0 && min <= v {
    78  			break
    79  		}
    80  
    81  		if atomic.CompareAndSwapInt64(ptr, min, v) {
    82  			break
    83  		}
    84  	}
    85  }
    86  
    87  func (m *minimum) snapshot() int64 {
    88  	p := m.ptr()
    89  	v := atomic.LoadInt64(p)
    90  	atomic.CompareAndSwapInt64(p, v, -1)
    91  	if v < 0 {
    92  		v = 0
    93  	}
    94  	return v
    95  }
    96  
    97  // maximum is an atomic integral type that keeps track of the maximum of all
    98  // values that it observed between snapshots.
    99  //
   100  // Since atomic is used to mutate the statistic the value must be 64-bit aligned.
   101  // See https://golang.org/pkg/sync/atomic/#pkg-note-BUG
   102  type maximum int64
   103  
   104  func (m *maximum) ptr() *int64 {
   105  	return (*int64)(m)
   106  }
   107  
   108  func (m *maximum) observe(v int64) {
   109  	for {
   110  		ptr := m.ptr()
   111  		max := atomic.LoadInt64(ptr)
   112  
   113  		if max >= 0 && max >= v {
   114  			break
   115  		}
   116  
   117  		if atomic.CompareAndSwapInt64(ptr, max, v) {
   118  			break
   119  		}
   120  	}
   121  }
   122  
   123  func (m *maximum) snapshot() int64 {
   124  	p := m.ptr()
   125  	v := atomic.LoadInt64(p)
   126  	atomic.CompareAndSwapInt64(p, v, -1)
   127  	if v < 0 {
   128  		v = 0
   129  	}
   130  	return v
   131  }
   132  
   133  type summary struct {
   134  	min   minimum
   135  	max   maximum
   136  	sum   counter
   137  	count counter
   138  }
   139  
   140  func makeSummary() summary {
   141  	return summary{
   142  		min: -1,
   143  		max: -1,
   144  	}
   145  }
   146  
   147  func (s *summary) observe(v int64) {
   148  	s.min.observe(v)
   149  	s.max.observe(v)
   150  	s.sum.observe(v)
   151  	s.count.observe(1)
   152  }
   153  
   154  func (s *summary) observeDuration(v time.Duration) {
   155  	s.observe(int64(v))
   156  }
   157  
   158  func (s *summary) snapshot() SummaryStats {
   159  	avg := int64(0)
   160  	min := s.min.snapshot()
   161  	max := s.max.snapshot()
   162  	sum := s.sum.snapshot()
   163  	count := s.count.snapshot()
   164  
   165  	if count != 0 {
   166  		avg = int64(float64(sum) / float64(count))
   167  	}
   168  
   169  	return SummaryStats{
   170  		Avg: avg,
   171  		Min: min,
   172  		Max: max,
   173  	}
   174  }
   175  
   176  func (s *summary) snapshotDuration() DurationStats {
   177  	summary := s.snapshot()
   178  	return DurationStats{
   179  		Avg: time.Duration(summary.Avg),
   180  		Min: time.Duration(summary.Min),
   181  		Max: time.Duration(summary.Max),
   182  	}
   183  }