mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-06 07:51:53 +00:00
fix(docker): tee supervised gateway stdout to docker logs
Follow-up to #33583 (the gateway-run-supervised redirect). Before this fix, the supervised gateway's stdout (most visibly the "Hermes Gateway Starting…" rich-console banner) was swallowed by `s6-log` into the rotated file at `${HERMES_HOME}/logs/gateways/<profile>/current` and never reached `docker logs`. Operational signal lived in two places: * **docker logs** — saw stderr (Python `logging` defaults to stderr), so warnings/errors were visible. * **the rotated file** — saw stdout (rich banners, `print()` output, third-party libs that wrote to fd 1). This was surprising for users coming from the pre-s6 image, where `docker run … gateway run` produced a single unified stream in `docker logs`. They'd see partial output, conclude something was broken, and dig around for the missing pieces. Fix: add the `1` s6-log action directive before the file destination so each line is forwarded to s6-log's stdout — which propagates up the s6-supervise pipeline to /init's stdout = container stdout = `docker logs`. The file destination is preserved as a second destination, so the rotated log (with ISO 8601 timestamps) still exists for `hermes logs` and for survival across container restarts. Trade-off considered: timestamps. Putting `T` between `1` and the file destination (not before `1`) means: * docker logs sees raw lines — Python's logging formatter has its own timestamps, and `docker logs --timestamps` adds another layer when desired. No double-stamping in the common reading path. * The persisted file gets s6-log's ISO 8601 timestamp so even output that lacked a Python-logger timestamp (rich banners, third-party raw prints) is correlatable in `current`. Verification: * New unit-test assertion in `test_service_manager.py` locks the `s6-log 1` directive into the rendered run-script. Mutation- tested by reverting to the pre-fix script (no `1`); the assert catches it cleanly. * New docker-harness test `test_supervised_gateway_stdout_reaches_docker_logs` builds the image, runs `docker run … gateway run`, and asserts the unique `⚕` banner glyph reaches `docker logs`. Also verifies the rotated file still contains the banner (no regression on the existing file destination). Mutation-tested end-to-end: built a deliberately-broken image without the `1` directive and the test failed exactly as designed, citing the banner present in `current` but absent from `docker logs`. * `website/docs/user-guide/docker.md` gains a new `:::note Where gateway logs go` admonition documenting both destinations and the audit-log file at `${HERMES_HOME}/logs/container-boot.log`. Existing functionality preserved: every other docker-harness test still passes against the new image. Unit-test sweep across `tests/hermes_cli/` (5561 tests) is green.
This commit is contained in:
parent
912e6e2274
commit
b345323195
4 changed files with 118 additions and 1 deletions
|
|
@ -555,6 +555,16 @@ def test_s6_register_creates_service_dir_and_triggers_scan(
|
|||
assert "/opt/data/logs/gateways/coder" not in log_text, (
|
||||
"log_dir was hard-coded; must use ${HERMES_HOME} at run time"
|
||||
)
|
||||
# `1` action directive forwards lines to stdout BEFORE the file
|
||||
# destination so the supervised gateway's stdout (including the
|
||||
# rich-console banner and plain print() output) reaches docker
|
||||
# logs, not just the rotated file. See _render_log_run's docstring
|
||||
# for the full output-routing rationale.
|
||||
assert "s6-log 1 " in log_text, (
|
||||
"log/run must include the `1` action directive before the file "
|
||||
"destination so supervised stdout reaches docker logs. Saw: "
|
||||
f"{log_text!r}"
|
||||
)
|
||||
|
||||
# s6-svscanctl -a was invoked against the scandir
|
||||
assert any(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue