Skip to main content

do_memory_mcp/monitoring/
endpoints.rs

1//! Monitoring endpoints for MCP server
2
3use super::core::MonitoringSystem;
4// use super::types::{HealthCheck, MonitoringStats, PerformanceMetrics}; // Currently unused
5use anyhow::Result;
6use serde_json::json;
7use std::sync::Arc;
8use tracing::debug;
9
10/// Monitoring endpoints handler
11pub struct MonitoringEndpoints {
12    /// Monitoring system
13    monitoring: Arc<MonitoringSystem>,
14}
15
16impl MonitoringEndpoints {
17    /// Create new monitoring endpoints
18    pub fn new(monitoring: Arc<MonitoringSystem>) -> Self {
19        Self { monitoring }
20    }
21
22    /// Handle health check endpoint
23    pub async fn health_check(&self) -> Result<serde_json::Value> {
24        debug!("Handling health check request");
25
26        let health = self.monitoring.health_check().await;
27
28        Ok(json!({
29            "status": match &health.status {
30                super::types::HealthStatus::Healthy => "healthy",
31                super::types::HealthStatus::Warning { .. } => "warning",
32                super::types::HealthStatus::Unhealthy { .. } => "unhealthy",
33            },
34            "timestamp": health.timestamp,
35            "components": health.components.into_iter()
36                .map(|(name, component)| {
37                    (name, json!({
38                        "status": match &component.status {
39                            super::types::HealthStatus::Healthy => "healthy",
40                            super::types::HealthStatus::Warning { .. } => "warning",
41                            super::types::HealthStatus::Unhealthy { .. } => "unhealthy",
42                        },
43                        "details": component.details,
44                        "last_check": component.last_check
45                    }))
46                })
47                .collect::<serde_json::Map<String, serde_json::Value>>()
48        }))
49    }
50
51    /// Handle metrics endpoint
52    pub async fn metrics(&self) -> Result<serde_json::Value> {
53        debug!("Handling metrics request");
54
55        let stats = self.monitoring.get_stats();
56        let performance = self.monitoring.get_performance();
57        let active_requests = self.monitoring.active_request_count().await;
58
59        Ok(json!({
60            "monitoring_stats": stats,
61            "performance_metrics": performance,
62            "active_requests": active_requests,
63            "timestamp": std::time::SystemTime::now()
64                .duration_since(std::time::UNIX_EPOCH)
65                .unwrap_or_default()
66                .as_secs()
67        }))
68    }
69
70    /// Handle stats endpoint (alias for metrics)
71    pub async fn stats(&self) -> Result<serde_json::Value> {
72        self.metrics().await
73    }
74
75    /// Handle episode metrics endpoint
76    pub async fn episode_metrics(&self) -> Result<serde_json::Value> {
77        debug!("Handling episode metrics request");
78
79        let stats = self.monitoring.get_stats();
80
81        Ok(json!({
82            "episode_metrics": stats.episode_metrics,
83            "timestamp": std::time::SystemTime::now()
84                .duration_since(std::time::UNIX_EPOCH)
85                .unwrap_or_default()
86                .as_secs()
87        }))
88    }
89
90    /// Handle performance metrics endpoint
91    pub async fn performance_metrics(&self) -> Result<serde_json::Value> {
92        debug!("Handling performance metrics request");
93
94        let performance = self.monitoring.get_performance();
95
96        Ok(json!({
97            "performance_metrics": performance,
98            "timestamp": std::time::SystemTime::now()
99                .duration_since(std::time::UNIX_EPOCH)
100                .unwrap_or_default()
101                .as_secs()
102        }))
103    }
104
105    /// Handle system info endpoint
106    pub async fn system_info(&self) -> Result<serde_json::Value> {
107        debug!("Handling system info request");
108
109        let stats = self.monitoring.get_stats();
110
111        Ok(json!({
112            "version": env!("CARGO_PKG_VERSION"),
113            "uptime_seconds": stats.uptime_seconds,
114            "memory_usage_mb": stats.memory_usage_mb,
115            "cpu_usage_percent": stats.cpu_usage_percent,
116            "total_requests": stats.total_requests,
117            "avg_response_time_ms": stats.avg_response_time_ms,
118            "timestamp": std::time::SystemTime::now()
119                .duration_since(std::time::UNIX_EPOCH)
120                .unwrap_or_default()
121                .as_secs()
122        }))
123    }
124
125    /// Check if monitoring is enabled
126    pub fn is_enabled(&self) -> bool {
127        self.monitoring.config().enabled
128    }
129}
130
131#[cfg(test)]
132mod tests {
133    use super::super::types::MonitoringConfig;
134    use super::*;
135
136    #[tokio::test]
137    async fn test_monitoring_endpoints() {
138        let config = MonitoringConfig::default();
139        let monitoring = Arc::new(MonitoringSystem::new(config));
140        let endpoints = MonitoringEndpoints::new(monitoring);
141
142        // Test health check
143        let health = endpoints.health_check().await.unwrap();
144        assert!(health.get("status").is_some());
145        assert!(health.get("components").is_some());
146
147        // Test metrics
148        let metrics = endpoints.metrics().await.unwrap();
149        assert!(metrics.get("monitoring_stats").is_some());
150        assert!(metrics.get("performance_metrics").is_some());
151
152        // Test episode metrics
153        let episode_metrics = endpoints.episode_metrics().await.unwrap();
154        assert!(episode_metrics.get("episode_metrics").is_some());
155
156        // Test system info
157        let system_info = endpoints.system_info().await.unwrap();
158        assert!(system_info.get("version").is_some());
159        assert!(system_info.get("uptime_seconds").is_some());
160    }
161}