Update docs and screenshots
CI / backend (pull_request) Canceled after 0s
CI / shell (pull_request) Canceled after 0s
CI / frontend (pull_request) Canceled after 0s
CI / arm64-smoke (pull_request) Canceled after 0s
CI / backend (push) Canceled after 0s
CI / shell (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / arm64-smoke (push) Canceled after 0s
CI / backend (pull_request) Canceled after 0s
CI / shell (pull_request) Canceled after 0s
CI / frontend (pull_request) Canceled after 0s
CI / arm64-smoke (pull_request) Canceled after 0s
CI / backend (push) Canceled after 0s
CI / shell (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / arm64-smoke (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
"""Telemetry services."""
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections import deque
|
||||
from dataclasses import dataclass
|
||||
from datetime import UTC, datetime
|
||||
from time import monotonic
|
||||
|
||||
import psutil
|
||||
|
||||
from app.dmx.backends import BackendStatus
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class TelemetryEvent:
|
||||
created_at: datetime
|
||||
category: str
|
||||
level: str
|
||||
message: str
|
||||
|
||||
|
||||
class TelemetryService:
|
||||
def __init__(self) -> None:
|
||||
self.started_at = monotonic()
|
||||
self.events: deque[TelemetryEvent] = deque(maxlen=1000)
|
||||
self.last_sent_at: datetime | None = None
|
||||
self.last_error: str | None = None
|
||||
self.reconnect_count = 0
|
||||
self.frames_sent = 0
|
||||
self.send_errors = 0
|
||||
|
||||
def record_send_success(self, status: BackendStatus) -> None:
|
||||
self.last_sent_at = datetime.now(UTC)
|
||||
self.last_error = None
|
||||
self.reconnect_count = status.reconnect_count
|
||||
self.frames_sent = status.frames_sent
|
||||
self.send_errors = status.send_errors
|
||||
|
||||
def record_send_failure(self, error: str, status: BackendStatus) -> None:
|
||||
self.last_error = error
|
||||
self.reconnect_count = status.reconnect_count
|
||||
self.frames_sent = status.frames_sent
|
||||
self.send_errors = status.send_errors
|
||||
self.events.append(
|
||||
TelemetryEvent(datetime.now(UTC), "DMX", "ERROR", error)
|
||||
)
|
||||
|
||||
def snapshot(self, queue_depth: int = 0) -> dict[str, object]:
|
||||
temperature = None
|
||||
try:
|
||||
readings = psutil.sensors_temperatures()
|
||||
if readings:
|
||||
first = next(iter(readings.values()))
|
||||
if first:
|
||||
temperature = float(first[0].current)
|
||||
except Exception:
|
||||
temperature = None
|
||||
|
||||
return {
|
||||
"uptime_seconds": round(monotonic() - self.started_at, 2),
|
||||
"cpu_percent": psutil.cpu_percent(interval=None),
|
||||
"ram_percent": psutil.virtual_memory().percent,
|
||||
"temperature_c": temperature,
|
||||
"queue_depth": queue_depth,
|
||||
"reconnect_count": self.reconnect_count,
|
||||
"last_error": self.last_error,
|
||||
"last_sent_at": self.last_sent_at,
|
||||
"frames_sent": self.frames_sent,
|
||||
"send_errors": self.send_errors,
|
||||
"events": [
|
||||
{
|
||||
"created_at": event.created_at.isoformat(),
|
||||
"category": event.category,
|
||||
"level": event.level,
|
||||
"message": event.message,
|
||||
}
|
||||
for event in list(self.events)[-50:]
|
||||
],
|
||||
}
|
||||
Reference in New Issue
Block a user