fix: silence werkzeug access logger so Flask 200s don't false-red (#181)#182
Merged
Conversation
The Server Logs panel (#178) logged every Flask request twice: the structured _access_log_finish entry, plus werkzeug's own request line, which the stdout/stderr tee captures from stderr and tags `error` (red). Healthy 200s rendered red and double-logged — and since docker-compose.prod.yml still runs the Flask dev server, this reached prod, not just dev. Silence werkzeug's built-in access logger at import in both app.py (setLevel ERROR, which keeps genuine werkzeug error/exception logging), so the structured hook is the sole, level-tagged access entry. Update the stale _access_log_finish comments and the byte-identical log_ring.py docstrings, add a per-service test asserting the logger is silenced, and record the rationale in ADR-023. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UUXqNmzoqszKVAtaam1A3U
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Closes #181 (follow-up to the #178 / PR #180 structured Server Logs panel).
In the Server Logs panel, every request to a Flask service (
duckdb-service,image-service) produced two ring entries:@app.after_request_access_log_finishhook —GET /health 200 0.1ms, level-tagged by status. Intended.… "GET /health HTTP/1.1" 200 -), which the stdout/stderr tee inservices/log_ring.pycaptures from stderr and therefore tagserror(red) — even for a healthy200.So every successful request was double-logged and painted red. Because
docker-compose.prod.ymlbuilds both Flask services fromDockerfile.dev(CMD ["python", "app.py"]→ the Werkzeug dev server), this noise reached prod, not just dev.The fix
Silence Werkzeug's built-in access logger at import in both
app.py, right afterinit_log_persistence()and before any request is served:Werkzeug's
_logonly forces the logger toINFOwhen its level is stillNOTSET, so pre-settingERRORat import wins permanently. Access request lines (emitted atinfo) are filtered; Werkzeug's genuine error/exception logging (emitted aterror) is untouched. The_access_log_finishhook is now the sole, level-tagged access entry.Changes
duckdb-service/app.pyandimage-service/app.py(+import logging)._access_log_finishcomments in both files.log_ring.pydocstring in both services — kept byte-identical (enforced bytest_log_ring_byte_identical_across_services).test_werkzeug_access_logger_silencedper service (asserts the logger level filtersINFOwhile keepingERROR; verified it fails when the fix is neutered toINFO).Verification
duckdb-service: 205 passed (incl. byte-identity guard + new test)image-service: 80 passedmake check-citations: 7 OK, 0 problemssenior-reviewergate — no P0/P1; mechanism independently verified against werkzeug source.Manual (needs the stack up): with
docker compose up, hit/healthon both services and confirm the Server Logs panel shows exactly one greenGET /health 200 N.Nmsentry — no second werkzeug line, no red.Out of scope (per issue)
setLevelbecomes a no-op and should be removed).docker-compose.prod.ymlchange.🤖 Generated with Claude Code
https://claude.ai/code/session_01UUXqNmzoqszKVAtaam1A3U
Generated by Claude Code