use alloc::string::String;
use alloc::vec::Vec;
use alloc::collections::BTreeMap as HashMap;
use crate::{SystemMetrics, AgentMetrics};
use crate::timing::{TimingHistogram, OperationStatistics, PerformanceProfiler};
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};
pub struct JsonExporter {
pub pretty: bool,
pub include_histograms: bool,
pub include_raw_data: bool,
}
impl JsonExporter {
pub fn new() -> Self {
Self {
pretty: false,
include_histograms: true,
include_raw_data: false,
}
}
pub fn pretty() -> Self {
Self {
pretty: true,
include_histograms: true,
include_raw_data: false,
}
}
pub fn with_histograms(mut self, include: bool) -> Self {
self.include_histograms = include;
self
}
pub fn with_raw_data(mut self, include: bool) -> Self {
self.include_raw_data = include;
self
}
pub fn export(&self, report: &MetricsReport) -> crate::Result<String> {
let export_data = ExportData {
timestamp: crate::collector::now(),
system_metrics: report.system.clone(),
agent_metrics: report.agents.clone(),
profiler_stats: report.profiler_stats.clone(),
histogram_data: if self.include_histograms {
report.histogram_data.clone()
} else {
HashMap::default()
},
metadata: ExportMetadata {
version: "1.0.0".to_string(),
export_type: "metrics_report".to_string(),
include_histograms: self.include_histograms,
include_raw_data: self.include_raw_data,
},
};
if self.pretty {
serde_json::to_string_pretty(&export_data)
.map_err(|_| "Failed to serialize metrics to pretty JSON")
} else {
serde_json::to_string(&export_data)
.map_err(|_| "Failed to serialize metrics to JSON")
}
}
pub fn export_system_only(&self, system: &SystemMetrics) -> crate::Result<String> {
let export_data = SystemExportData {
timestamp: crate::collector::now(),
system_metrics: system.clone(),
metadata: ExportMetadata {
version: "1.0.0".to_string(),
export_type: "system_metrics".to_string(),
include_histograms: false,
include_raw_data: false,
},
};
if self.pretty {
serde_json::to_string_pretty(&export_data)
.map_err(|_| "Failed to serialize system metrics to pretty JSON")
} else {
serde_json::to_string(&export_data)
.map_err(|_| "Failed to serialize system metrics to JSON")
}
}
pub fn export_agents_only(&self, agents: &[AgentMetrics]) -> crate::Result<String> {
let export_data = AgentExportData {
timestamp: crate::collector::now(),
agent_metrics: agents.to_vec(),
metadata: ExportMetadata {
version: "1.0.0".to_string(),
export_type: "agent_metrics".to_string(),
include_histograms: false,
include_raw_data: false,
},
};
if self.pretty {
serde_json::to_string_pretty(&export_data)
.map_err(|_| "Failed to serialize agent metrics to pretty JSON")
} else {
serde_json::to_string(&export_data)
.map_err(|_| "Failed to serialize agent metrics to JSON")
}
}
pub fn export_performance_stats(&self, stats: &[OperationStatistics]) -> crate::Result<String> {
let export_data = PerformanceExportData {
timestamp: crate::collector::now(),
performance_stats: stats.to_vec(),
metadata: ExportMetadata {
version: "1.0.0".to_string(),
export_type: "performance_stats".to_string(),
include_histograms: false,
include_raw_data: false,
},
};
if self.pretty {
serde_json::to_string_pretty(&export_data)
.map_err(|_| "Failed to serialize performance stats to pretty JSON")
} else {
serde_json::to_string(&export_data)
.map_err(|_| "Failed to serialize performance stats to JSON")
}
}
}
#[derive(Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MetricsReport {
pub system: SystemMetrics,
pub agents: Vec<AgentMetrics>,
pub profiler_stats: Vec<OperationStatistics>,
pub histogram_data: HashMap<String, HistogramData>,
pub timestamp: u64,
pub metadata: ReportMetadata,
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct HistogramData {
pub operation: String,
pub buckets: Vec<u64>,
pub counts: Vec<u64>,
pub total_samples: u64,
pub stats: HistogramStats,
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct HistogramStats {
pub mean_ns: f64,
pub std_dev_ns: f64,
pub p50_ns: u64,
pub p95_ns: u64,
pub p99_ns: u64,
pub mean_ms: f64,
pub p50_ms: f64,
pub p95_ms: f64,
pub p99_ms: f64,
}
#[derive(Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ReportMetadata {
pub version: String,
pub generated_at: u64,
pub collection_duration_ns: u64,
pub operations_tracked: u32,
pub export_config: ExportConfig,
}
#[derive(Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ExportConfig {
pub include_histograms: bool,
pub include_raw_data: bool,
pub pretty_print: bool,
}
#[derive(Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
struct ExportData {
timestamp: u64,
system_metrics: SystemMetrics,
agent_metrics: Vec<AgentMetrics>,
profiler_stats: Vec<OperationStatistics>,
histogram_data: HashMap<String, HistogramData>,
metadata: ExportMetadata,
}
#[derive(Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
struct SystemExportData {
timestamp: u64,
system_metrics: SystemMetrics,
metadata: ExportMetadata,
}
#[derive(Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
struct AgentExportData {
timestamp: u64,
agent_metrics: Vec<AgentMetrics>,
metadata: ExportMetadata,
}
#[derive(Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
struct PerformanceExportData {
timestamp: u64,
performance_stats: Vec<OperationStatistics>,
metadata: ExportMetadata,
}
#[derive(Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
struct ExportMetadata {
version: String,
export_type: String,
include_histograms: bool,
include_raw_data: bool,
}
impl MetricsReport {
pub fn new() -> Self {
let timestamp = crate::collector::now();
Self {
system: SystemMetrics::default(),
agents: Vec::new(),
profiler_stats: Vec::new(),
histogram_data: HashMap::default(),
timestamp,
metadata: ReportMetadata {
version: "1.0.0".to_string(),
generated_at: timestamp,
collection_duration_ns: 0,
operations_tracked: 0,
export_config: ExportConfig {
include_histograms: true,
include_raw_data: false,
pretty_print: false,
},
},
}
}
pub fn from_collector(
system: SystemMetrics,
agents: Vec<AgentMetrics>,
profiler: &PerformanceProfiler,
) -> Self {
let timestamp = crate::collector::now();
let profiler_stats = profiler.get_all_stats();
let mut histogram_data = HashMap::default();
for stat in &profiler_stats {
if let Some(histogram) = profiler.get_histogram(&stat.operation) {
let hist_data = HistogramData {
operation: stat.operation.clone(),
buckets: histogram.buckets().to_vec(),
counts: histogram.counts().to_vec(),
total_samples: histogram.count(),
stats: HistogramStats {
mean_ns: histogram.mean(),
std_dev_ns: histogram.std_dev(),
p50_ns: histogram.p50(),
p95_ns: histogram.p95(),
p99_ns: histogram.p99(),
mean_ms: histogram.mean() / 1_000_000.0,
p50_ms: histogram.p50() as f64 / 1_000_000.0,
p95_ms: histogram.p95() as f64 / 1_000_000.0,
p99_ms: histogram.p99() as f64 / 1_000_000.0,
},
};
histogram_data.insert(stat.operation.clone(), hist_data);
}
}
Self {
system: system.clone(),
agents,
profiler_stats,
histogram_data,
timestamp,
metadata: ReportMetadata {
version: "1.0.0".to_string(),
generated_at: timestamp,
collection_duration_ns: system.uptime_ns,
operations_tracked: system.operation_stats.len() as u32,
export_config: ExportConfig {
include_histograms: true,
include_raw_data: false,
pretty_print: false,
},
},
}
}
pub fn add_agent(&mut self, agent: AgentMetrics) {
self.agents.push(agent);
}
pub fn update_system(&mut self, system: SystemMetrics) {
self.metadata.collection_duration_ns = system.uptime_ns;
self.metadata.operations_tracked = system.operation_stats.len() as u32;
self.system = system;
}
pub fn add_profiler_stats(&mut self, stats: Vec<OperationStatistics>) {
self.profiler_stats = stats;
}
pub fn get_summary(&self) -> ReportSummary {
ReportSummary {
total_operations: self.system.total_operations,
active_agents: self.system.active_agents,
uptime_ms: self.system.uptime_ns as f64 / 1_000_000.0,
memory_usage_mb: self.system.memory_usage as f64 / (1024.0 * 1024.0),
peak_memory_mb: self.system.peak_memory_usage as f64 / (1024.0 * 1024.0),
operations_tracked: self.metadata.operations_tracked,
avg_cpu_usage: self.system.system_stats.cpu_usage,
}
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ReportSummary {
pub total_operations: u64,
pub active_agents: u32,
pub uptime_ms: f64,
pub memory_usage_mb: f64,
pub peak_memory_mb: f64,
pub operations_tracked: u32,
pub avg_cpu_usage: f32,
}
impl Default for JsonExporter {
fn default() -> Self {
Self::new()
}
}
impl Default for MetricsReport {
fn default() -> Self {
Self::new()
}
}
pub struct CsvExporter {
pub include_headers: bool,
pub separator: char,
}
impl CsvExporter {
pub fn new() -> Self {
Self {
include_headers: true,
separator: ',',
}
}
pub fn export_system_metrics(&self, metrics: &SystemMetrics) -> String {
let mut csv = String::new();
if self.include_headers {
csv.push_str("timestamp,uptime_ns,total_operations,memory_usage,peak_memory_usage,total_allocations,total_deallocations,active_agents,cpu_usage,memory_usage_percent\n");
}
csv.push_str(&format!(
"{}{sep}{}{sep}{}{sep}{}{sep}{}{sep}{}{sep}{}{sep}{}{sep}{:.2}{sep}{:.2}\n",
crate::collector::now(),
metrics.uptime_ns,
metrics.total_operations,
metrics.memory_usage,
metrics.peak_memory_usage,
metrics.total_allocations,
metrics.total_deallocations,
metrics.active_agents,
metrics.system_stats.cpu_usage,
metrics.system_stats.memory_usage_percent,
sep = self.separator
));
csv
}
pub fn export_agent_metrics(&self, agents: &[AgentMetrics]) -> String {
let mut csv = String::new();
if self.include_headers {
csv.push_str("agent_id,success_rate,total_operations,successful_operations,failed_operations,avg_duration_ns,uptime_ns\n");
}
for agent in agents {
csv.push_str(&format!(
"{}{sep}{:.4}{sep}{}{sep}{}{sep}{}{sep}{}{sep}{}\n",
agent.id,
agent.success_rate,
agent.total_operations,
agent.successful_operations,
agent.failed_operations,
agent.avg_duration_ns,
agent.uptime_ns,
sep = self.separator
));
}
csv
}
}
impl Default for CsvExporter {
fn default() -> Self {
Self::new()
}
}