From 0dca18e19a981685ab7d6e7f1e745387e042ae3a Mon Sep 17 00:00:00 2001 From: yucheng Date: Wed, 28 Oct 2026 01:54:26 -0700 Subject: [PATCH] test(otel): assert the collector gets one copy instead of reading the key logger's exporters --- .../otel/test_otel_v2_destinations.py | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/tests/unit/integrations/otel/test_otel_v2_destinations.py b/tests/unit/integrations/otel/test_otel_v2_destinations.py index cd2ae99e93c..3fed1801b21 100644 --- a/tests/unit/integrations/otel/test_otel_v2_destinations.py +++ b/tests/unit/integrations/otel/test_otel_v2_destinations.py @@ -3525,7 +3525,7 @@ class TestLangfuseTenantOnly: @staticmethod def _key_logger_beside_the_generic_startup_logger( monkeypatch: pytest.MonkeyPatch, loggers: list[CustomLogger] - ) -> OpenTelemetryV2: + ) -> tuple[OpenTelemetryV2, OpenTelemetryV2]: """``langfuse_otel`` only in a key's logging: the proxy published the generic logger, which exports to the operator's collector, and a key's request builds the Langfuse one.""" from litellm.litellm_core_utils.litellm_logging import _maybe_construct_otel_v2 @@ -3533,7 +3533,7 @@ class TestLangfuseTenantOnly: credential_less_proxy(monkeypatch) monkeypatch.setenv("OTEL_EXPORTER_OTLP_ENDPOINT", "http://collector.local:4318") monkeypatch.setenv("LITELLM_OTEL_V2", "true") - publish_global_otel_v2_provider(loggers, lambda _p: None) + published: Final = publish_global_otel_v2_provider(loggers, lambda _p: None) def with_destination() -> OpenTelemetryV2 | None: set_request_destinations((LANGFUSE_DEST,)) @@ -3543,15 +3543,20 @@ class TestLangfuseTenantOnly: logger: Final = in_fresh_context(with_destination) is_otel_v2_enabled.cache_clear() assert isinstance(logger, OpenTelemetryV2) - return logger + return published, logger - def test_a_key_destinations_logger_leaves_the_operators_collector_to_the_published_logger( + def test_the_operators_collector_gets_one_copy_of_a_call_both_loggers_emit( self, monkeypatch: pytest.MonkeyPatch ) -> None: - """The published logger already sends every span to the collector; a copy here doubles each one.""" - logger: Final = self._key_logger_beside_the_generic_startup_logger(monkeypatch, []) + capture: Final = _ExporterCapture() + for kind in ("otlp_grpc", "otlp_http", "console"): + monkeypatch.setitem(otel_providers._EXPORTER_FACTORIES, kind, capture.build) - assert all(spec.requires_headers and not spec.headers for spec in logger.config.exporters) + for logger in self._key_logger_beside_the_generic_startup_logger(monkeypatch, []): + emit(logger.tracer_provider) + logger.tracer_provider.force_flush() + + assert [span.name for _, exporter in capture.built for span in exporter.get_finished_spans()] == ["chat gpt-4"] def test_a_key_destinations_logger_is_reused_by_later_requests_without_a_destination( self, monkeypatch: pytest.MonkeyPatch @@ -3559,7 +3564,7 @@ class TestLangfuseTenantOnly: from litellm.litellm_core_utils.litellm_logging import _maybe_construct_otel_v2 loggers: Final[list[CustomLogger]] = [] - for_the_key: Final = self._key_logger_beside_the_generic_startup_logger(monkeypatch, loggers) + for_the_key: Final = self._key_logger_beside_the_generic_startup_logger(monkeypatch, loggers)[1] is_otel_v2_enabled.cache_clear() later: Final = in_fresh_context(_maybe_construct_otel_v2, "langfuse_otel", loggers)