From f8eb2912cedb00dcc062c248e72237b7ae14031e Mon Sep 17 00:00:00 2001 From: teknium1 <127238744+teknium1@users.noreply.github.com> Date: Mon, 14 Sep 2026 21:18:07 -0700 Subject: [PATCH] fix: route component log files added after profile routing is already on Adoption of a second home only wrapped the file handlers that existed at adoption time. A later setup_logging(hermes_home=, mode="gateway") skipped _adopt_secondary_home (the home is already served) and appended a bare _ManagedRotatingFileHandler for gateway.log, which carries no home filter and so took every profile's gateway records. When a router is already queued, the new handler is now wrapped in a _ProfileRoutingFileHandler over the union of the live routers' homes. Review finding: setup_logging(A); setup_logging(B); setup_logging(A, mode="gateway") wrote gw-b into A's gateway.log. --- hermes_logging.py | 11 +++++++++++ tests/test_hermes_logging.py | 24 ++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/hermes_logging.py b/hermes_logging.py index 4de9619a97..a2f786f9bb 100644 --- a/hermes_logging.py +++ b/hermes_logging.py @@ -669,6 +669,17 @@ def _add_rotating_handler( ) if log_filter is not None: handler.addFilter(log_filter) + # Routing already on (a second home adopted earlier): a component log added now — + # ``mode="gateway"`` after the fact — must route too, or it takes every home's records. + routers = [h for h in _queued_file_handlers if isinstance(h, _ProfileRoutingFileHandler)] + if routers: + homes: set[Path] = set() + for router in routers: + homes.add(router._default_home) + homes.update(router._profile_homes) + routed = _ProfileRoutingFileHandler(handler, sorted(homes)) + _quietly(handler.close) + handler = routed # Queue, not ``addHandler``: the rotation-lock wait never runs on the caller's thread. _register_queued_handler(handler) diff --git a/tests/test_hermes_logging.py b/tests/test_hermes_logging.py index ca0813ca97..14afc5e0fb 100644 --- a/tests/test_hermes_logging.py +++ b/tests/test_hermes_logging.py @@ -196,6 +196,30 @@ class TestSetupLogging: assert (profile_home / "logs" / "agent.log").read_text().count("once please") == 1 assert "once please" not in (hermes_home / "logs" / "agent.log").read_text() + def test_a_component_log_added_after_routing_is_routed_too(self, hermes_home, tmp_path): + """setup_logging(mode="gateway") for an already-known home AFTER a second home turned + routing on: gateway.log must be a routed writer, not a bare handler taking every home.""" + from hermes_constants import reset_hermes_home_override, set_hermes_home_override + + profile_home = tmp_path / "profile-b" + profile_home.mkdir() + hermes_logging.setup_logging(hermes_home=hermes_home) + hermes_logging.setup_logging(hermes_home=profile_home) + hermes_logging.setup_logging(hermes_home=hermes_home, mode="gateway") + + logger = logging.getLogger("gateway.run.routed-component-test") + token = set_hermes_home_override(profile_home) + try: + logger.info("gw-b") + finally: + reset_hermes_home_override(token) + logger.info("gw-a") + hermes_logging.flush_log_queue() + + a_log = (hermes_home / "logs" / "gateway.log").read_text() + assert "gw-a" in a_log and "gw-b" not in a_log + assert "gw-b" in (profile_home / "logs" / "gateway.log").read_text() +