github.com/psiphon-inc/goarista@v0.0.0-20160825065156-d002785f4c67/monitor/stats/counter.go (about)

     1  package stats
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  )
     7  
     8  var (
     9  	// TimeNow is used for testing.
    10  	TimeNow = time.Now
    11  )
    12  
    13  const (
    14  	hour       = 0
    15  	tenminutes = 1
    16  	minute     = 2
    17  )
    18  
    19  // Counter is a counter that keeps track of its recent values over a given
    20  // period of time, and with a given resolution. Use newCounter() to instantiate.
    21  type Counter struct {
    22  	mu         sync.RWMutex
    23  	ts         [3]*timeseries
    24  	lastUpdate time.Time
    25  }
    26  
    27  // newCounter returns a new Counter.
    28  func newCounter() *Counter {
    29  	now := TimeNow()
    30  	c := &Counter{}
    31  	c.ts[hour] = newTimeSeries(now, time.Hour, time.Minute)
    32  	c.ts[tenminutes] = newTimeSeries(now, 10*time.Minute, 10*time.Second)
    33  	c.ts[minute] = newTimeSeries(now, time.Minute, time.Second)
    34  	return c
    35  }
    36  
    37  func (c *Counter) advance() time.Time {
    38  	now := TimeNow()
    39  	for _, ts := range c.ts {
    40  		ts.advanceTime(now)
    41  	}
    42  	return now
    43  }
    44  
    45  // Value returns the current value of the counter.
    46  func (c *Counter) Value() int64 {
    47  	c.mu.RLock()
    48  	defer c.mu.RUnlock()
    49  	return c.ts[minute].headValue()
    50  }
    51  
    52  // LastUpdate returns the last update time of the counter.
    53  func (c *Counter) LastUpdate() time.Time {
    54  	c.mu.RLock()
    55  	defer c.mu.RUnlock()
    56  	return c.lastUpdate
    57  }
    58  
    59  // Set updates the current value of the counter.
    60  func (c *Counter) Set(value int64) {
    61  	c.mu.Lock()
    62  	defer c.mu.Unlock()
    63  	c.lastUpdate = c.advance()
    64  	for _, ts := range c.ts {
    65  		ts.set(value)
    66  	}
    67  }
    68  
    69  // Incr increments the current value of the counter by 'delta'.
    70  func (c *Counter) Incr(delta int64) {
    71  	c.mu.Lock()
    72  	defer c.mu.Unlock()
    73  	c.lastUpdate = c.advance()
    74  	for _, ts := range c.ts {
    75  		ts.incr(delta)
    76  	}
    77  }
    78  
    79  // Delta1h returns the delta for the last hour.
    80  func (c *Counter) Delta1h() int64 {
    81  	c.mu.RLock()
    82  	defer c.mu.RUnlock()
    83  	c.advance()
    84  	return c.ts[hour].delta()
    85  }
    86  
    87  // Delta10m returns the delta for the last 10 minutes.
    88  func (c *Counter) Delta10m() int64 {
    89  	c.mu.RLock()
    90  	defer c.mu.RUnlock()
    91  	c.advance()
    92  	return c.ts[tenminutes].delta()
    93  }
    94  
    95  // Delta1m returns the delta for the last minute.
    96  func (c *Counter) Delta1m() int64 {
    97  	c.mu.RLock()
    98  	defer c.mu.RUnlock()
    99  	c.advance()
   100  	return c.ts[minute].delta()
   101  }
   102  
   103  // Rate1h returns the rate of change of the counter in the last hour.
   104  func (c *Counter) Rate1h() float64 {
   105  	c.mu.RLock()
   106  	defer c.mu.RUnlock()
   107  	c.advance()
   108  	return c.ts[hour].rate()
   109  }
   110  
   111  // Rate10m returns the rate of change of the counter in the last 10 minutes.
   112  func (c *Counter) Rate10m() float64 {
   113  	c.mu.RLock()
   114  	defer c.mu.RUnlock()
   115  	c.advance()
   116  	return c.ts[tenminutes].rate()
   117  }
   118  
   119  // Rate1m returns the rate of change of the counter in the last minute.
   120  func (c *Counter) Rate1m() float64 {
   121  	c.mu.RLock()
   122  	defer c.mu.RUnlock()
   123  	c.advance()
   124  	return c.ts[minute].rate()
   125  }
   126  
   127  // Reset resets the counter to an empty state.
   128  func (c *Counter) Reset() {
   129  	c.mu.Lock()
   130  	defer c.mu.Unlock()
   131  	now := TimeNow()
   132  	for _, ts := range c.ts {
   133  		ts.reset(now)
   134  	}
   135  }