vibetunnel/tauri/src-tauri/src/debug_features.rs
2025-06-23 14:58:10 +02:00

694 lines
20 KiB
Rust

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, VecDeque};
use std::path::PathBuf;
use std::sync::Arc;
use tokio::sync::RwLock;
/// Debug feature types
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum DebugFeature {
APITesting,
PerformanceMonitoring,
MemoryProfiling,
NetworkInspector,
EventLogger,
StateInspector,
LogViewer,
CrashReporter,
BenchmarkRunner,
DiagnosticReport,
}
/// Debug log level
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
pub enum LogLevel {
Trace,
Debug,
Info,
Warn,
Error,
}
/// Debug log entry
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LogEntry {
pub timestamp: DateTime<Utc>,
pub level: LogLevel,
pub component: String,
pub message: String,
pub metadata: HashMap<String, serde_json::Value>,
}
/// Performance metric
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceMetric {
pub name: String,
pub value: f64,
pub unit: String,
pub timestamp: DateTime<Utc>,
pub tags: HashMap<String, String>,
}
/// Memory snapshot
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemorySnapshot {
pub timestamp: DateTime<Utc>,
pub heap_used_mb: f64,
pub heap_total_mb: f64,
pub external_mb: f64,
pub process_rss_mb: f64,
pub details: HashMap<String, f64>,
}
/// Network request log
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NetworkRequest {
pub id: String,
pub timestamp: DateTime<Utc>,
pub method: String,
pub url: String,
pub status: Option<u16>,
pub duration_ms: Option<u64>,
pub request_headers: HashMap<String, String>,
pub response_headers: HashMap<String, String>,
pub request_body: Option<String>,
pub response_body: Option<String>,
pub error: Option<String>,
}
/// API test case
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct APITestCase {
pub id: String,
pub name: String,
pub endpoint: String,
pub method: String,
pub headers: HashMap<String, String>,
pub body: Option<serde_json::Value>,
pub expected_status: u16,
pub expected_body: Option<serde_json::Value>,
pub timeout_ms: u64,
}
/// API test result
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct APITestResult {
pub test_id: String,
pub success: bool,
pub actual_status: Option<u16>,
pub actual_body: Option<serde_json::Value>,
pub duration_ms: u64,
pub error: Option<String>,
pub timestamp: DateTime<Utc>,
}
/// Benchmark configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BenchmarkConfig {
pub name: String,
pub iterations: u32,
pub warmup_iterations: u32,
pub timeout_ms: u64,
pub collect_memory: bool,
pub collect_cpu: bool,
}
/// Benchmark result
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BenchmarkResult {
pub name: String,
pub iterations: u32,
pub mean_ms: f64,
pub median_ms: f64,
pub min_ms: f64,
pub max_ms: f64,
pub std_dev_ms: f64,
pub memory_usage_mb: Option<f64>,
pub cpu_usage_percent: Option<f64>,
pub timestamp: DateTime<Utc>,
}
/// Diagnostic report
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DiagnosticReport {
pub timestamp: DateTime<Utc>,
pub system_info: SystemInfo,
pub app_info: AppInfo,
pub performance_summary: PerformanceSummary,
pub error_summary: ErrorSummary,
pub recommendations: Vec<String>,
}
/// System information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SystemInfo {
pub os: String,
pub arch: String,
pub cpu_count: usize,
pub total_memory_mb: u64,
pub available_memory_mb: u64,
pub disk_space_mb: u64,
pub node_version: Option<String>,
pub rust_version: String,
}
/// Application information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppInfo {
pub version: String,
pub build_date: String,
pub uptime_seconds: u64,
pub active_sessions: usize,
pub total_requests: u64,
pub error_count: u64,
}
/// Performance summary
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceSummary {
pub avg_response_time_ms: f64,
pub p95_response_time_ms: f64,
pub p99_response_time_ms: f64,
pub requests_per_second: f64,
pub cpu_usage_percent: f64,
pub memory_usage_mb: f64,
}
/// Error summary
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ErrorSummary {
pub total_errors: u64,
pub errors_by_type: HashMap<String, u64>,
pub recent_errors: Vec<LogEntry>,
}
/// Debug settings
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DebugSettings {
pub enabled: bool,
pub log_level: LogLevel,
pub max_log_entries: usize,
pub enable_performance_monitoring: bool,
pub enable_memory_profiling: bool,
pub enable_network_inspector: bool,
pub enable_crash_reporting: bool,
pub log_to_file: bool,
pub log_file_path: Option<PathBuf>,
pub performance_sample_interval_ms: u64,
pub memory_sample_interval_ms: u64,
}
impl Default for DebugSettings {
fn default() -> Self {
Self {
enabled: cfg!(debug_assertions),
log_level: LogLevel::Info,
max_log_entries: 10000,
enable_performance_monitoring: false,
enable_memory_profiling: false,
enable_network_inspector: false,
enable_crash_reporting: true,
log_to_file: false,
log_file_path: None,
performance_sample_interval_ms: 1000,
memory_sample_interval_ms: 5000,
}
}
}
/// Debug features manager
pub struct DebugFeaturesManager {
settings: Arc<RwLock<DebugSettings>>,
logs: Arc<RwLock<VecDeque<LogEntry>>>,
performance_metrics: Arc<RwLock<VecDeque<PerformanceMetric>>>,
memory_snapshots: Arc<RwLock<VecDeque<MemorySnapshot>>>,
network_requests: Arc<RwLock<HashMap<String, NetworkRequest>>>,
api_test_results: Arc<RwLock<HashMap<String, Vec<APITestResult>>>>,
benchmark_results: Arc<RwLock<Vec<BenchmarkResult>>>,
notification_manager: Option<Arc<crate::notification_manager::NotificationManager>>,
}
impl Default for DebugFeaturesManager {
fn default() -> Self {
Self::new()
}
}
impl DebugFeaturesManager {
/// Create a new debug features manager
pub fn new() -> Self {
Self {
settings: Arc::new(RwLock::new(DebugSettings::default())),
logs: Arc::new(RwLock::new(VecDeque::new())),
performance_metrics: Arc::new(RwLock::new(VecDeque::new())),
memory_snapshots: Arc::new(RwLock::new(VecDeque::new())),
network_requests: Arc::new(RwLock::new(HashMap::new())),
api_test_results: Arc::new(RwLock::new(HashMap::new())),
benchmark_results: Arc::new(RwLock::new(Vec::new())),
notification_manager: None,
}
}
/// Set the notification manager
pub fn set_notification_manager(
&mut self,
notification_manager: Arc<crate::notification_manager::NotificationManager>,
) {
self.notification_manager = Some(notification_manager);
}
/// Get debug settings
pub async fn get_settings(&self) -> DebugSettings {
self.settings.read().await.clone()
}
/// Update debug settings
pub async fn update_settings(&self, settings: DebugSettings) {
*self.settings.write().await = settings;
}
/// Log a message
pub async fn log(
&self,
level: LogLevel,
component: &str,
message: &str,
metadata: HashMap<String, serde_json::Value>,
) {
let settings = self.settings.read().await;
// Check if logging is enabled and level is appropriate
if !settings.enabled || level < settings.log_level {
return;
}
let entry = LogEntry {
timestamp: Utc::now(),
level,
component: component.to_string(),
message: message.to_string(),
metadata,
};
// Add to in-memory log
let mut logs = self.logs.write().await;
logs.push_back(entry.clone());
// Limit log size
while logs.len() > settings.max_log_entries {
logs.pop_front();
}
// Log to file if enabled
if settings.log_to_file {
if let Some(path) = &settings.log_file_path {
let _ = self.write_log_to_file(&entry, path).await;
}
}
}
/// Record a performance metric
pub async fn record_metric(
&self,
name: &str,
value: f64,
unit: &str,
tags: HashMap<String, String>,
) {
let settings = self.settings.read().await;
if !settings.enabled || !settings.enable_performance_monitoring {
return;
}
let metric = PerformanceMetric {
name: name.to_string(),
value,
unit: unit.to_string(),
timestamp: Utc::now(),
tags,
};
let mut metrics = self.performance_metrics.write().await;
metrics.push_back(metric);
// Keep only last 1000 metrics
while metrics.len() > 1000 {
metrics.pop_front();
}
}
/// Take a memory snapshot
pub async fn take_memory_snapshot(&self) -> Result<MemorySnapshot, String> {
let settings = self.settings.read().await;
if !settings.enabled || !settings.enable_memory_profiling {
return Err("Memory profiling is disabled".to_string());
}
// TODO: Implement actual memory profiling
let snapshot = MemorySnapshot {
timestamp: Utc::now(),
heap_used_mb: 0.0,
heap_total_mb: 0.0,
external_mb: 0.0,
process_rss_mb: 0.0,
details: HashMap::new(),
};
let mut snapshots = self.memory_snapshots.write().await;
snapshots.push_back(snapshot.clone());
// Keep only last 100 snapshots
while snapshots.len() > 100 {
snapshots.pop_front();
}
Ok(snapshot)
}
/// Log a network request
#[allow(dead_code)]
pub async fn log_network_request(&self, request: NetworkRequest) {
let settings = self.settings.read().await;
if !settings.enabled || !settings.enable_network_inspector {
return;
}
let mut requests = self.network_requests.write().await;
requests.insert(request.id.clone(), request);
// Keep only last 500 requests
if requests.len() > 500 {
// Remove oldest entries
let mut ids: Vec<_> = requests.keys().cloned().collect();
ids.sort();
for id in ids.iter().take(requests.len() - 500) {
requests.remove(id);
}
}
}
/// Run API tests
pub async fn run_api_tests(&self, tests: Vec<APITestCase>) -> Vec<APITestResult> {
let mut results = Vec::new();
for test in tests {
let result = self.run_single_api_test(&test).await;
results.push(result.clone());
// Store result
let mut test_results = self.api_test_results.write().await;
test_results
.entry(test.id.clone())
.or_insert_with(Vec::new)
.push(result);
}
results
}
/// Run a single API test
async fn run_single_api_test(&self, test: &APITestCase) -> APITestResult {
let start = std::time::Instant::now();
// TODO: Implement actual API testing
let duration_ms = start.elapsed().as_millis() as u64;
APITestResult {
test_id: test.id.clone(),
success: false,
actual_status: None,
actual_body: None,
duration_ms,
error: Some("API testing not yet implemented".to_string()),
timestamp: Utc::now(),
}
}
/// Run benchmarks
pub async fn run_benchmarks(&self, configs: Vec<BenchmarkConfig>) -> Vec<BenchmarkResult> {
let mut results = Vec::new();
for config in configs {
let result = self.run_single_benchmark(&config).await;
results.push(result.clone());
// Store result
self.benchmark_results.write().await.push(result);
}
results
}
/// Run a single benchmark
async fn run_single_benchmark(&self, config: &BenchmarkConfig) -> BenchmarkResult {
// TODO: Implement actual benchmarking
BenchmarkResult {
name: config.name.clone(),
iterations: config.iterations,
mean_ms: 0.0,
median_ms: 0.0,
min_ms: 0.0,
max_ms: 0.0,
std_dev_ms: 0.0,
memory_usage_mb: None,
cpu_usage_percent: None,
timestamp: Utc::now(),
}
}
/// Generate diagnostic report
pub async fn generate_diagnostic_report(&self) -> DiagnosticReport {
let system_info = self.get_system_info().await;
let app_info = self.get_app_info().await;
let performance_summary = self.get_performance_summary().await;
let error_summary = self.get_error_summary().await;
let recommendations = self.generate_recommendations(
&system_info,
&app_info,
&performance_summary,
&error_summary,
);
DiagnosticReport {
timestamp: Utc::now(),
system_info,
app_info,
performance_summary,
error_summary,
recommendations,
}
}
/// Get recent logs
pub async fn get_logs(&self, limit: Option<usize>, level: Option<LogLevel>) -> Vec<LogEntry> {
let logs = self.logs.read().await;
let iter = logs.iter().rev();
let filtered: Vec<_> = if let Some(min_level) = level {
iter.filter(|log| log.level >= min_level).cloned().collect()
} else {
iter.cloned().collect()
};
match limit {
Some(n) => filtered.into_iter().take(n).collect(),
None => filtered,
}
}
/// Get performance metrics
pub async fn get_performance_metrics(&self, limit: Option<usize>) -> Vec<PerformanceMetric> {
let metrics = self.performance_metrics.read().await;
match limit {
Some(n) => metrics.iter().rev().take(n).cloned().collect(),
None => metrics.iter().cloned().collect(),
}
}
/// Get memory snapshots
pub async fn get_memory_snapshots(&self, limit: Option<usize>) -> Vec<MemorySnapshot> {
let snapshots = self.memory_snapshots.read().await;
match limit {
Some(n) => snapshots.iter().rev().take(n).cloned().collect(),
None => snapshots.iter().cloned().collect(),
}
}
/// Get network requests
pub async fn get_network_requests(&self, limit: Option<usize>) -> Vec<NetworkRequest> {
let requests = self.network_requests.read().await;
let mut sorted: Vec<_> = requests.values().cloned().collect();
sorted.sort_by(|a, b| b.timestamp.cmp(&a.timestamp));
match limit {
Some(n) => sorted.into_iter().take(n).collect(),
None => sorted,
}
}
/// Clear all debug data
pub async fn clear_all_data(&self) {
self.logs.write().await.clear();
self.performance_metrics.write().await.clear();
self.memory_snapshots.write().await.clear();
self.network_requests.write().await.clear();
self.api_test_results.write().await.clear();
self.benchmark_results.write().await.clear();
}
/// Enable/disable debug mode
pub async fn set_debug_mode(&self, enabled: bool) {
self.settings.write().await.enabled = enabled;
if let Some(notification_manager) = &self.notification_manager {
let message = if enabled {
"Debug mode enabled"
} else {
"Debug mode disabled"
};
let _ = notification_manager
.notify_success("Debug Mode", message)
.await;
}
}
// Helper methods
async fn write_log_to_file(&self, entry: &LogEntry, path: &PathBuf) -> Result<(), String> {
use tokio::io::AsyncWriteExt;
let log_line = format!(
"[{}] [{}] [{}] {}\n",
entry.timestamp.format("%Y-%m-%d %H:%M:%S%.3f"),
format!("{:?}", entry.level),
entry.component,
entry.message
);
let mut file = tokio::fs::OpenOptions::new()
.create(true)
.append(true)
.open(path)
.await
.map_err(|e| e.to_string())?;
file.write_all(log_line.as_bytes())
.await
.map_err(|e| e.to_string())?;
Ok(())
}
async fn get_system_info(&self) -> SystemInfo {
SystemInfo {
os: std::env::consts::OS.to_string(),
arch: std::env::consts::ARCH.to_string(),
cpu_count: num_cpus::get(),
total_memory_mb: 0, // TODO: Get actual memory
available_memory_mb: 0,
disk_space_mb: 0,
node_version: None,
rust_version: "1.70.0".to_string(), // TODO: Get actual rust version
}
}
async fn get_app_info(&self) -> AppInfo {
AppInfo {
version: env!("CARGO_PKG_VERSION").to_string(),
build_date: chrono::Utc::now().to_rfc3339(), // TODO: Get actual build date
uptime_seconds: 0, // TODO: Track uptime
active_sessions: 0,
total_requests: 0,
error_count: 0,
}
}
async fn get_performance_summary(&self) -> PerformanceSummary {
PerformanceSummary {
avg_response_time_ms: 0.0,
p95_response_time_ms: 0.0,
p99_response_time_ms: 0.0,
requests_per_second: 0.0,
cpu_usage_percent: 0.0,
memory_usage_mb: 0.0,
}
}
async fn get_error_summary(&self) -> ErrorSummary {
let logs = self.logs.read().await;
let errors: Vec<_> = logs
.iter()
.filter(|log| log.level == LogLevel::Error)
.cloned()
.collect();
let mut errors_by_type = HashMap::new();
for error in &errors {
let error_type = error
.metadata
.get("type")
.and_then(|v| v.as_str())
.unwrap_or("unknown")
.to_string();
*errors_by_type.entry(error_type).or_insert(0) += 1;
}
ErrorSummary {
total_errors: errors.len() as u64,
errors_by_type,
recent_errors: errors.into_iter().rev().take(10).collect(),
}
}
fn generate_recommendations(
&self,
system: &SystemInfo,
_app: &AppInfo,
perf: &PerformanceSummary,
errors: &ErrorSummary,
) -> Vec<String> {
let mut recommendations = Vec::new();
if perf.cpu_usage_percent > 80.0 {
recommendations.push(
"High CPU usage detected. Consider optimizing performance-critical code."
.to_string(),
);
}
if perf.memory_usage_mb > (system.total_memory_mb as f64 * 0.8) {
recommendations.push("High memory usage detected. Check for memory leaks.".to_string());
}
if errors.total_errors > 100 {
recommendations
.push("High error rate detected. Review error logs for patterns.".to_string());
}
if perf.avg_response_time_ms > 1000.0 {
recommendations.push(
"Slow response times detected. Consider caching or query optimization.".to_string(),
);
}
recommendations
}
}
/// Debug statistics
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DebugStats {
pub total_logs: usize,
pub logs_by_level: HashMap<String, usize>,
pub total_metrics: usize,
pub total_snapshots: usize,
pub total_requests: usize,
pub total_test_results: usize,
pub total_benchmarks: usize,
}
// Re-export num_cpus if needed
extern crate num_cpus;