Skip to content

Commit ef6ff46

Browse files
committed
fix(logging): honor LOG_LEVEL instead of pinning every logger to INFO
make_logger hardcoded logging.INFO and read no override, so the SDK's log level could not be changed by any configuration. That is not only a missing knob: it made diagnostics already written into the SDK unreachable. The handler that explains why agent output streaming stopped logged at debug level, so the one message that would have identified a frozen worker could never be emitted. Read LOG_LEVEL from the environment, defaulting to INFO so nothing changes for anyone who does not set it. Unprefixed to match the SDK's other variables (ENVIRONMENT, REDIS_URL, AGENT_NAME), and read directly rather than through EnvVarKeys, because environment_variables imports this module. getLevelName returns the string "Level FOO" for an unrecognized name, so an unusable value falls back to INFO rather than being handed to setLevel, where a typo would silently disable logging.
1 parent df7f0ff commit ef6ff46

2 files changed

Lines changed: 86 additions & 1 deletion

File tree

‎src/agentex/lib/utils/logging.py‎

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,25 @@
1111

1212
ctx_var_request_id = contextvars.ContextVar[str]("request_id")
1313

14+
DEFAULT_LOG_LEVEL = logging.INFO
15+
16+
17+
def resolve_log_level() -> int:
18+
"""Read the log level from ``LOG_LEVEL``, falling back to INFO.
19+
20+
Read straight from the environment rather than through ``EnvVarKeys``, since
21+
``environment_variables`` imports this module and the reverse would be a cycle.
22+
23+
``getLevelName`` returns the string ``"Level FOO"`` for anything it does not
24+
recognise, so the isinstance check is what stops a typo in ``LOG_LEVEL`` from
25+
silently turning logging off.
26+
"""
27+
configured = os.getenv("LOG_LEVEL")
28+
if not configured:
29+
return DEFAULT_LOG_LEVEL
30+
level = logging.getLevelName(configured.strip().upper())
31+
return level if isinstance(level, int) else DEFAULT_LOG_LEVEL
32+
1433

1534
class CustomJSONFormatter(json_log_formatter.JSONFormatter):
1635
def json_record(self, message: str, extra: dict, record: logging.LogRecord) -> dict: # type: ignore[override]
@@ -51,7 +70,7 @@ def make_logger(name: str) -> logging.Logger:
5170
"""
5271
# Create a console object to print colored text
5372
logger = logging.getLogger(name)
54-
logger.setLevel(logging.INFO)
73+
logger.setLevel(resolve_log_level())
5574

5675
environment = os.getenv("ENVIRONMENT")
5776
if environment == "local":
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
"""Tests for log level resolution in agentex.lib.utils.logging.
2+
3+
The level used to be pinned to INFO with no override, so a debug() call could
4+
never be emitted on any configuration. That is not just a missing feature: it
5+
made diagnostics that were already written into the SDK unreachable.
6+
"""
7+
8+
from __future__ import annotations
9+
10+
import logging
11+
12+
import pytest
13+
14+
from agentex.lib.utils.logging import (
15+
DEFAULT_LOG_LEVEL,
16+
make_logger,
17+
resolve_log_level,
18+
)
19+
20+
21+
def test_defaults_to_info_when_unset(monkeypatch: pytest.MonkeyPatch) -> None:
22+
monkeypatch.delenv("LOG_LEVEL", raising=False)
23+
24+
assert resolve_log_level() == DEFAULT_LOG_LEVEL == logging.INFO
25+
26+
27+
@pytest.mark.parametrize(
28+
("configured", "expected"),
29+
[
30+
("DEBUG", logging.DEBUG),
31+
("debug", logging.DEBUG),
32+
(" WaRnInG ", logging.WARNING),
33+
("ERROR", logging.ERROR),
34+
("CRITICAL", logging.CRITICAL),
35+
],
36+
)
37+
def test_reads_level_from_env(
38+
monkeypatch: pytest.MonkeyPatch, configured: str, expected: int
39+
) -> None:
40+
monkeypatch.setenv("LOG_LEVEL", configured)
41+
42+
assert resolve_log_level() == expected
43+
44+
45+
@pytest.mark.parametrize("configured", ["", " ", "VERBOSE", "10x", "TRUE"])
46+
def test_falls_back_to_info_on_an_unusable_value(
47+
monkeypatch: pytest.MonkeyPatch, configured: str
48+
) -> None:
49+
"""A typo must not silently disable logging.
50+
51+
logging.getLevelName returns the string "Level FOO" for anything it does not
52+
recognise, which would otherwise be handed straight to setLevel.
53+
"""
54+
monkeypatch.setenv("LOG_LEVEL", configured)
55+
56+
assert resolve_log_level() == logging.INFO
57+
58+
59+
def test_make_logger_applies_the_configured_level(monkeypatch: pytest.MonkeyPatch) -> None:
60+
"""The regression that mattered: a debug() call must be able to emit."""
61+
monkeypatch.setenv("LOG_LEVEL", "DEBUG")
62+
63+
logger = make_logger("agentex.tests.level_from_env")
64+
65+
assert logger.level == logging.DEBUG
66+
assert logger.isEnabledFor(logging.DEBUG)

0 commit comments

Comments
 (0)