diff --git a/cache.go b/cache.go index b1451bb..e7ec49d 100644 --- a/cache.go +++ b/cache.go @@ -8,8 +8,105 @@ import ( "runtime" "sync" "time" + + "github.com/prometheus/client_golang/prometheus" ) +var ( + cacheItem = prometheus.NewGauge( + prometheus.GaugeOpts{ + Namespace: "go", + Subsystem: "cache", + Name: "set", + Help: "Current number of cached items", + }, + ) + + cacheAddTotal = prometheus.NewCounter( + prometheus.CounterOpts{ + Namespace: "go", + Subsystem: "cache", + Name: "add_total", + Help: "Total number of add operations", + }, + ) + + cacheDecrementTotal = prometheus.NewCounter( + prometheus.CounterOpts{ + Namespace: "go", + Subsystem: "cache", + Name: "decrement_total", + Help: "Total number of decrement operations", + }, + ) + + cacheDeleteTotal = prometheus.NewCounter( + prometheus.CounterOpts{ + Namespace: "go", + Subsystem: "cache", + Name: "delete_total", + Help: "Total number of delete operations", + }, + ) + + cacheFlushTotal = prometheus.NewCounter( + prometheus.CounterOpts{ + Namespace: "go", + Subsystem: "cache", + Name: "flush_total", + Help: "Total number of flush operations", + }, + ) + + cacheIncrementTotal = prometheus.NewCounter( + prometheus.CounterOpts{ + Namespace: "go", + Subsystem: "cache", + Name: "increment_total", + Help: "Total number of increment operations", + }, + ) + + cacheReplaceTotal = prometheus.NewCounter( + prometheus.CounterOpts{ + Namespace: "go", + Subsystem: "cache", + Name: "replace_total", + Help: "Total number of replace operations", + }, + ) + + cacheSetTotal = prometheus.NewCounter( + prometheus.CounterOpts{ + Namespace: "go", + Subsystem: "cache", + Name: "set_total", + Help: "Total number of set operations", + }, + ) + + cacheJanitorLastRun = prometheus.NewGauge( + prometheus.GaugeOpts{ + Namespace: "go", + Subsystem: "cache", + Name: "janitor_last_run", + Help: "Timestamp of last janitor run", + }, + ) +) + +func init() { + prometheus.MustRegister(cacheItem) + prometheus.MustRegister(cacheAddTotal) + prometheus.MustRegister(cacheDecrementTotal) + prometheus.MustRegister(cacheDeleteTotal) + prometheus.MustRegister(cacheFlushTotal) + prometheus.MustRegister(cacheIncrementTotal) + prometheus.MustRegister(cacheReplaceTotal) + prometheus.MustRegister(cacheSetTotal) + prometheus.MustRegister(cacheJanitorLastRun) +} + type Item struct { Object interface{} Expiration int64 @@ -65,6 +162,8 @@ func (c *cache) Set(k string, x interface{}, d time.Duration) { // TODO: Calls to mu.Unlock are currently not deferred because defer // adds ~200 ns (as of go1.) c.mu.Unlock() + cacheItem.Inc() + cacheSetTotal.Inc() } func (c *cache) set(k string, x interface{}, d time.Duration) { @@ -91,13 +190,17 @@ func (c *cache) SetDefault(k string, x interface{}) { // key, or if the existing item has expired. Returns an error otherwise. func (c *cache) Add(k string, x interface{}, d time.Duration) error { c.mu.Lock() - _, found := c.get(k) + ov, found := c.get(k) if found { c.mu.Unlock() return fmt.Errorf("Item %s already exists", k) } c.set(k, x, d) c.mu.Unlock() + if ov == nil { + cacheItem.Inc() + } + cacheAddTotal.Inc() return nil } @@ -112,6 +215,7 @@ func (c *cache) Replace(k string, x interface{}, d time.Duration) error { } c.set(k, x, d) c.mu.Unlock() + cacheReplaceTotal.Inc() return nil } @@ -228,6 +332,7 @@ func (c *cache) Increment(k string, n int64) error { } c.items[k] = v c.mu.Unlock() + cacheIncrementTotal.Inc() return nil } @@ -254,6 +359,7 @@ func (c *cache) IncrementFloat(k string, n float64) error { } c.items[k] = v c.mu.Unlock() + cacheIncrementTotal.Inc() return nil } @@ -276,6 +382,7 @@ func (c *cache) IncrementInt(k string, n int) (int, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheIncrementTotal.Inc() return nv, nil } @@ -298,6 +405,7 @@ func (c *cache) IncrementInt8(k string, n int8) (int8, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheIncrementTotal.Inc() return nv, nil } @@ -320,6 +428,7 @@ func (c *cache) IncrementInt16(k string, n int16) (int16, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheIncrementTotal.Inc() return nv, nil } @@ -342,6 +451,7 @@ func (c *cache) IncrementInt32(k string, n int32) (int32, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheIncrementTotal.Inc() return nv, nil } @@ -364,6 +474,7 @@ func (c *cache) IncrementInt64(k string, n int64) (int64, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheIncrementTotal.Inc() return nv, nil } @@ -386,6 +497,7 @@ func (c *cache) IncrementUint(k string, n uint) (uint, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheIncrementTotal.Inc() return nv, nil } @@ -408,6 +520,7 @@ func (c *cache) IncrementUintptr(k string, n uintptr) (uintptr, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheIncrementTotal.Inc() return nv, nil } @@ -430,6 +543,7 @@ func (c *cache) IncrementUint8(k string, n uint8) (uint8, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheIncrementTotal.Inc() return nv, nil } @@ -452,6 +566,7 @@ func (c *cache) IncrementUint16(k string, n uint16) (uint16, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheIncrementTotal.Inc() return nv, nil } @@ -474,6 +589,7 @@ func (c *cache) IncrementUint32(k string, n uint32) (uint32, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheIncrementTotal.Inc() return nv, nil } @@ -496,6 +612,7 @@ func (c *cache) IncrementUint64(k string, n uint64) (uint64, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheIncrementTotal.Inc() return nv, nil } @@ -518,6 +635,7 @@ func (c *cache) IncrementFloat32(k string, n float32) (float32, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheIncrementTotal.Inc() return nv, nil } @@ -540,6 +658,7 @@ func (c *cache) IncrementFloat64(k string, n float64) (float64, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheIncrementTotal.Inc() return nv, nil } @@ -590,6 +709,7 @@ func (c *cache) Decrement(k string, n int64) error { } c.items[k] = v c.mu.Unlock() + cacheDecrementTotal.Inc() return nil } @@ -616,6 +736,7 @@ func (c *cache) DecrementFloat(k string, n float64) error { } c.items[k] = v c.mu.Unlock() + cacheDecrementTotal.Inc() return nil } @@ -638,6 +759,7 @@ func (c *cache) DecrementInt(k string, n int) (int, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheDecrementTotal.Inc() return nv, nil } @@ -660,6 +782,7 @@ func (c *cache) DecrementInt8(k string, n int8) (int8, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheDecrementTotal.Inc() return nv, nil } @@ -682,6 +805,7 @@ func (c *cache) DecrementInt16(k string, n int16) (int16, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheDecrementTotal.Inc() return nv, nil } @@ -704,6 +828,7 @@ func (c *cache) DecrementInt32(k string, n int32) (int32, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheDecrementTotal.Inc() return nv, nil } @@ -726,6 +851,7 @@ func (c *cache) DecrementInt64(k string, n int64) (int64, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheDecrementTotal.Inc() return nv, nil } @@ -748,6 +874,7 @@ func (c *cache) DecrementUint(k string, n uint) (uint, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheDecrementTotal.Inc() return nv, nil } @@ -770,6 +897,7 @@ func (c *cache) DecrementUintptr(k string, n uintptr) (uintptr, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheDecrementTotal.Inc() return nv, nil } @@ -792,6 +920,7 @@ func (c *cache) DecrementUint8(k string, n uint8) (uint8, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheDecrementTotal.Inc() return nv, nil } @@ -814,6 +943,7 @@ func (c *cache) DecrementUint16(k string, n uint16) (uint16, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheDecrementTotal.Inc() return nv, nil } @@ -836,6 +966,7 @@ func (c *cache) DecrementUint32(k string, n uint32) (uint32, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheDecrementTotal.Inc() return nv, nil } @@ -858,6 +989,7 @@ func (c *cache) DecrementUint64(k string, n uint64) (uint64, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheDecrementTotal.Inc() return nv, nil } @@ -880,6 +1012,7 @@ func (c *cache) DecrementFloat32(k string, n float32) (float32, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheDecrementTotal.Inc() return nv, nil } @@ -902,6 +1035,7 @@ func (c *cache) DecrementFloat64(k string, n float64) (float64, error) { v.Object = nv c.items[k] = v c.mu.Unlock() + cacheDecrementTotal.Inc() return nv, nil } @@ -916,13 +1050,15 @@ func (c *cache) Delete(k string) { } func (c *cache) delete(k string) (interface{}, bool) { - var ret interface{} = nil var found = false + var ret interface{} if v, ok := c.items[k]; ok { found = true ret = v.Object delete(c.items, k) + cacheItem.Dec() + cacheDeleteTotal.Inc() } return ret, found @@ -1013,9 +1149,13 @@ func (c *cache) Load(r io.Reader) error { c.mu.Lock() defer c.mu.Unlock() for k, v := range items { - ov, found := c.items[k] - if !found || ov.Expired() { + ov, found := c.get(k) + if !found { c.items[k] = v + + if ov == nil { + cacheItem.Inc() + } } } } @@ -1070,8 +1210,10 @@ func (c *cache) ItemCount() int { // Delete all items from the cache. func (c *cache) Flush() { c.mu.Lock() + cacheItem.Sub(float64(len(c.items))) c.items = map[string]Item{} c.mu.Unlock() + cacheFlushTotal.Inc() } type janitor struct { @@ -1084,6 +1226,7 @@ func (j *janitor) Run(c *cache) { for { select { case <-ticker.C: + cacheJanitorLastRun.Set(float64(time.Now().Unix())) c.DeleteExpired() case <-j.stop: ticker.Stop() @@ -1113,6 +1256,7 @@ func newCache(de time.Duration, m map[string]Item) *cache { defaultExpiration: de, items: m, } + cacheItem.Add(float64(len(m))) return c } diff --git a/cache_test.go b/cache_test.go index cb80b38..1aa9f53 100644 --- a/cache_test.go +++ b/cache_test.go @@ -3,13 +3,21 @@ package cache import ( "bytes" "io/ioutil" + "net/http" "runtime" "strconv" "sync" "testing" "time" + + "github.com/prometheus/client_golang/prometheus/promhttp" ) +func init() { + http.Handle("/metrics", promhttp.Handler()) + go http.ListenAndServe("localhost:9000", nil) +} + type TestStruct struct { Num int Children []*TestStruct