@@ -2,6 +2,7 @@ package hypercache
22
33import (
44 "context"
5+ "log/slog"
56 "time"
67
78 "github.com/hyp3rd/sectools/pkg/converters"
@@ -61,6 +62,13 @@ func (hyperCache *HyperCache[T]) startEvictionRoutine(ctx context.Context) {
6162 return
6263 }
6364
65+ hyperCache .logger .Info (
66+ "eviction loop starting" ,
67+ slog .Duration ("interval" , hyperCache .evictionInterval ),
68+ slog .Int ("max_per_tick" , int (hyperCache .maxEvictionCount )),
69+ slog .String ("algorithm" , hyperCache .evictionAlgorithmName ),
70+ )
71+
6472 tick := time .NewTicker (hyperCache .evictionInterval )
6573
6674 go func () {
@@ -70,11 +78,13 @@ func (hyperCache *HyperCache[T]) startEvictionRoutine(ctx context.Context) {
7078 hyperCache .evictionLoop (ctx )
7179 case <- ctx .Done ():
7280 tick .Stop ()
81+ hyperCache .logger .Info ("eviction loop stopped" , slog .String ("reason" , "context_canceled" ))
7382
7483 return
7584
7685 case <- hyperCache .stop :
7786 tick .Stop ()
87+ hyperCache .logger .Info ("eviction loop stopped" , slog .String ("reason" , "stop_signal" ))
7888
7989 return
8090 }
@@ -89,6 +99,9 @@ func (hyperCache *HyperCache[T]) evictionLoop(ctx context.Context) {
8999 // Enqueue the eviction loop in the worker pool to avoid blocking the main goroutine if the eviction loop is slow
90100 hyperCache .workerPool .Enqueue (func () error {
91101 hyperCache .StatsCollector .Incr ("eviction_loop_count" , 1 )
102+
103+ start := time .Now ()
104+
92105 defer hyperCache .StatsCollector .Timing ("eviction_loop_duration" , time .Now ().UnixNano ())
93106
94107 var evictedCount uint
@@ -133,10 +146,35 @@ func (hyperCache *HyperCache[T]) evictionLoop(ctx context.Context) {
133146
134147 hyperCache .StatsCollector .Gauge ("evicted_item_count" , evictedCount64 )
135148
149+ hyperCache .logEvictionTick (evictedCount , itemCount , time .Since (start ))
150+
136151 return nil
137152 })
138153}
139154
155+ // logEvictionTick emits a single-line tick log so operators can grep
156+ // for `eviction tick`. Info when items were evicted, Debug for idle
157+ // ticks — the metric counters cover the idle case so we don't drown
158+ // logs in noise.
159+ func (hyperCache * HyperCache [T ]) logEvictionTick (evicted uint , remaining int64 , elapsed time.Duration ) {
160+ if evicted > 0 {
161+ hyperCache .logger .Info (
162+ "eviction tick" ,
163+ slog .Uint64 ("evicted" , uint64 (evicted )),
164+ slog .Int64 ("items_remaining" , remaining ),
165+ slog .Duration ("elapsed" , elapsed ),
166+ )
167+
168+ return
169+ }
170+
171+ hyperCache .logger .Debug (
172+ "eviction tick (idle)" ,
173+ slog .Int64 ("items" , remaining ),
174+ slog .Duration ("elapsed" , elapsed ),
175+ )
176+ }
177+
140178// evictItem is a helper function that removes an item from the cache and returns the key of the evicted item.
141179// If no item can be evicted, it returns a false.
142180func (hyperCache * HyperCache [T ]) evictItem (ctx context.Context ) (string , bool ) {
@@ -177,6 +215,11 @@ func (hyperCache *HyperCache[T]) TriggerEviction(_ context.Context) {
177215
178216 select {
179217 case hyperCache .evictCh <- true :
218+ hyperCache .logger .Info ("eviction triggered" , slog .String ("source" , "manual" ))
180219 default :
220+ // Trigger channel full; previous trigger already in-flight.
221+ // Log at debug — the coalesced trigger is intentional, not
222+ // an error worth waking the operator over.
223+ hyperCache .logger .Debug ("eviction trigger coalesced (already pending)" )
181224 }
182225}
0 commit comments