Complete DDS training workflow and delivery package

This commit is contained in:
andreysk0304 2026-09-24 01:10:49 +03:00
commit 4c4b91064f
229 changed files with 11969 additions and 1024 deletions

167
backend/app/monitoring.py Normal file
View file

@ -0,0 +1,167 @@
"""Small, dependency-free runtime diagnostics for the local stand.
The product has to run on Windows as well as Linux. Keep the collector in
the standard library: unavailable host counters are returned as ``None``
instead of making the administrator screen fail.
"""
from __future__ import annotations
import logging
import os
import re
import shutil
import sys
import threading
import time
from collections import deque
from datetime import datetime, timezone
from pathlib import Path
STARTED_MONOTONIC = time.monotonic()
_events: deque[dict] = deque(maxlen=500)
_installed = False
_sample_lock = threading.Lock()
_last_wall = time.monotonic()
_last_cpu = time.process_time()
_CREDENTIALS = re.compile(r"(://[^:/\s]+:)([^@/\s]+)(@)")
_TOKENS = re.compile(
r"(?i)\b(session_secret|llm_api_key|authorization|password)\b\s*[:=]\s*([^\s,;]+)"
)
def _safe(message: str) -> str:
message = _CREDENTIALS.sub(r"\1[скрыто]\3", message)
message = _TOKENS.sub(r"\1=[скрыто]", message)
return message.replace("\x00", "")[:2000]
class DiagnosticHandler(logging.Handler):
"""Bounded warning/error journal safe enough to expose to an admin."""
def emit(self, record: logging.LogRecord) -> None:
try:
_events.append({
"at": datetime.fromtimestamp(record.created, timezone.utc),
"level": record.levelname,
"source": record.name[:120],
"message": _safe(record.getMessage()),
})
except Exception: # logging must never take the service down
pass
def install_diagnostics() -> None:
global _installed
if _installed:
return
handler = DiagnosticHandler(level=logging.WARNING)
logging.getLogger().addHandler(handler)
_installed = True
def recent_events(*, limit: int = 100) -> list[dict]:
return list(_events)[-max(1, min(limit, 500)):][::-1]
def _rss_bytes() -> int | None:
try:
if sys.platform.startswith("linux"):
resident_pages = int(Path("/proc/self/statm").read_text().split()[1])
return resident_pages * int(os.sysconf("SC_PAGE_SIZE"))
if os.name == "nt":
import ctypes
from ctypes import wintypes
class Counters(ctypes.Structure):
_fields_ = [
("cb", wintypes.DWORD), ("PageFaultCount", wintypes.DWORD),
("PeakWorkingSetSize", ctypes.c_size_t),
("WorkingSetSize", ctypes.c_size_t),
("QuotaPeakPagedPoolUsage", ctypes.c_size_t),
("QuotaPagedPoolUsage", ctypes.c_size_t),
("QuotaPeakNonPagedPoolUsage", ctypes.c_size_t),
("QuotaNonPagedPoolUsage", ctypes.c_size_t),
("PagefileUsage", ctypes.c_size_t),
("PeakPagefileUsage", ctypes.c_size_t),
]
counters = Counters()
counters.cb = ctypes.sizeof(counters)
ctypes.windll.psapi.GetProcessMemoryInfo( # type: ignore[attr-defined]
ctypes.windll.kernel32.GetCurrentProcess(), ctypes.byref(counters), counters.cb
)
return int(counters.WorkingSetSize)
import resource
value = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
return int(value if sys.platform == "darwin" else value * 1024)
except (OSError, ValueError, AttributeError, ImportError, IndexError):
return None
def _memory() -> tuple[int | None, int | None]:
try:
if sys.platform.startswith("linux"):
fields: dict[str, int] = {}
for line in Path("/proc/meminfo").read_text().splitlines():
name, value = line.split(":", 1)
fields[name] = int(value.strip().split()[0]) * 1024
return fields.get("MemTotal"), fields.get("MemAvailable")
if os.name == "nt":
import ctypes
class MemoryStatus(ctypes.Structure):
_fields_ = [
("length", ctypes.c_ulong), ("memory_load", ctypes.c_ulong),
("total_physical", ctypes.c_ulonglong),
("available_physical", ctypes.c_ulonglong),
("total_page_file", ctypes.c_ulonglong),
("available_page_file", ctypes.c_ulonglong),
("total_virtual", ctypes.c_ulonglong),
("available_virtual", ctypes.c_ulonglong),
("available_extended_virtual", ctypes.c_ulonglong),
]
status = MemoryStatus()
status.length = ctypes.sizeof(status)
ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(status)) # type: ignore[attr-defined]
return int(status.total_physical), int(status.available_physical)
page = int(os.sysconf("SC_PAGE_SIZE"))
return int(os.sysconf("SC_PHYS_PAGES")) * page, None
except (OSError, ValueError, AttributeError, ImportError):
return None, None
def sample_metrics() -> dict:
"""Return a cheap point-in-time sample; the first CPU sample is zero."""
global _last_wall, _last_cpu
now = time.monotonic()
cpu_now = time.process_time()
with _sample_lock:
wall_delta = max(now - _last_wall, 0.001)
cpu_percent = max(0.0, (cpu_now - _last_cpu) / wall_delta * 100.0)
_last_wall, _last_cpu = now, cpu_now
cores = os.cpu_count() or 1
try:
load_1m_percent = os.getloadavg()[0] / cores * 100.0
except (AttributeError, OSError):
load_1m_percent = None
memory_total, memory_available = _memory()
disk = shutil.disk_usage(Path.cwd())
return {
"at": datetime.now(timezone.utc),
"uptime_seconds": max(0.0, now - STARTED_MONOTONIC),
"cpu_percent": round(cpu_percent, 2),
"load_1m_percent": round(load_1m_percent, 2) if load_1m_percent is not None else None,
"cpu_cores": cores,
"rss_bytes": _rss_bytes(),
"memory_total_bytes": memory_total,
"memory_available_bytes": memory_available,
"disk_total_bytes": disk.total,
"disk_free_bytes": disk.free,
"threads": threading.active_count(),
}