Skip to content

fix(logging): scope OPENROUTER_DEBUG to the openrouter logger instead of root - #594

Open
rajarshidattapy wants to merge 1 commit into
OpenRouterTeam:mainfrom
rajarshidattapy:fix/scoped-debug-logger
Open

fix(logging): scope OPENROUTER_DEBUG to the openrouter logger instead of root#594
rajarshidattapy wants to merge 1 commit into
OpenRouterTeam:mainfrom
rajarshidattapy:fix/scoped-debug-logger

Conversation

@rajarshidattapy

Copy link
Copy Markdown

Fixes #590.

Problem

get_default_logger() called logging.basicConfig(level=logging.DEBUG), and it runs at client
construction — so instantiating OpenRouter() with OPENROUTER_DEBUG set mutated the host
application's root logger, turning on DEBUG output for every library in the process.

Change

src/openrouter/utils/logger.py | +21 -3   scoped to the openrouter logger
.genignore                     | +1       keeps the fix from being regenerated away
tests/test_logger.py           | new, 71 lines
if os.getenv("OPENROUTER_DEBUG"):
    logger = logging.getLogger("openrouter")
    logger.setLevel(logging.DEBUG)
    if not logger.hasHandlers():
        logger.addHandler(logging.StreamHandler())
    return logger
return NoOpLogger()

The issue's repro, on this branch:

before: 30 []
after : 30 []                                    # was: 10 [StreamHandler]
openrouter logger: 10 [<StreamHandler <stderr>>]

One deviation from the patch suggested in #590: hasHandlers() rather than
if not logger.handlers. hasHandlers() walks the ancestor chain, so when the host app has
already configured logging the SDK attaches nothing and its records flow through the app's
existing handler — if not logger.handlers would add a competing one and print every record
twice. It also makes repeated client construction idempotent for free.

On landing this in the generator

#590 notes the file carries a DO NOT EDIT header and that the fix belongs in the generator.
It does eventually, but that isn't something this repo can do, and without .genignore the
edit would be reverted by the next regeneration regardless.

Freezing a generated file is a real risk — it's what deleted the OAuth PKCE helpers in #583
so it's worth stating why it's acceptable here: utils/logger.py has changed exactly once in
the repo's entire history, in the initial commit. And if a future regen does add a symbol that
utils/__init__.py imports from it, the failure is a loud ImportError at import time rather
than silent drift.

Worth noting gen.yaml has enableCustomCodeRegions: false. Turning that on would be the
sanctioned way to keep a hand-written block inside a generated file, but I could not verify the
Python region syntax without the Speakeasy CLI, so I did not reach for it. Happy to switch if
you'd prefer that route.

Verification

  • debug output still works — 4 SDK debug lines on a real models.count() call
  • INFO:httpx no longer leaks to stderr
  • the three new tests pass, each in a fresh interpreter since logging config is process-global
  • they discriminate: the old basicConfig line moves root from 30 / 0 handlers to 10 / 1,
    which is exactly what test_debug_mode_leaves_the_root_logger_alone asserts against
  • mypy 769 files clean, pyright 0 errors, pylint 10.00/10

Full suite is 6 passed, 1 failed — the failure is test_responses_namespace.py, which is
#585 and already red on main before this branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OPENROUTER_DEBUG reconfigures the root logger, forcing DEBUG output for the entire process

1 participant