Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/nanodot/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import argparse
import getpass
import logging
import os
import signal
import subprocess
Expand Down Expand Up @@ -912,6 +913,7 @@ def unwind() -> None:
return 0
signal.signal(signal.SIGINT, _sigint)
signal.signal(signal.SIGTERM, _sigint)
_configure_runner_logging()
print("nanodot runner started — Ctrl-C to stop", flush=True)
daemon.serve(stop)
print("nanodot runner stopped")
Expand Down Expand Up @@ -981,6 +983,20 @@ def _run_start(_: argparse.Namespace) -> int:
return 1


_RUNNER_LOG_FORMAT = "%(asctime)s %(levelname)s %(name)s %(message)s"


def _configure_runner_logging() -> None:
"""Timestamped WARNING+ logging for the runner process. runner.log
lines are the only forensic trail after a crash; without timestamps a
failure storm (e.g. a transient DB lock) cannot be placed in time.
Process-local: this is our own process, not a global library policy."""
logging.basicConfig(
level=logging.WARNING,
format=_RUNNER_LOG_FORMAT,
)


def _runner_alive() -> bool:
from nanodot.native.runner_control import running_pid

Expand Down
17 changes: 17 additions & 0 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,3 +391,20 @@ def fake_input(prompt: str = "") -> str:

assert main(["watch", "show", task.id]) == 0
assert "flaky alerts:" in capsys.readouterr().out


def test_runner_logging_is_timestamped() -> None:
"""runner.log is the post-crash forensic trail; every line must carry
a timestamp (found missing while diagnosing the dogfood failure storm)."""
import logging
import re

from nanodot.cli import _RUNNER_LOG_FORMAT

rendered = logging.Formatter(_RUNNER_LOG_FORMAT).format(
logging.LogRecord(
"nanodot.native.daemon", logging.WARNING, __file__, 1,
"task listing failed; will retry next pass", None, None,
)
)
assert re.match(r"^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} ", rendered), rendered
Loading