feat: structured DEBUG/INFO logging via loguru
- common/logging.py: improve format to timestamp|LEVEL|module:func:line - message - core/ layer: DEBUG log every subprocess invocation (cmd, rc, byte counts), JSON load/dump events, parsed application_id. ERROR log on failures. - tools/ layer: DEBUG log every public tool entry with key parameters, INFO log on business outcomes (saved/submitted/killed/...). - New tests/unit/test_logging.py: capture loguru output via in-memory sink and assert DEBUG + INFO messages are emitted for representative flows.
This commit is contained in:
@@ -6,6 +6,8 @@
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
from common.logging import logger
|
||||
|
||||
|
||||
class YarnError(Exception):
|
||||
"""Raised when a yarn CLI invocation fails."""
|
||||
@@ -15,33 +17,54 @@ _STATE_RE = re.compile(r"State\s*:\s*(\S+)")
|
||||
|
||||
|
||||
def _run(cmd: list[str]) -> "subprocess.CompletedProcess[str]":
|
||||
return subprocess.run(cmd, capture_output=True, text=True, errors="replace")
|
||||
logger.debug(f"yarn _run exec: {cmd}")
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, errors="replace")
|
||||
logger.debug(
|
||||
f"yarn _run done rc={result.returncode} "
|
||||
f"stdout_len={len(result.stdout)} stderr_len={len(result.stderr)}"
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
def get_application_status(application_id: str) -> tuple[str, str]:
|
||||
proc = _run(["yarn", "application", "-status", application_id])
|
||||
if proc.returncode != 0:
|
||||
logger.error(
|
||||
f"yarn application -status failed (rc={proc.returncode}) for "
|
||||
f"{application_id}: {proc.stderr[:500]}"
|
||||
)
|
||||
raise YarnError(
|
||||
f"yarn application -status failed (rc={proc.returncode}): {proc.stderr}"
|
||||
)
|
||||
match = _STATE_RE.search(proc.stdout)
|
||||
if not match:
|
||||
raise YarnError(f"Could not parse YARN state from output: {proc.stdout!r}")
|
||||
return match.group(1), proc.stdout
|
||||
state = match.group(1)
|
||||
logger.info(f"yarn status {application_id} -> {state}")
|
||||
return state, proc.stdout
|
||||
|
||||
|
||||
def get_application_logs(application_id: str) -> str:
|
||||
proc = _run(["yarn", "logs", "-applicationId", application_id])
|
||||
if proc.returncode != 0:
|
||||
logger.error(
|
||||
f"yarn logs failed (rc={proc.returncode}) for {application_id}: {proc.stderr[:500]}"
|
||||
)
|
||||
raise YarnError(
|
||||
f"yarn logs failed (rc={proc.returncode}): {proc.stderr}"
|
||||
)
|
||||
logger.info(f"yarn logs {application_id} -> {len(proc.stdout)} chars")
|
||||
return proc.stdout
|
||||
|
||||
|
||||
def kill_application(application_id: str) -> None:
|
||||
proc = _run(["yarn", "application", "-kill", application_id])
|
||||
if proc.returncode != 0:
|
||||
logger.error(
|
||||
f"yarn application -kill failed (rc={proc.returncode}) for "
|
||||
f"{application_id}: {proc.stderr[:500]}"
|
||||
)
|
||||
raise YarnError(
|
||||
f"yarn application -kill failed (rc={proc.returncode}): {proc.stderr}"
|
||||
)
|
||||
logger.info(f"yarn kill {application_id} -> ok")
|
||||
|
||||
Reference in New Issue
Block a user