Skip to content

Commit 90ea7a8

Browse files
chore: update logger implementation and add tests for debug mode behavior
1 parent cb401a8 commit 90ea7a8

3 files changed

Lines changed: 94 additions & 3 deletions

File tree

‎.genignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
pylintrc
22
docs/docs.json
33
docs/overview.mdx
4+
src/openrouter/utils/logger.py

‎src/openrouter/utils/logger.py‎

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
1+
"""Debug logging for the SDK.
2+
3+
Originally generated by Speakeasy, now hand-maintained and listed in `.genignore`
4+
so a regeneration cannot reinstate the `logging.basicConfig` call below — see
5+
`get_default_logger`.
6+
"""
27

38
import httpx
49
import logging
@@ -21,7 +26,21 @@ def get_body_content(req: httpx.Request) -> str:
2126

2227

2328
def get_default_logger() -> Logger:
29+
"""Return the debug logger used when `OPENROUTER_DEBUG` is set.
30+
31+
Configuration is scoped to the `openrouter` logger. A library must not call
32+
`logging.basicConfig`: that sets the level and attaches a handler on the
33+
*root* logger, turning on DEBUG output for every library in the process and
34+
overriding whatever logging the host application had already set up.
35+
36+
A `StreamHandler` is only attached when nothing up the hierarchy would emit
37+
the records already, so an application that has configured its own handlers
38+
keeps them, and repeated client construction does not stack duplicates.
39+
"""
2440
if os.getenv("OPENROUTER_DEBUG"):
25-
logging.basicConfig(level=logging.DEBUG)
26-
return logging.getLogger("openrouter")
41+
logger = logging.getLogger("openrouter")
42+
logger.setLevel(logging.DEBUG)
43+
if not logger.hasHandlers():
44+
logger.addHandler(logging.StreamHandler())
45+
return logger
2746
return NoOpLogger()

‎tests/test_logger.py‎

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import json
2+
import os
3+
import subprocess
4+
import sys
5+
from pathlib import Path
6+
7+
SRC = str(Path(__file__).resolve().parents[1] / "src")
8+
9+
PROBE = """
10+
import json, logging, sys
11+
{setup}
12+
root = logging.getLogger()
13+
before = (root.level, len(root.handlers))
14+
15+
from openrouter import OpenRouter
16+
OpenRouter(api_key="x")
17+
OpenRouter(api_key="x") # twice: handlers must not stack
18+
19+
sdk = logging.getLogger("openrouter")
20+
print(json.dumps({{
21+
"root_before": before,
22+
"root_after": (root.level, len(root.handlers)),
23+
"sdk_level": sdk.level,
24+
"sdk_handlers": len(sdk.handlers),
25+
}}))
26+
"""
27+
28+
29+
def _probe(setup="", **env):
30+
"""Run a fresh interpreter: logging config is process-global."""
31+
out = subprocess.run(
32+
[sys.executable, "-c", PROBE.format(setup=setup)],
33+
capture_output=True,
34+
text=True,
35+
check=True,
36+
env={**os.environ, "PYTHONPATH": SRC, **env},
37+
).stdout
38+
return json.loads(out.strip().splitlines()[-1])
39+
40+
41+
def test_debug_mode_leaves_the_root_logger_alone():
42+
r = _probe(OPENROUTER_DEBUG="1")
43+
44+
# basicConfig used to set root to DEBUG and attach a StreamHandler to it.
45+
assert r["root_after"] == r["root_before"]
46+
assert r["root_after"] == [30, 0] # WARNING, no handlers
47+
48+
# The SDK's own logger is what gets configured.
49+
assert r["sdk_level"] == 10 # DEBUG
50+
assert r["sdk_handlers"] == 1 # not 2 — repeated construction must not stack
51+
52+
53+
def test_no_logging_is_touched_without_the_env_var():
54+
r = _probe()
55+
56+
assert r["root_after"] == r["root_before"]
57+
assert r["sdk_level"] == 0 # NOTSET
58+
assert r["sdk_handlers"] == 0
59+
60+
61+
def test_an_application_handler_is_not_duplicated():
62+
r = _probe(
63+
setup="logging.basicConfig(level=logging.INFO)",
64+
OPENROUTER_DEBUG="1",
65+
)
66+
67+
# The app configured root itself; we must not add a competing handler,
68+
# which would print every record twice.
69+
assert r["sdk_handlers"] == 0
70+
assert r["sdk_level"] == 10
71+
assert r["root_after"] == r["root_before"]

0 commit comments

Comments
 (0)