mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-07 02:59:05 +00:00
fix(otel): read the registered v2 logger without importing the proxy (#44485)
* fix(otel): read the registered v2 logger without importing the proxy phase_span, which the router enters on every deployment pick since #44150, looked up the proxy's OTel logger by importing litellm.proxy.proxy_server. In an SDK process that import loads the whole proxy synchronously on the caller's event loop during its first request, which stalled litellm_router_unit_testing past its 5s wait. Read the module from sys.modules instead: when the proxy was never imported it has no registered logger. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * test(otel): pin the no-proxy-import guarantee in-process Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --------- Co-authored-by: mateo <mateo@berri.ai> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
bb4f7211d7
commit
b4fcc5c1bc
2 changed files with 31 additions and 4 deletions
|
|
@ -1,5 +1,6 @@
|
|||
"""``CustomLogger`` adapter on the OpenTelemetry span engine."""
|
||||
|
||||
import sys
|
||||
from collections import OrderedDict
|
||||
from collections.abc import Callable, Iterator, Mapping, Sequence
|
||||
from contextlib import contextmanager, nullcontext
|
||||
|
|
@ -966,10 +967,12 @@ def _v2_configs(in_memory_loggers: Sequence[object], logger: "OpenTelemetryV2")
|
|||
|
||||
|
||||
def _registered_v2_logger() -> "OpenTelemetryV2 | None":
|
||||
try:
|
||||
from litellm.proxy import proxy_server
|
||||
except Exception:
|
||||
return None
|
||||
"""The proxy's registered V2 logger, read without importing the proxy.
|
||||
|
||||
Request paths call this (the router's ``route`` phase among them), so importing
|
||||
``proxy_server`` here would load the whole proxy on an SDK caller's event loop.
|
||||
"""
|
||||
proxy_server: Final = sys.modules.get("litellm.proxy.proxy_server")
|
||||
logger: Final = getattr(proxy_server, "open_telemetry_logger", None)
|
||||
return logger if isinstance(logger, OpenTelemetryV2) else None
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import lock. These tests pin the import to a single resolution.
|
|||
"""
|
||||
|
||||
import builtins
|
||||
import importlib.abc
|
||||
import sys
|
||||
|
||||
import litellm.integrations.otel.runtime as runtime
|
||||
|
||||
|
|
@ -69,3 +71,25 @@ def test_phase_event_no_ops_when_runtime_absent(monkeypatch):
|
|||
|
||||
assert runtime.phase_event("litellm.request.body_parsed") is None
|
||||
assert runtime.phase_event("litellm.request.body_received", {"litellm.request.body_bytes": 3}) is None
|
||||
|
||||
|
||||
def test_phase_span_does_not_import_the_proxy_in_an_sdk_process(monkeypatch):
|
||||
import litellm.proxy
|
||||
|
||||
monkeypatch.delitem(sys.modules, "litellm.proxy.proxy_server", raising=False)
|
||||
monkeypatch.delattr(litellm.proxy, "proxy_server", raising=False)
|
||||
proxy_imports: list[str] = []
|
||||
|
||||
class _RefuseProxyImport(importlib.abc.MetaPathFinder):
|
||||
def find_spec(self, fullname, path, target=None):
|
||||
if fullname == "litellm.proxy.proxy_server":
|
||||
proxy_imports.append(fullname)
|
||||
raise ImportError(fullname)
|
||||
return None
|
||||
|
||||
monkeypatch.setattr(sys, "meta_path", [_RefuseProxyImport(), *sys.meta_path])
|
||||
|
||||
with runtime.phase_span("route gpt-5-mini") as span:
|
||||
assert span is None
|
||||
|
||||
assert proxy_imports == []
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue