mirror of
https://git.ianrenton.com/ian/spothole.git
synced 2026-09-20 06:17:41 +00:00
159 lines
6.0 KiB
Python
159 lines
6.0 KiB
Python
import logging
|
|
import os
|
|
from datetime import datetime
|
|
from threading import Event, Thread
|
|
|
|
import psutil
|
|
import pytz
|
|
|
|
from core.cleanup import CLEANUP_TIMER
|
|
from core.config import SERVER_OWNER_CALLSIGN
|
|
from core.constants import SOFTWARE_VERSION
|
|
from core.data_providers import DATA_PROVIDERS
|
|
from core.data_store import DATA_STORE
|
|
from core.prometheus_metrics_handler import alerts_gauge, memory_use_gauge, spots_gauge
|
|
from telnetserver.telnetserver import TELNET_SERVER
|
|
from webserver.webserver import WEB_SERVER
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class StatusReporter:
|
|
"""Provides a timed update of the application's status data."""
|
|
|
|
def __init__(self, run_interval):
|
|
"""Constructor"""
|
|
|
|
self._run_interval = run_interval
|
|
self._thread = None
|
|
self._stop_event = Event()
|
|
self._startup_time = datetime.now(pytz.UTC)
|
|
|
|
DATA_STORE.status.get()["software_version"] = SOFTWARE_VERSION
|
|
DATA_STORE.status.get()["server_owner_callsign"] = SERVER_OWNER_CALLSIGN
|
|
DATA_STORE.status.store()
|
|
|
|
def start(self):
|
|
"""Start the reporter thread"""
|
|
|
|
self._thread = Thread(target=self._run, name="StatusReporter", daemon=True)
|
|
self._thread.start()
|
|
|
|
def stop(self):
|
|
"""Stop any threads and prepare for application shutdown"""
|
|
|
|
self._stop_event.set()
|
|
if self._thread:
|
|
self._thread.join(timeout=15)
|
|
if self._thread.is_alive():
|
|
logger.warning("Status reporter worker thread did not exit on time and will be killed.")
|
|
|
|
def _run(self):
|
|
"""Thread entry point: report immediately on startup, then on each interval until stopped"""
|
|
|
|
while True:
|
|
self._report()
|
|
if self._stop_event.wait(timeout=self._run_interval):
|
|
break
|
|
|
|
def _report(self):
|
|
"""Write status information"""
|
|
|
|
DATA_STORE.status.get()["uptime"] = (datetime.now(pytz.UTC) - self._startup_time).total_seconds()
|
|
DATA_STORE.status.get()["mem_use_mb"] = round(psutil.Process(os.getpid()).memory_info().rss / (1024 * 1024), 3)
|
|
DATA_STORE.status.get()["num_spots"] = len(DATA_STORE.spots.values())
|
|
DATA_STORE.status.get()["num_alerts"] = len(DATA_STORE.alerts.values())
|
|
DATA_STORE.status.get()["spot_providers"] = [
|
|
{
|
|
"name": p.name,
|
|
"enabled": p.enabled,
|
|
"enabled_by_default_in_web_ui": p.enabled_by_default_in_web_ui,
|
|
"status": p.status,
|
|
"last_updated": p.last_update_time.replace(tzinfo=pytz.UTC).timestamp()
|
|
if p.last_update_time.year > 2000
|
|
else 0,
|
|
"last_spot": p.last_spot_time.replace(tzinfo=pytz.UTC).timestamp()
|
|
if p.last_spot_time.year > 2000
|
|
else 0,
|
|
}
|
|
for p in DATA_PROVIDERS.spot_providers
|
|
]
|
|
DATA_STORE.status.get()["alert_providers"] = [
|
|
{
|
|
"name": p.name,
|
|
"enabled": p.enabled,
|
|
"status": p.status,
|
|
"last_updated": p.last_update_time.replace(tzinfo=pytz.UTC).timestamp()
|
|
if p.last_update_time.year > 2000
|
|
else 0,
|
|
}
|
|
for p in DATA_PROVIDERS.alert_providers
|
|
]
|
|
DATA_STORE.status.get()["solar_condition_providers"] = [
|
|
{
|
|
"name": p.name,
|
|
"enabled": p.enabled,
|
|
"status": p.status,
|
|
"last_updated": p.last_update_time.replace(tzinfo=pytz.UTC).timestamp()
|
|
if p.last_update_time.year > 2000
|
|
else 0,
|
|
}
|
|
for p in DATA_PROVIDERS.solar_condition_providers
|
|
]
|
|
DATA_STORE.status.get()["static_data_providers"] = [
|
|
{
|
|
"name": p.name,
|
|
"enabled": p.enabled,
|
|
"status": p.status,
|
|
"last_updated": p.last_update_time.replace(tzinfo=pytz.UTC).timestamp()
|
|
if p.last_update_time.year > 2000
|
|
else 0,
|
|
}
|
|
for p in DATA_PROVIDERS.static_data_providers
|
|
]
|
|
DATA_STORE.status.get()["sig_ref_data_providers"] = [
|
|
{
|
|
"sig_name": p.sig_name,
|
|
"enabled": p.enabled,
|
|
"status": p.status,
|
|
"last_updated": p.last_update_time.replace(tzinfo=pytz.UTC).timestamp()
|
|
if p.last_update_time.year > 2000
|
|
else 0,
|
|
"reference_count": p.reference_count,
|
|
}
|
|
for p in DATA_PROVIDERS.sig_ref_data_providers
|
|
]
|
|
DATA_STORE.status.get()["callsign_data_providers"] = [
|
|
{
|
|
"name": p.name,
|
|
"enabled": p.enabled,
|
|
"status": p.status,
|
|
"last_updated": p.last_update_time.replace(tzinfo=pytz.UTC).timestamp()
|
|
if p.last_update_time.year > 2000
|
|
else 0,
|
|
"lookup_count": p.lookup_count,
|
|
}
|
|
for p in DATA_PROVIDERS.callsign_data_providers
|
|
]
|
|
DATA_STORE.status.get()["cleanup"] = {
|
|
"status": CLEANUP_TIMER.status,
|
|
"last_ran": CLEANUP_TIMER.last_cleanup_time.replace(tzinfo=pytz.UTC).timestamp()
|
|
if CLEANUP_TIMER.last_cleanup_time
|
|
else 0,
|
|
}
|
|
DATA_STORE.status.get()["webserver"] = {
|
|
"status": WEB_SERVER.web_server_metrics.status,
|
|
"api_requests_per_hour": WEB_SERVER.web_server_metrics.api_requests_per_hour(),
|
|
"page_requests_per_hour": WEB_SERVER.web_server_metrics.page_requests_per_hour(),
|
|
"sse_client_count": WEB_SERVER.sse_client_count,
|
|
}
|
|
DATA_STORE.status.get()["telnet"] = {
|
|
"client_count": TELNET_SERVER.client_count,
|
|
}
|
|
DATA_STORE.status.store()
|
|
|
|
# Update Prometheus metrics
|
|
memory_use_gauge.set(psutil.Process(os.getpid()).memory_info().rss)
|
|
spots_gauge.set(len(DATA_STORE.spots.values()))
|
|
alerts_gauge.set(len(DATA_STORE.alerts.values()))
|