Full-stack burn-in orchestration dashboard (Stages 1–6d complete): FastAPI backend, SQLite/WAL, SSE live dashboard, mock TrueNAS server, SMTP/webhook notifications, batch burn-in, settings UI, audit log, stats page, cancel SMART/burn-in, drag-to-reorder stages. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
50 lines
1.6 KiB
Python
50 lines
1.6 KiB
Python
"""
|
|
Structured JSON logging configuration.
|
|
|
|
Each log line is a single JSON object:
|
|
{"ts":"2026-02-21T21:34:36","level":"INFO","logger":"app.burnin","msg":"...","job_id":1}
|
|
|
|
Extra context fields (job_id, drive_id, devname, stage) are included when
|
|
passed via the logging `extra=` kwarg.
|
|
"""
|
|
|
|
import json
|
|
import logging
|
|
import traceback
|
|
|
|
from app.config import settings
|
|
|
|
# Standard LogRecord attributes to exclude from the "extra" dump
|
|
_STDLIB_ATTRS = frozenset(logging.LogRecord("", 0, "", 0, "", (), None).__dict__)
|
|
|
|
|
|
class _JsonFormatter(logging.Formatter):
|
|
def format(self, record: logging.LogRecord) -> str:
|
|
data: dict = {
|
|
"ts": self.formatTime(record, "%Y-%m-%dT%H:%M:%S"),
|
|
"level": record.levelname,
|
|
"logger": record.name,
|
|
"msg": record.getMessage(),
|
|
}
|
|
# Include any non-standard fields passed via extra={}
|
|
for key, val in record.__dict__.items():
|
|
if key not in _STDLIB_ATTRS and not key.startswith("_"):
|
|
data[key] = val
|
|
if record.exc_info:
|
|
data["exc"] = "".join(traceback.format_exception(*record.exc_info)).strip()
|
|
return json.dumps(data)
|
|
|
|
|
|
def configure() -> None:
|
|
handler = logging.StreamHandler()
|
|
handler.setFormatter(_JsonFormatter())
|
|
|
|
level = getattr(logging, settings.log_level.upper(), logging.INFO)
|
|
root = logging.getLogger()
|
|
root.setLevel(level)
|
|
root.handlers = [handler]
|
|
|
|
# Quiet chatty third-party loggers
|
|
logging.getLogger("httpx").setLevel(logging.WARNING)
|
|
logging.getLogger("httpcore").setLevel(logging.WARNING)
|
|
logging.getLogger("uvicorn.access").setLevel(logging.WARNING)
|