Atomic Int64 Counter Metrics
Track hot counters with atomic operations instead of mutexes, exporting per-second rates and cumulative values for monitoring.
Code
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
)
type Counters struct {
requests atomic.Int64
errors atomic.Int64
bytes atomic.Int64
}
func (c *Counters) IncRequest() { c.requests.Add(1) }
func (c *Counters) IncError() { c.errors.Add(1) }
func (c *Counters) AddBytes(n int64) { c.bytes.Add(n) }
func (c *Counters) Snapshot() (req, errs, transferred int64) {
return c.requests.Load(), c.errors.Load(), c.bytes.Load()
}
type RateCalculator struct {
lastValue atomic.Int64
lastTime atomic.Int64
}
func (r *RateCalculator) Rate(now time.Time, current int64) float64 {
prevTime := r.lastTime.Load()
prevValue := r.lastValue.Load()
if prevTime == 0 {
r.lastTime.Store(now.Unix())
r.lastValue.Store(current)
return 0
}
elapsed := now.Unix() - prevTime
if elapsed <= 0 {
return 0
}
rate := float64(current-prevValue) / float64(elapsed)
r.lastTime.Store(now.Unix())
r.lastValue.Store(current)
return rate
}
func main() {
counters := new(Counters)
rate := new(RateCalculator)
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func(n int) {
defer wg.Done()
counters.IncRequest()
if n%50 == 0 {
counters.IncError() // 模拟约百分之二的错误率
}
counters.AddBytes(512)
}(i)
}
wg.Wait()
req, errs, transferred := counters.Snapshot()
fmt.Println(req, errs, transferred, rate.Rate(time.Now(), req))
}Report a problem with this exampleOpens a pre-filled issue on GitHub.