|
@@ -32,25 +32,54 @@ async def get_recent_host_metrics(
|
|
|
metrics = list(result.scalars().all())
|
|
metrics = list(result.scalars().all())
|
|
|
|
|
|
|
|
# Return in chronological order
|
|
# Return in chronological order
|
|
|
- return [
|
|
|
|
|
- {
|
|
|
|
|
- "timestamp": m.timestamp.isoformat(),
|
|
|
|
|
- "cpu_percent": m.cpu_percent,
|
|
|
|
|
- "cpu_count": m.cpu_count,
|
|
|
|
|
- "memory_total": m.memory_total,
|
|
|
|
|
- "memory_used": m.memory_used,
|
|
|
|
|
- "memory_percent": m.memory_percent,
|
|
|
|
|
- "load_1": m.load_1,
|
|
|
|
|
- "load_5": m.load_5,
|
|
|
|
|
- "load_15": m.load_15,
|
|
|
|
|
- "disk_read_bytes": m.disk_read_bytes,
|
|
|
|
|
- "disk_write_bytes": m.disk_write_bytes,
|
|
|
|
|
- "disk_usage_percent": m.disk_usage_percent,
|
|
|
|
|
- "net_sent_bytes": m.net_sent_bytes,
|
|
|
|
|
- "net_recv_bytes": m.net_recv_bytes,
|
|
|
|
|
- }
|
|
|
|
|
- for m in reversed(metrics)
|
|
|
|
|
- ]
|
|
|
|
|
|
|
+ return {
|
|
|
|
|
+ "metrics": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "timestamp": m.timestamp.isoformat(),
|
|
|
|
|
+ "cpu_percent": m.cpu_percent,
|
|
|
|
|
+ "cpu_count": m.cpu_count,
|
|
|
|
|
+ "cpu_per_core": m.cpu_per_core,
|
|
|
|
|
+ "cpu_steal": m.cpu_steal,
|
|
|
|
|
+ "context_switches_per_sec": m.context_switches_per_sec,
|
|
|
|
|
+ "interrupts_per_sec": m.interrupts_per_sec,
|
|
|
|
|
+ "memory_total": m.memory_total,
|
|
|
|
|
+ "memory_used": m.memory_used,
|
|
|
|
|
+ "memory_percent": m.memory_percent,
|
|
|
|
|
+ "memory_available": m.memory_available,
|
|
|
|
|
+ "memory_buffers": m.memory_buffers,
|
|
|
|
|
+ "memory_cached": m.memory_cached,
|
|
|
|
|
+ "swap_total": m.swap_total,
|
|
|
|
|
+ "swap_used": m.swap_used,
|
|
|
|
|
+ "swap_percent": m.swap_percent,
|
|
|
|
|
+ "load_1": m.load_1,
|
|
|
|
|
+ "load_5": m.load_5,
|
|
|
|
|
+ "load_15": m.load_15,
|
|
|
|
|
+ "disk_read_bytes": m.disk_read_bytes,
|
|
|
|
|
+ "disk_write_bytes": m.disk_write_bytes,
|
|
|
|
|
+ "disk_read_iops": m.disk_read_iops,
|
|
|
|
|
+ "disk_write_iops": m.disk_write_iops,
|
|
|
|
|
+ "disk_read_mbps": m.disk_read_mbps,
|
|
|
|
|
+ "disk_write_mbps": m.disk_write_mbps,
|
|
|
|
|
+ "disk_io_time_ms": m.disk_io_time_ms,
|
|
|
|
|
+ "disk_usage_percent": m.disk_usage_percent,
|
|
|
|
|
+ "net_sent_bytes": m.net_sent_bytes,
|
|
|
|
|
+ "net_recv_bytes": m.net_recv_bytes,
|
|
|
|
|
+ "net_in_mbps": m.net_in_mbps,
|
|
|
|
|
+ "net_out_mbps": m.net_out_mbps,
|
|
|
|
|
+ "net_packets_in_per_sec": m.net_packets_in_per_sec,
|
|
|
|
|
+ "net_packets_out_per_sec": m.net_packets_out_per_sec,
|
|
|
|
|
+ "net_errors_in": m.net_errors_in,
|
|
|
|
|
+ "net_errors_out": m.net_errors_out,
|
|
|
|
|
+ "net_drops_in": m.net_drops_in,
|
|
|
|
|
+ "net_drops_out": m.net_drops_out,
|
|
|
|
|
+ "process_count": m.process_count,
|
|
|
|
|
+ "thread_count": m.thread_count,
|
|
|
|
|
+ "top_cpu_processes": m.top_cpu_processes,
|
|
|
|
|
+ "top_mem_processes": m.top_mem_processes,
|
|
|
|
|
+ }
|
|
|
|
|
+ for m in reversed(metrics)
|
|
|
|
|
+ ]
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("/host-metrics/history")
|
|
@router.get("/host-metrics/history")
|
|
@@ -93,11 +122,12 @@ async def get_host_metrics_history(
|
|
|
@router.get("/alerts")
|
|
@router.get("/alerts")
|
|
|
async def get_alerts(
|
|
async def get_alerts(
|
|
|
dismissed: bool = Query(default=False),
|
|
dismissed: bool = Query(default=False),
|
|
|
|
|
+ limit: int = Query(default=100, le=1000),
|
|
|
db: AsyncSession = Depends(get_db),
|
|
db: AsyncSession = Depends(get_db),
|
|
|
_current_user=Depends(get_current_superadmin),
|
|
_current_user=Depends(get_current_superadmin),
|
|
|
):
|
|
):
|
|
|
"""Get alerts (by default only active/non-dismissed alerts)."""
|
|
"""Get alerts (by default only active/non-dismissed alerts)."""
|
|
|
- query = select(Alert).order_by(Alert.timestamp.desc())
|
|
|
|
|
|
|
+ query = select(Alert).order_by(Alert.timestamp.desc()).limit(limit)
|
|
|
|
|
|
|
|
if not dismissed:
|
|
if not dismissed:
|
|
|
query = query.where(Alert.dismissed == False)
|
|
query = query.where(Alert.dismissed == False)
|
|
@@ -105,26 +135,29 @@ async def get_alerts(
|
|
|
result = await db.execute(query)
|
|
result = await db.execute(query)
|
|
|
alerts = list(result.scalars().all())
|
|
alerts = list(result.scalars().all())
|
|
|
|
|
|
|
|
- return [
|
|
|
|
|
- {
|
|
|
|
|
- "id": a.id,
|
|
|
|
|
- "timestamp": a.timestamp.isoformat(),
|
|
|
|
|
- "alert_type": a.alert_type,
|
|
|
|
|
- "severity": a.severity,
|
|
|
|
|
- "title": a.title,
|
|
|
|
|
- "message": a.message,
|
|
|
|
|
- "alert_metadata": a.alert_metadata,
|
|
|
|
|
- "acknowledged": a.acknowledged,
|
|
|
|
|
- "acknowledged_at": a.acknowledged_at.isoformat() if a.acknowledged_at else None,
|
|
|
|
|
- "acknowledged_by": a.acknowledged_by,
|
|
|
|
|
- "dismissed": a.dismissed,
|
|
|
|
|
- "dismissed_at": a.dismissed_at.isoformat() if a.dismissed_at else None,
|
|
|
|
|
- "sent_dashboard": a.sent_dashboard,
|
|
|
|
|
- "sent_telegram": a.sent_telegram,
|
|
|
|
|
- "sent_email": a.sent_email,
|
|
|
|
|
- }
|
|
|
|
|
- for a in alerts
|
|
|
|
|
- ]
|
|
|
|
|
|
|
+ return {
|
|
|
|
|
+ "alerts": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "id": a.id,
|
|
|
|
|
+ "timestamp": a.timestamp.isoformat(),
|
|
|
|
|
+ "created_at": a.timestamp.isoformat(), # For frontend compatibility
|
|
|
|
|
+ "alert_type": a.alert_type,
|
|
|
|
|
+ "severity": a.severity,
|
|
|
|
|
+ "title": a.title,
|
|
|
|
|
+ "message": a.message,
|
|
|
|
|
+ "alert_metadata": a.alert_metadata,
|
|
|
|
|
+ "acknowledged": a.acknowledged,
|
|
|
|
|
+ "acknowledged_at": a.acknowledged_at.isoformat() if a.acknowledged_at else None,
|
|
|
|
|
+ "acknowledged_by": a.acknowledged_by,
|
|
|
|
|
+ "dismissed": a.dismissed,
|
|
|
|
|
+ "dismissed_at": a.dismissed_at.isoformat() if a.dismissed_at else None,
|
|
|
|
|
+ "sent_dashboard": a.sent_dashboard,
|
|
|
|
|
+ "sent_telegram": a.sent_telegram,
|
|
|
|
|
+ "sent_email": a.sent_email,
|
|
|
|
|
+ }
|
|
|
|
|
+ for a in alerts
|
|
|
|
|
+ ]
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/alerts/{alert_id}/acknowledge")
|
|
@router.post("/alerts/{alert_id}/acknowledge")
|