From 0fdf938995dd3a75c050bdc9a456b8cd01ac473c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Marques?= Date: Sun, 4 Oct 2026 21:40:38 -0300 Subject: [PATCH 1/2] fix(serve): keep json_logging's startup debug line out of plain-text stderr --- maestro_worker_python/serve.py | 3 +++ tests/test_serve.py | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/maestro_worker_python/serve.py b/maestro_worker_python/serve.py index 3a82aae..eb6f656 100644 --- a/maestro_worker_python/serve.py +++ b/maestro_worker_python/serve.py @@ -89,6 +89,9 @@ async def lifespan(_app: FastAPI) -> AsyncIterator[None]: if settings.enable_json_logging: register_client_safe_request_extractor() + # json_logging pins its own logger to DEBUG at import, and init logs at DEBUG before + # the root handler is JSON, leaking a plain-text line that Cloud Logging files as ERROR. + logging.getLogger("json_logging").setLevel(logging.INFO) json_logging.init_fastapi(enable_json=True) json_logging.init_request_instrument(app) json_logging.config_root_logger() diff --git a/tests/test_serve.py b/tests/test_serve.py index 7ff4cd7..13277aa 100644 --- a/tests/test_serve.py +++ b/tests/test_serve.py @@ -1,5 +1,7 @@ import asyncio import importlib +import json +import subprocess import sys import threading from pathlib import Path @@ -341,3 +343,36 @@ def test_a_recoverable_failure_keeps_the_process_serving(tmp_path, monkeypatch, assert client.post("/inference", json={}).status_code == status_code assert serve_module.model.calls == 2 assert terminations == [] + + +def _start_with_json_logging(tmp_path, then: str = "") -> subprocess.CompletedProcess: + """Import serve.py in a fresh interpreter: json_logging configures process-wide state once.""" + worker_path = tmp_path / "worker.py" + worker_path.write_text("class MoisesWorker:\n pass\n") + return subprocess.run( + [sys.executable, "-c", f"from maestro_worker_python import serve\n{then}"], + capture_output=True, + text=True, + env={"ENABLE_JSON_LOGGING": "true", "MODEL_PATH": str(worker_path)}, + ) + + +def _log_lines(result: subprocess.CompletedProcess) -> list[str]: + return [line for line in (result.stdout + result.stderr).splitlines() if line.strip()] + + +def test_json_logging_startup_writes_only_json(tmp_path): + # Cloud Logging files any non-JSON stderr line as ERROR. + result = _start_with_json_logging(tmp_path) + + assert result.returncode == 0, result.stderr + for line in _log_lines(result): + json.loads(line) + + +def test_json_logging_keeps_reporting_its_own_warnings(tmp_path): + result = _start_with_json_logging(tmp_path, 'import logging; logging.getLogger("json_logging").warning("probe")') + + assert result.returncode == 0, result.stderr + records = [json.loads(line) for line in _log_lines(result) if line.startswith("{")] + assert any(r["msg"] == "probe" and r["level"] == "WARNING" for r in records), records From a98ad5ead32b6fdc34e727bdcfcdd4dc4df8fadb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Marques?= Date: Sun, 4 Oct 2026 21:40:46 -0300 Subject: [PATCH 2/2] chore: bump version to 5.2.1 in pyproject.toml and uv.lock --- pyproject.toml | 2 +- uv.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8353644..136a0f2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "maestro-worker-python" -version = "5.2.0" +version = "5.2.1" description = "Utility to run workers on Moises/Maestro" readme = "README.md" requires-python = ">=3.10,<3.14" diff --git a/uv.lock b/uv.lock index 96fca76..fa005b1 100644 --- a/uv.lock +++ b/uv.lock @@ -220,7 +220,7 @@ wheels = [ [[package]] name = "maestro-worker-python" -version = "5.2.0" +version = "5.2.1" source = { editable = "." } dependencies = [ { name = "fastapi" },