From 7c13866ba3d49123d6f143f0b15cd6aa2e2cccb5 Mon Sep 17 00:00:00 2001 From: ff225 Date: Tue, 14 Jul 2026 10:04:54 +0200 Subject: [PATCH] fix(logger): route inference table through a dedicated console logger PR #60 replaced the inference-table print() calls with logger.info(), which prefixed every row with the timestamp/level/file formatter, broke the column alignment, and interleaved the table with the verbose diagnostic log stream. Add a dedicated `table_logger` (server.table) with a plain %(message)s format on stdout, propagate=False, fixed at INFO so it stays visible regardless of the `verbose` setting. Route the header/row printers through it. Closes #66 --- src/server/communication/request_handler.py | 8 +++++--- src/server/logger/log.py | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/server/communication/request_handler.py b/src/server/communication/request_handler.py index f8b4c75..d6ae5f1 100644 --- a/src/server/communication/request_handler.py +++ b/src/server/communication/request_handler.py @@ -31,7 +31,7 @@ ) from server.telemetry.firestore import FirestoreTelemetryPublisher -from server.logger.log import logger +from server.logger.log import logger, table_logger from server.communication.message_data import MessageData from server.communication.inference_protocol import decode_inference_payload @@ -392,7 +392,9 @@ def should_force_local_inference(self) -> bool: @classmethod def _print_inference_table_header(cls) -> None: - logger.info(f"\n{cls.INFERENCE_TABLE_HEADER}\n{cls.INFERENCE_TABLE_SEPARATOR}") + table_logger.info( + f"\n{cls.INFERENCE_TABLE_HEADER}\n{cls.INFERENCE_TABLE_SEPARATOR}" + ) cls.header_printed = True @classmethod @@ -418,7 +420,7 @@ def _print_inference_table_row( ): cls._print_inference_table_header() - logger.info( + table_logger.info( f"{device_id:13s} | {offloading_layer_index:7d} | " f"{acquisition_time_ms:13.2f} | {device_compute_time_ms:16.2f} | " f"{edge_compute_time_ms:14.2f} | {network_time_ms:13.2f} | " diff --git a/src/server/logger/log.py b/src/server/logger/log.py index 9e0a5b3..515c31d 100644 --- a/src/server/logger/log.py +++ b/src/server/logger/log.py @@ -12,6 +12,7 @@ from logging.handlers import TimedRotatingFileHandler from os import path from pathlib import Path +import sys from server.logger.log_config import LoggerConfig from sciot.config import load_server_config @@ -74,6 +75,25 @@ def format(self, record): logger.addHandler(fh) +# ── Dedicated console logger for the human-readable inference table ────────── +# The inference status table is meant to be read as an aligned grid. Routing it +# through ``logger`` prefixes every row with timestamp/level/file info (which +# breaks the column alignment) and buries it among the verbose diagnostic logs. +# ``table_logger`` emits the message verbatim to stdout, keeps ``propagate`` off +# so it does not double-emit through the root logger, and stays visible +# regardless of the ``verbose`` setting so the table survives even when the +# noisy INFO/DEBUG stream is silenced. +table_logger = getLogger("server.table") +table_logger.setLevel(INFO) +table_logger.propagate = False +if len(table_logger.handlers) == 0: + # Target stdout explicitly to match the pre-PR-60 print() behaviour (the + # default StreamHandler stream is stderr). + _table_handler = StreamHandler(sys.stdout) + _table_handler.setFormatter(Formatter("%(message)s")) + table_logger.addHandler(_table_handler) + + def configure_logger_from_settings(): """Configure logger verbosity based on settings.yaml.