from datetime import datetime import asyncio import json async def get_systemd_logs(lines: int = 200, service_name: str = "smartwave") -> list[dict]: """ Asynchronously fetches the last N log entries from a systemd service using native asyncio subprocess execution. """ cmd = ( "journalctl", "-u", service_name, "-n", str(lines), "-o", "json", "--no-pager" ) try: # Create non-blocking child process proc = await asyncio.create_subprocess_exec( *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE ) # Await completion and read output non-blockingly stdout_bytes, stderr_bytes = await proc.communicate() if proc.returncode != 0: print(f"[Logs] journalctl error (code {proc.returncode}): {stderr_bytes.decode('utf-8', errors='replace')}") return [] structured_logs = [] stdout_text = stdout_bytes.decode("utf-8", errors="replace") for line in stdout_text.strip().split("\n"): if not line: continue try: entry = json.loads(line) raw_ts = entry.get("__REALTIME_TIMESTAMP") timestamp_iso = None if raw_ts: timestamp_iso = datetime.fromtimestamp(int(raw_ts) / 1_000_000).isoformat() structured_logs.append({ "timestamp": timestamp_iso, "timestamp_us": int(raw_ts) if raw_ts else None, "message": entry.get("MESSAGE", ""), "priority": entry.get("PRIORITY"), "pid": entry.get("_PID"), }) except (json.JSONDecodeError, ValueError): continue return structured_logs except Exception as e: print(f"[Logs] Failed to read systemd logs for '{service_name}': {e}") return []