fix htmx refactor route mismatches and remaining TODO items
- wireguard: POST /peers with JSON encoding (was /add-peer) - rules: delete by rule_id in URL path (was JSON body); pass rule objects with id from server; add hx-disable to initial render - nat: port forward delete uses URL path params to match blueprint - nat: masquerade toggle uses native hx-post/hx-vals (was inline fetch) - app.js renderers updated to use URL path deletes for rules and forwards - remove TODO.md
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
"""
|
||||
logging - Centralized logging configuration for Vacuum Wall.
|
||||
|
||||
Call :func:`setup_logging` once at application startup. All other
|
||||
modules obtain a logger via ``logging.getLogger(__name__)``.
|
||||
|
||||
Output:
|
||||
* **stderr** (StreamHandler) - captured by systemd journald
|
||||
* **data/logs/vacuum-wall.log** (RotatingFileHandler) - persisted for
|
||||
viewing via the WebUI ``/logs`` page.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from logging.handlers import RotatingFileHandler
|
||||
from pathlib import Path
|
||||
|
||||
PROJECT_DIR = Path(__file__).resolve().parent.parent
|
||||
_LOG_DIR = PROJECT_DIR / "data" / "logs"
|
||||
_LOG_FILE = _LOG_DIR / "vacuum-wall.log"
|
||||
|
||||
_MAX_BYTES = 5 * 1024 * 1024 # 5 MB
|
||||
_BACKUP_COUNT = 3
|
||||
|
||||
_LOG_FMT = "[%(asctime)s] %(levelname)-8s %(name)s %(message)s"
|
||||
_DATE_FMT = "%Y-%m-%d %H:%M:%S"
|
||||
|
||||
_initialized = False
|
||||
|
||||
|
||||
def setup_logging(level: str | None = None) -> None:
|
||||
"""Configure and enable root-level logging for the application.
|
||||
|
||||
Safe to call multiple times; subsequent calls are no-ops.
|
||||
|
||||
Args:
|
||||
level: Override log level string (e.g. ``"DEBUG"``). If ``None``,
|
||||
reads ``VACUUM_WALL_LOG_LEVEL`` from the environment, defaulting
|
||||
to ``"INFO"``.
|
||||
"""
|
||||
global _initialized
|
||||
if _initialized:
|
||||
return
|
||||
_initialized = True
|
||||
|
||||
if level is None:
|
||||
level = os.environ.get("VACUUM_WALL_LOG_LEVEL", "INFO").upper()
|
||||
|
||||
valid_levels = {
|
||||
"DEBUG": logging.DEBUG,
|
||||
"INFO": logging.INFO,
|
||||
"WARNING": logging.WARNING,
|
||||
"ERROR": logging.ERROR,
|
||||
"CRITICAL": logging.CRITICAL,
|
||||
}
|
||||
numeric = valid_levels.get(level, logging.INFO)
|
||||
|
||||
root = logging.getLogger()
|
||||
root.setLevel(numeric)
|
||||
|
||||
fmt = logging.Formatter(_LOG_FMT, datefmt=_DATE_FMT)
|
||||
|
||||
# stderr handler — feeds systemd journal
|
||||
sh = logging.StreamHandler(sys.stderr)
|
||||
sh.setFormatter(fmt)
|
||||
root.addHandler(sh)
|
||||
|
||||
# rotating file handler
|
||||
_LOG_DIR.mkdir(parents=True, exist_ok=True)
|
||||
fh = RotatingFileHandler(
|
||||
str(_LOG_FILE),
|
||||
maxBytes=_MAX_BYTES,
|
||||
backupCount=_BACKUP_COUNT,
|
||||
)
|
||||
fh.setFormatter(fmt)
|
||||
root.addHandler(fh)
|
||||
|
||||
# Silence noisy third-party loggers in production
|
||||
for name in ("werkzeug", "urllib3"):
|
||||
logging.getLogger(name).setLevel(logging.WARNING)
|
||||
Reference in New Issue
Block a user