use super::{CompressionAlgorithm, CompressionStats};
use prometheus::{
register_histogram_vec, register_int_counter_vec, register_int_gauge_vec, HistogramVec,
IntCounterVec, IntGaugeVec,
};
use std::sync::Arc;
use tracing::{debug, info};
lazy_static::lazy_static! {
static ref COMPRESSION_OPERATIONS: IntCounterVec = register_int_counter_vec!(
"compression_operations_total",
"Total number of compression operations",
&["algorithm", "operation", "status"]
)
.unwrap();
static ref COMPRESSION_RATIO: HistogramVec = register_histogram_vec!(
"compression_ratio",
"Compression ratio (compressed/original)",
&["algorithm"],
vec![0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
)
.unwrap();
static ref COMPRESSION_DURATION: HistogramVec = register_histogram_vec!(
"compression_duration_milliseconds",
"Compression duration in milliseconds",
&["algorithm", "operation"],
vec![0.1, 0.5, 1.0, 2.5, 5.0, 10.0, 25.0, 50.0, 100.0, 250.0, 500.0, 1000.0]
)
.unwrap();
static ref BYTES_PROCESSED: IntCounterVec = register_int_counter_vec!(
"compression_bytes_processed_total",
"Total bytes processed",
&["algorithm", "type"]
)
.unwrap();
static ref BYTES_SAVED: IntGaugeVec = register_int_gauge_vec!(
"compression_bytes_saved",
"Bytes saved by compression",
&["algorithm"]
)
.unwrap();
}
#[derive(Debug, Clone)]
pub struct CompressionMetrics {
enabled: bool,
}
impl CompressionMetrics {
pub fn new(enabled: bool) -> Self {
Self { enabled }
}
pub fn record_compression(&self, stats: &CompressionStats) {
if !self.enabled {
return;
}
let algorithm = stats
.algorithm
.map(|a| a.as_str())
.unwrap_or("unknown");
COMPRESSION_OPERATIONS
.with_label_values(&[algorithm, "compress", "success"])
.inc();
COMPRESSION_RATIO
.with_label_values(&[algorithm])
.observe(stats.compression_ratio);
COMPRESSION_DURATION
.with_label_values(&[algorithm, "compress"])
.observe(stats.duration_ms);
BYTES_PROCESSED
.with_label_values(&[algorithm, "original"])
.inc_by(stats.original_size as u64);
BYTES_PROCESSED
.with_label_values(&[algorithm, "compressed"])
.inc_by(stats.compressed_size as u64);
BYTES_SAVED
.with_label_values(&[algorithm])
.add(stats.bytes_saved as i64);
debug!(
algorithm = algorithm,
original_size = stats.original_size,
compressed_size = stats.compressed_size,
ratio = stats.compression_ratio,
duration_ms = stats.duration_ms,
"Compression completed"
);
if stats.bytes_saved > 10_000 {
info!(
algorithm = algorithm,
bytes_saved = stats.bytes_saved,
compression_pct = stats.compression_percentage(),
"Significant compression achieved"
);
}
}
pub fn record_decompression(&self, stats: &CompressionStats) {
if !self.enabled {
return;
}
let algorithm = stats
.algorithm
.map(|a| a.as_str())
.unwrap_or("unknown");
COMPRESSION_OPERATIONS
.with_label_values(&[algorithm, "decompress", "success"])
.inc();
COMPRESSION_DURATION
.with_label_values(&[algorithm, "decompress"])
.observe(stats.duration_ms);
debug!(
algorithm = algorithm,
compressed_size = stats.compressed_size,
decompressed_size = stats.original_size,
duration_ms = stats.duration_ms,
"Decompression completed"
);
}
pub fn record_error(&self, algorithm: Option<CompressionAlgorithm>, operation: &str) {
if !self.enabled {
return;
}
let algorithm = algorithm
.map(|a| a.as_str())
.unwrap_or("unknown");
COMPRESSION_OPERATIONS
.with_label_values(&[algorithm, operation, "error"])
.inc();
}
}
impl Default for CompressionMetrics {
fn default() -> Self {
Self::new(true)
}
}
static GLOBAL_METRICS: once_cell::sync::Lazy<Arc<CompressionMetrics>> =
once_cell::sync::Lazy::new(|| Arc::new(CompressionMetrics::default()));
pub fn get_metrics() -> Arc<CompressionMetrics> {
GLOBAL_METRICS.clone()
}
pub fn init_compression_metrics(enabled: bool) -> Arc<CompressionMetrics> {
Arc::new(CompressionMetrics::new(enabled))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_compression_metrics_creation() {
let metrics = CompressionMetrics::new(true);
assert!(metrics.enabled);
let metrics = CompressionMetrics::new(false);
assert!(!metrics.enabled);
}
#[test]
fn test_record_compression() {
let metrics = CompressionMetrics::new(true);
let stats = CompressionStats::new(1000, 300, CompressionAlgorithm::Gzip, 10.5);
metrics.record_compression(&stats);
}
#[test]
fn test_record_decompression() {
let metrics = CompressionMetrics::new(true);
let stats = CompressionStats::new(1000, 300, CompressionAlgorithm::Gzip, 5.0);
metrics.record_decompression(&stats);
}
#[test]
fn test_record_error() {
let metrics = CompressionMetrics::new(true);
metrics.record_error(Some(CompressionAlgorithm::Gzip), "compress");
}
#[test]
fn test_disabled_metrics() {
let metrics = CompressionMetrics::new(false);
let stats = CompressionStats::new(1000, 300, CompressionAlgorithm::Gzip, 10.5);
metrics.record_compression(&stats);
metrics.record_decompression(&stats);
metrics.record_error(Some(CompressionAlgorithm::Gzip), "compress");
}
#[test]
fn test_get_metrics() {
let metrics = get_metrics();
assert!(metrics.enabled);
}
}