log: route task/component status output through logging, not print()

AttributeChange (the common base of every ATask and component ABC) now
sets self.log = logging.getLogger(type(self).__name__), so components
no longer need to hand-type their own name into each message. Wired
logging.basicConfig() in server/brewpi.py with a bare "%(name)s:
%(message)s" formatter - Tee (see prior commit) still supplies the
"<date>T<time>:" prefix, so lines read "<date>T<time>:<component>:
<message>" without double-stamping, and third-party loggers
(websockets, asyncio) now get the same formatting for free.

Converted the print() call sites that were standing in for this in
tasks/ and components/ (leaving __main__ demo blocks and explicit
debug-dump helpers alone).
This commit is contained in:
2026-07-10 22:00:04 +02:00
parent 6c746c8964
commit a1864a5257
12 changed files with 64 additions and 45 deletions
+22 -14
View File
@@ -2,6 +2,7 @@
import asyncio
import functools
import json
import logging
import os
import signal
import sys
@@ -20,20 +21,23 @@ from tasks import TaskManager, TempSensorTask, HeaterTask, PotTask, TcTask, Stir
import argparse as ap
log = logging.getLogger('brewpi')
class Tee:
"""Duplicates writes to multiple streams - used to mirror stdout/stderr
(everything the rest of the codebase already reaches via print()) into
a log file under logs/ as well as the console, without having to touch
every print() call site.
into a log file under logs/ as well as the console, without every
writer needing to know about either.
Also stamps every line with a "<date>T<time>:" prefix (existing print()
call sites already start their message with "Component: ..." - see e.g.
tasks/stirrer.py - so the combined line reads
"<date>T<time>:<component>: <message>"), so log entries can be
correlated with the JSON sample logs (ServerLogTask/SudLogTask) without
relying on journalctl's own timestamps, which aren't present in the
mirrored log files themselves."""
Also stamps every line with a "<date>T<time>:" prefix. Every task/
component logs via logging (see utils/value.py's AttributeChange, which
gives self.log to all of them), configured below with a bare
"%(name)s:%(message)s" formatter - Tee supplies the timestamp instead,
so the combined line reads "<date>T<time>:<component>:<message>" (see
logging.basicConfig() call below) without double-stamping. This lets
log entries be correlated with the JSON sample logs (ServerLogTask/
SudLogTask) without relying on journalctl's own timestamps, which
aren't present in the mirrored log files themselves."""
def __init__(self, *streams):
self.streams = streams
@@ -92,7 +96,11 @@ if __name__ == '__main__':
latest_log_file = open(latest_log_path, "w", buffering=1)
sys.stdout = Tee(sys.stdout, log_file, latest_log_file)
sys.stderr = Tee(sys.stderr, log_file, latest_log_file)
print("Logging to {}".format(log_path))
# No "%(asctime)s" here - Tee (above) already stamps every mirrored
# line with "<date>T<time>:", so this only contributes the
# "<component>:<message>" part (see Tee's own docstring).
logging.basicConfig(stream=sys.stdout, level=logging.INFO, format='%(name)s:%(message)s')
log.info("Logging to {}".format(log_path))
config = json.load(open(args.config))
dispatcher = MessageDispatcher()
@@ -246,7 +254,7 @@ if __name__ == '__main__':
http_handler = functools.partial(SimpleHTTPRequestHandler, directory=web_dir)
http_server = ThreadingHTTPServer(("0.0.0.0", args.http_port), http_handler)
threading.Thread(target=http_server.serve_forever, daemon=True).start()
print("Serving {} on http://0.0.0.0:{}".format(web_dir, args.http_port))
log.info("Serving {} on http://0.0.0.0:{}".format(web_dir, args.http_port))
# systemd's `stop`/`restart` send SIGTERM, whose default disposition is to
# kill the process immediately - skipping the finally: block below
@@ -259,7 +267,7 @@ if __name__ == '__main__':
try:
loop.run_forever()
except KeyboardInterrupt:
print("\nShutting down...")
log.info("Shutting down...")
finally:
# Cancel all tasks so their finally blocks (e.g. HeaterTask's/
# StirrerTask's `with device.open()`) get a chance to run before we
@@ -278,4 +286,4 @@ if __name__ == '__main__':
stirrer.activate(False)
http_server.shutdown()
loop.close()
print("Server stopped.")
log.info("Server stopped.")