use crate::cli::colors as c;
use crate::services::telemetry_service::{telemetry, OperationMetrics, TelemetryInput};
use anyhow::Result;
use serde_json::json;
use std::collections::HashMap;
use std::time::Instant;
use tracing::{debug, info};
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub async fn handle_telemetry(
system: bool,
service: Option<String>,
reset: bool,
test_event: bool,
) -> Result<()> {
let start_time = Instant::now();
if reset {
return handle_reset_command().await;
}
if test_event {
return handle_test_event_command().await;
}
handle_display_command(system, service).await?;
let _ = record_telemetry_command_execution(start_time).await;
Ok(())
}
async fn handle_reset_command() -> Result<()> {
#[cfg(test)]
{
telemetry().reset();
println!("{}", c::pass("Telemetry data reset successfully"));
Ok(())
}
#[cfg(not(test))]
{
println!(
"{}",
c::warn("Telemetry reset is only available in test builds")
);
Ok(())
}
}
async fn handle_test_event_command() -> Result<()> {
record_test_telemetry_event().await?;
println!("{}", c::pass("Test telemetry event recorded successfully"));
Ok(())
}
async fn handle_display_command(system: bool, service: Option<String>) -> Result<()> {
match (system, service) {
(_, Some(service_name)) => show_service_telemetry(&service_name).await,
(true, None) => show_system_telemetry().await,
(false, None) => show_system_overview().await,
}
}
async fn show_system_telemetry() -> Result<()> {
info!("Generating system telemetry report");
let telemetry_service = telemetry();
let system_data = telemetry_service.get_system_telemetry().await?;
println!("{}", c::header("PMAT System Telemetry Report"));
println!("{}", c::rule());
println!();
println!("{}", c::subheader("System Overview:"));
println!(
" {}: {} seconds",
c::dim("Uptime"),
c::number(&system_data.uptime_seconds.to_string())
);
println!(
" {}: {}",
c::dim("Total Operations"),
c::number(&system_data.system_metrics.total_operations.to_string())
);
println!(
" {}: {}",
c::dim("Success Rate"),
c::pct(system_data.system_metrics.success_rate * 100.0, 90.0, 70.0)
);
println!(
" {}: {} ms",
c::dim("Average Duration"),
c::number(&system_data.system_metrics.avg_duration_ms.to_string())
);
println!(
" {}: {}",
c::dim("Total Items Processed"),
c::number(&system_data.system_metrics.total_items_processed.to_string())
);
println!();
if !system_data.services.is_empty() {
println!("{}", c::subheader("Service Breakdown:"));
for (service_name, service_data) in &system_data.services {
println!(" {}", c::label(service_name));
println!(
" {}: {} ({}Success{}: {}, {}Failed{}: {})",
c::dim("Operations"),
c::number(&service_data.total_operations.to_string()),
c::GREEN,
c::RESET,
service_data.successful_operations,
c::RED,
c::RESET,
service_data.failed_operations
);
println!(
" {}: {}",
c::dim("Success Rate"),
c::pct(service_data.success_rate * 100.0, 90.0, 70.0)
);
println!(
" {}: {} ms",
c::dim("Avg Duration"),
c::number(&service_data.avg_duration_ms.to_string())
);
println!(
" {}: {}",
c::dim("Items Processed"),
c::number(&service_data.total_items_processed.to_string())
);
if !service_data.operation_counts.is_empty() {
println!(" {}:", c::dim("Top Operations"));
let mut ops: Vec<_> = service_data.operation_counts.iter().collect();
ops.sort_by(|a, b| b.1.cmp(a.1));
for (op, count) in ops.iter().take(3) {
println!(" - {}: {} times", c::label(op), count);
}
}
println!();
}
}
println!("{}", c::dim("Raw Data (JSON):"));
println!("{}", serde_json::to_string_pretty(&system_data)?);
Ok(())
}
async fn show_service_telemetry(service_name: &str) -> Result<()> {
info!(service = %service_name, "Generating service telemetry report");
let telemetry_service = telemetry();
if let Some(service_data) = telemetry_service.get_service_telemetry(service_name).await {
println!(
"{} {}",
c::header("Service Telemetry:"),
c::label(service_name)
);
println!("{}", c::rule());
println!();
println!("{}", c::subheader("Performance Metrics:"));
println!(
" {}: {}",
c::dim("Total Operations"),
c::number(&service_data.total_operations.to_string())
);
println!(
" {}: {} ({})",
c::dim("Successful"),
c::number(&service_data.successful_operations.to_string()),
c::pct(service_data.success_rate * 100.0, 90.0, 70.0)
);
println!(
" {}: {}",
c::dim("Failed"),
if service_data.failed_operations > 0 {
format!("{}{}{}", c::RED, service_data.failed_operations, c::RESET)
} else {
service_data.failed_operations.to_string()
}
);
println!(
" {}: {} ms",
c::dim("Average Duration"),
c::number(&service_data.avg_duration_ms.to_string())
);
println!(
" {}: {} ms",
c::dim("Total Duration"),
c::number(&service_data.total_duration_ms.to_string())
);
println!(
" {}: {}",
c::dim("Items Processed"),
c::number(&service_data.total_items_processed.to_string())
);
if service_data.peak_memory_bytes > 0 {
println!(
" {}: {} bytes",
c::dim("Peak Memory"),
c::number(&service_data.peak_memory_bytes.to_string())
);
}
println!(
" {}: {}",
c::dim("Last Operation"),
service_data.last_operation_at
);
println!();
if !service_data.operation_counts.is_empty() {
println!("{}", c::subheader("Operation Breakdown:"));
let mut operations: Vec<_> = service_data.operation_counts.iter().collect();
operations.sort_by(|a, b| b.1.cmp(a.1));
for (operation, count) in operations {
let percentage = (*count as f64 / service_data.total_operations as f64) * 100.0;
println!(
" - {}: {} ({:.1}%)",
c::label(operation),
count,
percentage
);
}
}
println!();
println!("{}", c::dim("Raw Data (JSON):"));
println!("{}", serde_json::to_string_pretty(&service_data)?);
} else {
println!(
"{}",
c::fail(&format!(
"No telemetry data found for service: {service_name}"
))
);
println!(
"{}",
c::dim("Available services can be seen with: pmat telemetry --system")
);
}
Ok(())
}
async fn show_system_overview() -> Result<()> {
info!("Generating system overview");
let telemetry_service = telemetry();
let system_data = telemetry_service.get_system_telemetry().await?;
println!("{}", c::header("PMAT System Overview"));
println!("{}", c::rule());
println!();
println!("{}", c::subheader("System Status:"));
println!(
" {}: {} seconds",
c::dim("Uptime"),
c::number(&system_data.uptime_seconds.to_string())
);
println!(
" {}: {}",
c::dim("Total Operations"),
c::number(&system_data.system_metrics.total_operations.to_string())
);
println!(
" {}: {}",
c::dim("Success Rate"),
c::pct(system_data.system_metrics.success_rate * 100.0, 90.0, 70.0)
);
println!();
if system_data.services.is_empty() {
println!("{}", c::dim("No service telemetry data available yet"));
println!(
"{}",
c::dim("Use --test-event to generate sample telemetry data")
);
} else {
println!(
"{}: {}",
c::subheader("Active Services"),
c::number(&system_data.services.len().to_string())
);
for service_name in system_data.services.keys() {
println!(" - {}", c::label(service_name));
}
println!();
println!(
"{}",
c::dim("Use --system for detailed metrics or --service <name> for service details")
);
}
Ok(())
}
async fn record_test_telemetry_event() -> Result<()> {
debug!("Recording test telemetry event");
let test_input = TelemetryInput {
event_type: "test_operation".to_string(),
service_name: "telemetry_test_service".to_string(),
operation: "test_command_execution".to_string(),
metrics: OperationMetrics {
duration_ms: 125,
items_processed: 3,
memory_bytes: Some(2048),
cpu_time_ms: Some(95),
success: true,
error_message: None,
},
tags: {
let mut tags = HashMap::new();
tags.insert("test_type".to_string(), "cli_demo".to_string());
tags.insert("user".to_string(), "system".to_string());
tags
},
properties: {
let mut props = HashMap::new();
props.insert("version".to_string(), json!("2.6.8"));
props.insert("environment".to_string(), json!("development"));
props
},
};
let output = telemetry().record_operation(test_input).await?;
info!(event_id = %output.event_id, "Test telemetry event recorded");
Ok(())
}
async fn record_telemetry_command_execution(start_time: Instant) -> Result<()> {
let duration = start_time.elapsed();
let input = TelemetryInput {
event_type: "cli_command".to_string(),
service_name: "cli_telemetry_handler".to_string(),
operation: "telemetry_command".to_string(),
metrics: OperationMetrics {
duration_ms: duration.as_millis() as u64,
items_processed: 1,
memory_bytes: None,
cpu_time_ms: None,
success: true,
error_message: None,
},
tags: HashMap::new(),
properties: HashMap::new(),
};
let _ = telemetry().record_operation(input).await;
Ok(())
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_telemetry_command_system() {
telemetry().reset();
record_test_telemetry_event().await.unwrap();
let result = show_system_overview().await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_telemetry_command_service() {
telemetry().reset();
record_test_telemetry_event().await.unwrap();
let result = show_service_telemetry("telemetry_test_service").await;
assert!(result.is_ok());
let result = show_service_telemetry("non_existent_service").await;
assert!(result.is_ok()); }
#[tokio::test]
async fn test_telemetry_reset() {
record_test_telemetry_event().await.unwrap();
let result = handle_telemetry(false, None, true, false).await;
assert!(result.is_ok());
let _system_data = telemetry().get_system_telemetry().await.unwrap();
}
#[tokio::test]
#[ignore = "requires telemetry setup"]
async fn test_test_event_generation() {
telemetry().reset();
let result = handle_telemetry(false, None, false, true).await;
assert!(result.is_ok());
let system_data = telemetry().get_system_telemetry().await.unwrap();
assert!(system_data.system_metrics.total_operations > 0);
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod property_tests {
use proptest::prelude::*;
proptest! {
#[test]
fn basic_property_stability(_input in ".*") {
prop_assert!(true);
}
#[test]
fn module_consistency_check(_x in 0u32..1000) {
prop_assert!(_x < 1001);
}
}
}