"""Logs daemon handler. Reads system logs and journal entries. """ import logging from pathlib import Path from daemon.server import registry from lib.common import run_proc logger = logging.getLogger(__name__) PROJECT_DIR = Path(__file__).resolve().parent.parent.parent _APP_LOG_FILE = PROJECT_DIR / "data" / "logs" / "vacuum-wall.log" _MAX_LINES = 200 def _tail_file(path: str, n: int = _MAX_LINES, sudo: bool = False) -> str: """Return the last N lines of a file, optionally via sudo. Args: path: Absolute path to the file to read. n: Number of trailing lines to return. sudo: Whether to use sudo to access the file. Returns: Truncated file content or an error message string. """ try: if sudo: result = run_proc(["cat", path], sudo=True) lines = result.stdout.splitlines(keepends=True) else: with open(path) as f: lines = f.readlines() return "".join(lines[-n:]) except FileNotFoundError: return "(log file not found)\n" except PermissionError: return "(permission denied)\n" def _sudo_journalctl(unit: str, n: int = _MAX_LINES) -> str: """Return recent journalctl output for a systemd unit via sudo. Args: unit: Systemd unit name to query. n: Number of journal lines to return. Returns: Journal output or an error message string. """ try: result = run_proc( ["journalctl", "--unit=" + unit, "-n", str(n)], sudo=True, check=False, timeout=10, ) output = result.stdout.strip() return output if output else f"(no journal entries for {unit})\n" except Exception as exc: return f"(error reading journal: {exc})\n" @registry.register("GET", "/logs/journal") def journal(_request, _body) -> str: """GET /logs/journal — return vacuum-wall daemon journal entries.""" return _sudo_journalctl("vacuum-wall") @registry.register("GET", "/logs/nginx/access") def nginx_access(_request, _body) -> str: """GET /logs/nginx/access — return recent nginx access log lines.""" return _tail_file("/var/log/nginx/access.log", sudo=True) @registry.register("GET", "/logs/nginx/error") def nginx_error(_request, _body) -> str: """GET /logs/nginx/error — return recent nginx error log lines.""" return _tail_file("/var/log/nginx/error.log", sudo=True) @registry.register("GET", "/logs/dnsmasq") def dnsmasq_log(_request, _body) -> str: """GET /logs/dnsmasq — return recent dnsmasq journal entries.""" return _sudo_journalctl("dnsmasq") @registry.register("GET", "/logs/app") def app_log(_request, _body) -> str: """GET /logs/app — return recent application log lines.""" return _tail_file(str(_APP_LOG_FILE))