Sujatha commited on
Commit
3d8cd15
·
verified ·
1 Parent(s): cc8df21

Create monitoring_system.py

Browse files
Files changed (1) hide show
  1. monitoring_system.py +381 -0
monitoring_system.py ADDED
@@ -0,0 +1,381 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Monitoring System - Layer 4: System monitoring and analytics (Free Version)
3
+ Lightweight monitoring for Hugging Face Spaces
4
+ """
5
+
6
+ import time
7
+ from typing import Dict, List, Any, Optional
8
+ from datetime import datetime, timedelta
9
+ from dataclasses import dataclass
10
+ import json
11
+ import pandas as pd
12
+ import numpy as np
13
+
14
+
15
+ @dataclass
16
+ class Alert:
17
+ """Monitoring alert"""
18
+ id: str
19
+ severity: str # info, warning, error
20
+ source: str
21
+ message: str
22
+ timestamp: datetime
23
+ acknowledged: bool = False
24
+ resolved: bool = False
25
+
26
+
27
+ @dataclass
28
+ class PerformanceSnapshot:
29
+ """Performance snapshot"""
30
+ timestamp: datetime
31
+ metrics: Dict[str, Any]
32
+ agent_status: Dict[str, str]
33
+
34
+
35
+ class MonitoringSystem:
36
+ """Lightweight monitoring system for free Hugging Face Spaces"""
37
+
38
+ def __init__(self, max_history: int = 1000):
39
+ self.alerts: List[Alert] = []
40
+ self.performance_history: List[PerformanceSnapshot] = []
41
+ self.max_history = max_history
42
+
43
+ # System metrics
44
+ self.system_metrics = {
45
+ 'start_time': datetime.now(),
46
+ 'total_queries': 0,
47
+ 'successful_queries': 0,
48
+ 'failed_queries': 0,
49
+ 'active_sessions': 0,
50
+ 'peak_memory_mb': 0,
51
+ 'average_response_time': 0.0
52
+ }
53
+
54
+ # Agent metrics
55
+ self.agent_metrics = {
56
+ 'diagnostician': {'calls': 0, 'avg_time': 0.0, 'errors': 0},
57
+ 'socratic_tutor': {'calls': 0, 'avg_time': 0.0, 'errors': 0},
58
+ 'calculator': {'calls': 0, 'avg_time': 0.0, 'errors': 0},
59
+ 'knowledge_expert': {'calls': 0, 'avg_time': 0.0, 'errors': 0},
60
+ 'practice_generator': {'calls': 0, 'avg_time': 0.0, 'errors': 0},
61
+ 'assessment': {'calls': 0, 'avg_time': 0.0, 'errors': 0}
62
+ }
63
+
64
+ # Alert rules
65
+ self.alert_rules = [
66
+ {
67
+ 'condition': lambda metrics: metrics.get('failed_queries', 0) > 10,
68
+ 'severity': 'warning',
69
+ 'message': 'High number of failed queries detected'
70
+ },
71
+ {
72
+ 'condition': lambda metrics: metrics.get('average_response_time', 0) > 5.0,
73
+ 'severity': 'warning',
74
+ 'message': 'Slow response times detected'
75
+ }
76
+ ]
77
+
78
+ def update_metrics(self):
79
+ """Update system metrics (called periodically)"""
80
+ # Create snapshot
81
+ snapshot = PerformanceSnapshot(
82
+ timestamp=datetime.now(),
83
+ metrics=self.system_metrics.copy(),
84
+ agent_status={agent: 'active' for agent in self.agent_metrics.keys()}
85
+ )
86
+
87
+ self.performance_history.append(snapshot)
88
+
89
+ # Keep history within limits
90
+ if len(self.performance_history) > self.max_history:
91
+ self.performance_history = self.performance_history[-self.max_history:]
92
+
93
+ # Check alerts
94
+ self._check_alerts()
95
+
96
+ # Cleanup old alerts
97
+ self._cleanup_alerts()
98
+
99
+ def record_query(self, success: bool, response_time: float = 0.0):
100
+ """Record a query"""
101
+ self.system_metrics['total_queries'] += 1
102
+
103
+ if success:
104
+ self.system_metrics['successful_queries'] += 1
105
+ else:
106
+ self.system_metrics['failed_queries'] += 1
107
+
108
+ # Update average response time
109
+ n = self.system_metrics['total_queries']
110
+ current_avg = self.system_metrics['average_response_time']
111
+ self.system_metrics['average_response_time'] = (
112
+ (current_avg * (n - 1) + response_time) / n if n > 1 else response_time
113
+ )
114
+
115
+ def record_agent_call(self, agent_name: str, success: bool, execution_time: float):
116
+ """Record an agent call"""
117
+ if agent_name in self.agent_metrics:
118
+ metrics = self.agent_metrics[agent_name]
119
+ metrics['calls'] += 1
120
+
121
+ # Update average time
122
+ n = metrics['calls']
123
+ current_avg = metrics['avg_time']
124
+ metrics['avg_time'] = (
125
+ (current_avg * (n - 1) + execution_time) / n if n > 1 else execution_time
126
+ )
127
+
128
+ if not success:
129
+ metrics['errors'] += 1
130
+
131
+ def get_system_metrics(self) -> Dict[str, Any]:
132
+ """Get current system metrics"""
133
+ # Calculate uptime
134
+ uptime = datetime.now() - self.system_metrics['start_time']
135
+ uptime_hours = uptime.total_seconds() / 3600
136
+
137
+ # Calculate success rate
138
+ total = self.system_metrics['total_queries']
139
+ successful = self.system_metrics['successful_queries']
140
+ success_rate = successful / total if total > 0 else 1.0
141
+
142
+ # Calculate active agents
143
+ active_agents = sum(1 for metrics in self.agent_metrics.values() if metrics['calls'] > 0)
144
+
145
+ # Get recent performance
146
+ recent_snapshots = [s for s in self.performance_history
147
+ if s.timestamp > datetime.now() - timedelta(hours=1)]
148
+
149
+ avg_response_time = self.system_metrics['average_response_time']
150
+
151
+ if recent_snapshots:
152
+ recent_times = [s.metrics.get('average_response_time', 0) for s in recent_snapshots]
153
+ avg_response_time = sum(recent_times) / len(recent_times)
154
+
155
+ return {
156
+ 'uptime_hours': uptime_hours,
157
+ 'total_queries': total,
158
+ 'successful_queries': successful,
159
+ 'failed_queries': self.system_metrics['failed_queries'],
160
+ 'success_rate': success_rate,
161
+ 'avg_response_time': avg_response_time,
162
+ 'active_agents': active_agents,
163
+ 'knowledge_coverage': self._estimate_knowledge_coverage(),
164
+ 'system_health': self._calculate_system_health()
165
+ }
166
+
167
+ def _estimate_knowledge_coverage(self) -> float:
168
+ """Estimate knowledge coverage percentage"""
169
+ # Simulated based on agent usage
170
+ total_calls = sum(metrics['calls'] for metrics in self.agent_metrics.values())
171
+ if total_calls == 0:
172
+ return 0.7 # Default coverage
173
+
174
+ # More calls to knowledge expert indicates better coverage
175
+ knowledge_calls = self.agent_metrics.get('knowledge_expert', {}).get('calls', 0)
176
+ coverage = 0.7 + (knowledge_calls / max(total_calls, 1)) * 0.3
177
+
178
+ return min(coverage, 0.95)
179
+
180
+ def _calculate_system_health(self) -> float:
181
+ """Calculate overall system health score (0-100)"""
182
+ # Based on success rate and response time
183
+ success_rate = self.get_system_metrics()['success_rate']
184
+ avg_response_time = self.get_system_metrics()['avg_response_time']
185
+
186
+ # Success component (0-70 points)
187
+ success_score = success_rate * 70
188
+
189
+ # Response time component (0-30 points, faster = better)
190
+ if avg_response_time < 1.0:
191
+ response_score = 30
192
+ elif avg_response_time < 3.0:
193
+ response_score = 20
194
+ elif avg_response_time < 5.0:
195
+ response_score = 10
196
+ else:
197
+ response_score = 0
198
+
199
+ health_score = success_score + response_score
200
+ return min(health_score, 100)
201
+
202
+ def _check_alerts(self):
203
+ """Check for alert conditions"""
204
+ metrics = self.get_system_metrics()
205
+
206
+ for rule in self.alert_rules:
207
+ if rule['condition'](metrics):
208
+ self._create_alert(
209
+ severity=rule['severity'],
210
+ source='system',
211
+ message=rule['message']
212
+ )
213
+
214
+ def _create_alert(self, severity: str, source: str, message: str):
215
+ """Create a new alert"""
216
+ alert_id = f"alert_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{len(self.alerts)}"
217
+
218
+ alert = Alert(
219
+ id=alert_id,
220
+ severity=severity,
221
+ source=source,
222
+ message=message,
223
+ timestamp=datetime.now()
224
+ )
225
+
226
+ self.alerts.append(alert)
227
+ print(f"🚨 Alert: {severity.upper()} - {message}")
228
+
229
+ def _cleanup_alerts(self):
230
+ """Cleanup old alerts"""
231
+ # Keep only last 50 alerts
232
+ if len(self.alerts) > 50:
233
+ self.alerts = self.alerts[-50:]
234
+
235
+ # Auto-resolve old info alerts (24 hours)
236
+ cutoff = datetime.now() - timedelta(hours=24)
237
+ for alert in self.alerts:
238
+ if alert.severity == 'info' and alert.timestamp < cutoff:
239
+ alert.resolved = True
240
+
241
+ def get_agent_logs(self, limit: int = 20) -> pd.DataFrame:
242
+ """Get agent activity logs"""
243
+ logs = []
244
+
245
+ for agent, metrics in self.agent_metrics.items():
246
+ if metrics['calls'] > 0:
247
+ logs.append({
248
+ 'agent': agent,
249
+ 'calls': metrics['calls'],
250
+ 'avg_time': metrics['avg_time'],
251
+ 'error_rate': metrics['errors'] / metrics['calls'] if metrics['calls'] > 0 else 0,
252
+ 'status': 'active' if metrics['calls'] > 0 else 'inactive'
253
+ })
254
+
255
+ if logs:
256
+ df = pd.DataFrame(logs)
257
+ return df.sort_values('calls', ascending=False).head(limit)
258
+
259
+ return pd.DataFrame(columns=['agent', 'calls', 'avg_time', 'error_rate', 'status'])
260
+
261
+ def get_active_alerts(self) -> List[Alert]:
262
+ """Get active (unresolved) alerts"""
263
+ return [a for a in self.alerts if not a.resolved]
264
+
265
+ def acknowledge_alert(self, alert_id: str) -> bool:
266
+ """Acknowledge an alert"""
267
+ for alert in self.alerts:
268
+ if alert.id == alert_id:
269
+ alert.acknowledged = True
270
+ return True
271
+ return False
272
+
273
+ def resolve_alert(self, alert_id: str) -> bool:
274
+ """Resolve an alert"""
275
+ for alert in self.alerts:
276
+ if alert.id == alert_id:
277
+ alert.resolved = True
278
+ return True
279
+ return False
280
+
281
+ def get_performance_report(self, period: str = '1h') -> Dict[str, Any]:
282
+ """Get performance report for a period"""
283
+ # Calculate time cutoff
284
+ if period == '1h':
285
+ cutoff = datetime.now() - timedelta(hours=1)
286
+ elif period == '24h':
287
+ cutoff = datetime.now() - timedelta(hours=24)
288
+ else:
289
+ cutoff = datetime.now() - timedelta(minutes=30)
290
+
291
+ # Filter snapshots
292
+ period_snapshots = [s for s in self.performance_history if s.timestamp > cutoff]
293
+
294
+ if not period_snapshots:
295
+ current_metrics = self.get_system_metrics()
296
+ return {
297
+ 'period': period,
298
+ 'data_points': 0,
299
+ 'current_metrics': current_metrics,
300
+ 'trend': 'insufficient_data'
301
+ }
302
+
303
+ # Calculate period metrics
304
+ total_queries = sum(s.metrics.get('total_queries', 0) for s in period_snapshots)
305
+ successful_queries = sum(s.metrics.get('successful_queries', 0) for s in period_snapshots)
306
+
307
+ response_times = [s.metrics.get('average_response_time', 0) for s in period_snapshots]
308
+ avg_response_time = sum(response_times) / len(response_times) if response_times else 0
309
+
310
+ # Calculate trend
311
+ if len(period_snapshots) >= 2:
312
+ first_half = period_snapshots[:len(period_snapshots)//2]
313
+ second_half = period_snapshots[len(period_snapshots)//2:]
314
+
315
+ first_rate = sum(s.metrics.get('successful_queries', 0) for s in first_half) / max(sum(s.metrics.get('total_queries', 0) for s in first_half), 1)
316
+ second_rate = sum(s.metrics.get('successful_queries', 0) for s in second_half) / max(sum(s.metrics.get('total_queries', 0) for s in second_half), 1)
317
+
318
+ if second_rate > first_rate * 1.1:
319
+ trend = 'improving'
320
+ elif second_rate < first_rate * 0.9:
321
+ trend = 'declining'
322
+ else:
323
+ trend = 'stable'
324
+ else:
325
+ trend = 'stable'
326
+
327
+ current_metrics = self.get_system_metrics()
328
+
329
+ return {
330
+ 'period': period,
331
+ 'data_points': len(period_snapshots),
332
+ 'queries_in_period': total_queries,
333
+ 'success_rate_period': successful_queries / total_queries if total_queries > 0 else 0,
334
+ 'avg_response_time_period': avg_response_time,
335
+ 'current_metrics': current_metrics,
336
+ 'trend': trend,
337
+ 'health_score': current_metrics['system_health'],
338
+ 'recommendations': self._generate_recommendations(current_metrics)
339
+ }
340
+
341
+ def _generate_recommendations(self, metrics: Dict[str, Any]) -> List[str]:
342
+ """Generate recommendations based on metrics"""
343
+ recommendations = []
344
+
345
+ if metrics['success_rate'] < 0.8:
346
+ recommendations.append('Improve query success rate by simplifying complex queries')
347
+
348
+ if metrics['avg_response_time'] > 3.0:
349
+ recommendations.append('Optimize response time by caching frequent queries')
350
+
351
+ if metrics['knowledge_coverage'] < 0.8:
352
+ recommendations.append('Expand knowledge base coverage for better answers')
353
+
354
+ if not recommendations:
355
+ recommendations.append('System performance is good. Maintain current operations.')
356
+
357
+ return recommendations[:3]
358
+
359
+ def reset_metrics(self):
360
+ """Reset all metrics (for testing or restart)"""
361
+ self.system_metrics = {
362
+ 'start_time': datetime.now(),
363
+ 'total_queries': 0,
364
+ 'successful_queries': 0,
365
+ 'failed_queries': 0,
366
+ 'active_sessions': 0,
367
+ 'peak_memory_mb': 0,
368
+ 'average_response_time': 0.0
369
+ }
370
+
371
+ for agent in self.agent_metrics:
372
+ self.agent_metrics[agent] = {'calls': 0, 'avg_time': 0.0, 'errors': 0}
373
+
374
+ self.performance_history = []
375
+ self.alerts = []
376
+
377
+ print("🔄 Monitoring metrics reset")
378
+
379
+
380
+ # Create global instance
381
+ monitoring_system = MonitoringSystem()