Statistics for metrics
yanns opened this issue · 3 comments
yanns commented
I'm wondering if we can expose metrics about a Cache
, like caffeine does.
Currently, it's difficult to observe the impact of tuning the cache size and the eviction policies.
tatsuya6502 commented
Hi. Currently Cache
does not provide built-in statistics. I tried to implement it a while ago but did not have time to finish it. I will try again in the future.
For now, please collect the statistics by yourself. Here is an example:
use std::sync::atomic::{AtomicU64, Ordering};
use moka::sync::Cache;
use once_cell::sync::Lazy;
fn main() {
// To record the number of evictions, create an eviction listener.
let listener = |_k, _v, cause| {
use moka::notification::RemovalCause;
// RemovalCause::Size means that the cache reached its maximum capacity
// and had to evict an entry.
//
// For other causes, please see:
// https://docs.rs/moka/*/moka/notification/enum.RemovalCause.html
if cause == RemovalCause::Size {
CACHE_STATS.record_eviction();
}
};
// Create a cache with the eviction listener.
let cache = Cache::builder()
.max_capacity(100)
.eviction_listener(listener)
.build();
// Insert 1000 entries into the cache with the max capacity of 100.
for i in 0..1000 {
get_or_insert(&cache, i % 250);
}
// For the sake of this example, we will call sync() to ensure that all
// pending tasks (e.g. evictions) are processed. In a real application, you
// do not have to call it as the Cache will periodically call it for you.
use moka::sync::ConcurrentCacheExt;
cache.sync();
println!("{:?}", *CACHE_STATS);
// => CacheStats { hits: 600, misses: 400, evictions: 300 }
}
fn get_or_insert(cache: &Cache<i32, i32>, key: i32) -> i32 {
let entry = cache.entry(key).or_insert_with(|| key);
if entry.is_fresh() {
// The entry was just inserted into the cache.
CACHE_STATS.record_miss();
} else {
// The entry was already in the cache.
CACHE_STATS.record_hit();
}
entry.into_value()
}
static CACHE_STATS: Lazy<CacheStats> = Lazy::new(CacheStats::default);
#[derive(Debug, Default)]
pub struct CacheStats {
hits: AtomicU64,
misses: AtomicU64,
evictions: AtomicU64,
}
impl CacheStats {
pub fn record_hit(&self) {
self.hits.fetch_add(1, Ordering::AcqRel);
}
pub fn record_miss(&self) {
self.misses.fetch_add(1, Ordering::AcqRel);
}
pub fn record_eviction(&self) {
self.evictions.fetch_add(1, Ordering::AcqRel);
}
}
yanns commented
thanks for the detailed info @tatsuya6502
This is very useful! ❤️
tatsuya6502 commented
I tried to implement it a while ago but did not have time to finish it. I will try again in the future.
I started to work on it via #262.