dynpatch-core 0.1.0

Runtime engine for dynpatch - dynamic library loading, ABI validation, and transactional patching
Documentation
//! Metrics and observability for patch operations

use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;

/// Metrics collector for patch operations
#[derive(Debug, Clone)]
pub struct PatchMetrics {
    loads_attempted: Arc<AtomicU64>,
    loads_successful: Arc<AtomicU64>,
    loads_failed: Arc<AtomicU64>,
    rollbacks: Arc<AtomicU64>,
    validation_failures: Arc<AtomicU64>,
}

impl Default for PatchMetrics {
    fn default() -> Self {
        Self::new()
    }
}

impl PatchMetrics {
    pub fn new() -> Self {
        Self {
            loads_attempted: Arc::new(AtomicU64::new(0)),
            loads_successful: Arc::new(AtomicU64::new(0)),
            loads_failed: Arc::new(AtomicU64::new(0)),
            rollbacks: Arc::new(AtomicU64::new(0)),
            validation_failures: Arc::new(AtomicU64::new(0)),
        }
    }

    pub fn record_load_attempt(&self) {
        self.loads_attempted.fetch_add(1, Ordering::Relaxed);
    }

    pub fn record_load_success(&self) {
        self.loads_successful.fetch_add(1, Ordering::Relaxed);
    }

    pub fn record_load_failure(&self) {
        self.loads_failed.fetch_add(1, Ordering::Relaxed);
    }

    pub fn record_rollback(&self) {
        self.rollbacks.fetch_add(1, Ordering::Relaxed);
    }

    pub fn record_validation_failure(&self) {
        self.validation_failures.fetch_add(1, Ordering::Relaxed);
    }

    pub fn loads_attempted(&self) -> u64 {
        self.loads_attempted.load(Ordering::Relaxed)
    }

    pub fn loads_successful(&self) -> u64 {
        self.loads_successful.load(Ordering::Relaxed)
    }

    pub fn loads_failed(&self) -> u64 {
        self.loads_failed.load(Ordering::Relaxed)
    }

    pub fn rollbacks(&self) -> u64 {
        self.rollbacks.load(Ordering::Relaxed)
    }

    pub fn validation_failures(&self) -> u64 {
        self.validation_failures.load(Ordering::Relaxed)
    }

    pub fn reset(&self) {
        self.loads_attempted.store(0, Ordering::Relaxed);
        self.loads_successful.store(0, Ordering::Relaxed);
        self.loads_failed.store(0, Ordering::Relaxed);
        self.rollbacks.store(0, Ordering::Relaxed);
        self.validation_failures.store(0, Ordering::Relaxed);
    }
}

// Global metrics instance
static GLOBAL_METRICS: once_cell::sync::Lazy<PatchMetrics> =
    once_cell::sync::Lazy::new(PatchMetrics::new);

/// Get the global metrics instance
pub fn global_metrics() -> &'static PatchMetrics {
    &GLOBAL_METRICS
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_metrics() {
        let metrics = PatchMetrics::new();
        
        assert_eq!(metrics.loads_attempted(), 0);
        
        metrics.record_load_attempt();
        assert_eq!(metrics.loads_attempted(), 1);
        
        metrics.record_load_success();
        assert_eq!(metrics.loads_successful(), 1);
        
        metrics.reset();
        assert_eq!(metrics.loads_attempted(), 0);
        assert_eq!(metrics.loads_successful(), 0);
    }
}