rs-zero 0.2.7

Rust-first microservice framework inspired by go-zero engineering practices
Documentation
use std::{
    collections::HashMap,
    sync::{Arc, Mutex},
};

/// Log sampling configuration.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SamplingConfig {
    /// Whether sampling is enabled.
    pub enabled: bool,
    /// Always log the first N occurrences for each key.
    pub first_n: u64,
    /// After `first_n`, log every Nth occurrence.
    pub thereafter: u64,
}

impl Default for SamplingConfig {
    fn default() -> Self {
        Self {
            enabled: false,
            first_n: 1,
            thereafter: 100,
        }
    }
}

/// In-memory deterministic log sampler keyed by low-cardinality fingerprints.
#[derive(Debug, Clone, Default)]
pub struct LogSampler {
    config: SamplingConfig,
    counts: Arc<Mutex<HashMap<String, u64>>>,
}

impl LogSampler {
    /// Creates a sampler.
    pub fn new(config: SamplingConfig) -> Self {
        Self {
            config,
            counts: Arc::new(Mutex::new(HashMap::new())),
        }
    }

    /// Returns whether a log for the key should be emitted.
    pub fn should_log(&self, key: &str) -> bool {
        if !self.config.enabled {
            return true;
        }
        let mut counts = self.counts.lock().expect("sampler mutex");
        let count = counts.entry(key.to_string()).or_default();
        *count += 1;
        if *count <= self.config.first_n {
            return true;
        }
        let thereafter = self.config.thereafter.max(1);
        (*count - self.config.first_n).is_multiple_of(thereafter)
    }
}