Files
ecw-charge-validation/src/ecw_bot/core/runlog.py
T
ManikandanandClaude Opus 5.5 ba15a574ab Initial import: eCW Charge Validation bot and results Portal
Snapshot of the working project as of 2026-10-23 (local 2d4d4fc), one
commit with no earlier history: the tracked files were de-identified
first (synthetic claim ids and patient data only; see Context.md
section 7). Credentials, run logs, screenshots, claim reports and client
workbooks are gitignored and not included.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 18:38:17 +05:30

77 lines
2.5 KiB
Python

"""
Run log.
Python buffers stdout when it is not a terminal, so a background run that hung
produced a zero-byte log and there was no way to see how far it had got — the
only evidence left was a screenshot. Every run now tees to
`Logs\\run_<timestamp>.log`, flushed per line, so a stuck or killed run still
leaves a readable trail.
"""
import sys
from datetime import datetime
from .. import settings as cfg
class _Tee:
def __init__(self, stream, handle):
self._stream = stream
self._handle = handle
def write(self, text):
try:
self._stream.write(text)
self._stream.flush()
except Exception:
pass
try:
self._handle.write(text)
self._handle.flush() # a killed run must still have its log
except Exception:
pass
return len(text)
def flush(self):
for target in (self._stream, self._handle):
try:
target.flush()
except Exception:
pass
def isatty(self):
return getattr(self._stream, "isatty", lambda: False)()
def _force_utf8_console() -> None:
"""
Make the console accept the characters this bot actually prints.
Windows hands Python a cp1252 console, which cannot encode an em dash or an
arrow — and nearly every log line here has one. The tee below swallows the
resulting UnicodeEncodeError so a run never dies of it, which is right but
means those lines were being **silently dropped from the console** while
landing correctly in the log file. Watching a run and reading its log
afterwards showed different things, which is a nasty way to debug.
`errors="replace"` as well as the encoding: a console that still cannot
represent a character should print a box, not raise.
"""
for stream in (sys.__stdout__, sys.__stderr__):
try:
stream.reconfigure(encoding="utf-8", errors="replace")
except Exception:
pass # not a real console, or too old to care
def start() -> "object":
"""Begin teeing stdout/stderr. Returns the log path."""
_force_utf8_console()
cfg.LOGS.mkdir(parents=True, exist_ok=True)
path = cfg.LOGS / f"run_{datetime.now():%Y%m%d_%H%M%S}.log"
handle = open(path, "a", encoding="utf-8", buffering=1)
handle.write(f"\n{'=' * 70}\n{datetime.now():%Y-%m-%d %H:%M:%S} — run start\n"
f"{'=' * 70}\n")
sys.stdout = _Tee(sys.__stdout__, handle)
sys.stderr = _Tee(sys.__stderr__, handle)
return path