use ipfrs_network::metrics_aggregator::{AggregatorConfig, MetricsAggregator, TimeWindow};
use std::thread;
use std::time::Duration;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Metrics Time-Series Aggregation Demo ===\n");
println!("Scenario 1: Basic Metrics Recording");
println!("------------------------------------");
basic_metrics_recording()?;
println!();
println!("Scenario 2: Statistical Analysis");
println!("--------------------------------");
statistical_analysis()?;
println!();
println!("Scenario 3: Percentile Calculations");
println!("------------------------------------");
percentile_calculations()?;
println!();
println!("Scenario 4: Trend Analysis");
println!("--------------------------");
trend_analysis()?;
println!();
println!("Scenario 5: Different Time Windows");
println!("-----------------------------------");
time_windows()?;
println!();
println!("Scenario 6: Configuration Presets");
println!("----------------------------------");
configuration_presets()?;
println!();
println!("Scenario 7: Sampling and Retention");
println!("-----------------------------------");
sampling_and_retention()?;
println!();
println!("=== Demo Complete ===");
Ok(())
}
fn basic_metrics_recording() -> Result<(), Box<dyn std::error::Error>> {
let config = AggregatorConfig::default();
let aggregator = MetricsAggregator::new(config);
aggregator.record_bandwidth(1024);
aggregator.record_bandwidth(2048);
aggregator.record_bandwidth(1536);
aggregator.record_latency(50);
aggregator.record_latency(75);
aggregator.record_latency(60);
aggregator.record_connection_event();
aggregator.record_connection_event();
aggregator.record_query_event();
let stats = aggregator.get_statistics(TimeWindow::Minute);
println!("Bandwidth:");
println!(" Count: {}", stats.bandwidth.count);
println!(" Min: {} bytes", stats.bandwidth.min);
println!(" Max: {} bytes", stats.bandwidth.max);
println!(" Avg: {:.2} bytes", stats.bandwidth.avg);
println!("\nLatency:");
println!(" Count: {}", stats.latency.count);
println!(" Min: {} ms", stats.latency.min);
println!(" Max: {} ms", stats.latency.max);
println!(" Avg: {:.2} ms", stats.latency.avg);
println!("\nConnection Events: {}", stats.connection_rate.count);
println!("Query Events: {}", stats.query_rate.count);
Ok(())
}
fn statistical_analysis() -> Result<(), Box<dyn std::error::Error>> {
let config = AggregatorConfig::default();
let aggregator = MetricsAggregator::new(config);
let latencies = vec![10, 15, 20, 50, 100, 200, 150, 75, 30, 25];
for latency in latencies {
aggregator.record_latency(latency);
}
let stats = aggregator.get_statistics(TimeWindow::Minute);
println!("Latency Statistics:");
println!(" Count: {}", stats.latency.count);
println!(" Min: {:.2} ms", stats.latency.min);
println!(" Max: {:.2} ms", stats.latency.max);
println!(" Average: {:.2} ms", stats.latency.avg);
println!(" Std Dev: {:.2} ms", stats.latency.stddev);
println!(" Median (P50): {:.2} ms", stats.latency.p50);
println!(" P95: {:.2} ms", stats.latency.p95);
println!(" P99: {:.2} ms", stats.latency.p99);
Ok(())
}
fn percentile_calculations() -> Result<(), Box<dyn std::error::Error>> {
let config = AggregatorConfig::default();
let aggregator = MetricsAggregator::new(config);
for i in 1..=100 {
aggregator.record_bandwidth((i * 100) as u64);
}
let stats = aggregator.get_statistics(TimeWindow::Minute);
println!("Bandwidth Percentiles (100 samples):");
println!(" P50 (Median): {:.2} bytes", stats.bandwidth.p50);
println!(" P95: {:.2} bytes", stats.bandwidth.p95);
println!(" P99: {:.2} bytes", stats.bandwidth.p99);
println!(" Max: {:.2} bytes", stats.bandwidth.max);
println!("\nInterpretation:");
println!(
" 95% of measurements were below {:.2} bytes",
stats.bandwidth.p95
);
println!(
" 99% of measurements were below {:.2} bytes",
stats.bandwidth.p99
);
Ok(())
}
fn trend_analysis() -> Result<(), Box<dyn std::error::Error>> {
let config = AggregatorConfig::default();
let aggregator = MetricsAggregator::new(config);
println!("Increasing Latency Pattern:");
for i in 1..=20 {
aggregator.record_latency((i * 5) as u64);
thread::sleep(Duration::from_millis(10));
}
let stats = aggregator.get_statistics(TimeWindow::Minute);
println!(
" Trend: {:.2} (positive = increasing)",
stats.latency.trend
);
println!(" Average: {:.2} ms", stats.latency.avg);
aggregator.clear();
println!("\nDecreasing Latency Pattern:");
for i in (1..=20).rev() {
aggregator.record_latency((i * 5) as u64);
thread::sleep(Duration::from_millis(10));
}
let stats = aggregator.get_statistics(TimeWindow::Minute);
println!(
" Trend: {:.2} (negative = decreasing)",
stats.latency.trend
);
println!(" Average: {:.2} ms", stats.latency.avg);
aggregator.clear();
println!("\nStable Latency Pattern:");
for _ in 1..=20 {
aggregator.record_latency(50);
thread::sleep(Duration::from_millis(10));
}
let stats = aggregator.get_statistics(TimeWindow::Minute);
println!(" Trend: {:.2} (near zero = stable)", stats.latency.trend);
println!(" Average: {:.2} ms", stats.latency.avg);
Ok(())
}
fn time_windows() -> Result<(), Box<dyn std::error::Error>> {
let config = AggregatorConfig::default();
let aggregator = MetricsAggregator::new(config);
for _ in 0..10 {
aggregator.record_bandwidth(1024);
aggregator.record_latency(50);
}
println!("Statistics across different time windows:");
let windows = vec![
TimeWindow::Second,
TimeWindow::Minute,
TimeWindow::Hour,
TimeWindow::Day,
];
for window in windows {
let stats = aggregator.get_statistics(window);
println!("\n{:?} Window:", window);
println!(" Bandwidth count: {}", stats.bandwidth.count);
println!(" Latency count: {}", stats.latency.count);
println!(" (All recent data falls within all windows in this example)");
}
Ok(())
}
fn configuration_presets() -> Result<(), Box<dyn std::error::Error>> {
println!("Realtime Configuration:");
let realtime = AggregatorConfig::realtime();
println!(" Max data points: {}", realtime.max_data_points);
println!(" Retention: {:?}", realtime.retention_period);
println!(" Percentiles: {}", realtime.enable_percentiles);
println!(" Trends: {}", realtime.enable_trends);
println!("\nLong-term Configuration:");
let longterm = AggregatorConfig::longterm();
println!(" Max data points: {}", longterm.max_data_points);
println!(" Retention: {:?}", longterm.retention_period);
println!(" Percentiles: {}", longterm.enable_percentiles);
println!(" Trends: {}", longterm.enable_trends);
println!(" Sample rate: 1 in {}", longterm.sample_rate);
println!("\nBalanced Configuration:");
let balanced = AggregatorConfig::balanced();
println!(" Max data points: {}", balanced.max_data_points);
println!(" Retention: {:?}", balanced.retention_period);
println!(" Percentiles: {}", balanced.enable_percentiles);
println!(" Trends: {}", balanced.enable_trends);
println!(" Sample rate: 1 in {}", balanced.sample_rate);
Ok(())
}
fn sampling_and_retention() -> Result<(), Box<dyn std::error::Error>> {
let config = AggregatorConfig {
sample_rate: 3, max_data_points: 10,
..Default::default()
};
let max_points = config.max_data_points; let aggregator = MetricsAggregator::new(config);
println!("Recording 15 bandwidth measurements (sample rate: 1 in 3):");
for i in 1..=15 {
aggregator.record_bandwidth((i * 100) as u64);
}
let stats = aggregator.get_statistics(TimeWindow::Minute);
println!(" Recorded: 15");
println!(" Sampled: {}", stats.bandwidth.count);
println!(" Expected: ~5 (15 / 3)");
println!("\nRecording 20 more measurements (max points: 10):");
for i in 16..=35 {
aggregator.record_bandwidth((i * 100) as u64);
}
println!(" Total data points: {}", aggregator.data_point_count());
println!(" Max allowed per series: {}", max_points);
println!(" (Oldest points are automatically removed)");
Ok(())
}