mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-28 01:32:17 +00:00
Merge b45fa18a95 into e26a6450c8
This commit is contained in:
commit
f75e1e5f4e
3 changed files with 60 additions and 16 deletions
|
|
@ -205,6 +205,17 @@ class LangFuseLogger:
|
|||
raise Exception(
|
||||
f"\033[91mLangfuse not installed, try running 'pip install langfuse' to fix this error: {e}\n{traceback.format_exc()}\033[0m"
|
||||
)
|
||||
import warnings
|
||||
|
||||
warnings.warn(
|
||||
"LangFuseLogger (the 'langfuse' callback) uses the Langfuse Python SDK "
|
||||
"and is deprecated in favour of LangfuseOtelLogger (the 'langfuse_otel' "
|
||||
"callback), which sends spans directly over OpenTelemetry and is compatible "
|
||||
"with Langfuse v4 Cloud Fast Preview. "
|
||||
"Set success_callback=['langfuse_otel'] to switch to the new integration.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
self.public_key, self.secret_key, self.langfuse_host = resolve_langfuse_credentials(
|
||||
langfuse_public_key=langfuse_public_key,
|
||||
langfuse_secret=langfuse_secret,
|
||||
|
|
|
|||
|
|
@ -401,7 +401,7 @@ also_copy = [
|
|||
# Run the test suite once before mutation to gather line coverage, then skip
|
||||
# mutating lines no test exercises. Those mutants would survive regardless
|
||||
# (no test hits the line to kill them), so generating them wastes hours of CI.
|
||||
# The score now reads as "mutation score over covered code" — pair with a
|
||||
# The score now reads as "mutation score over covered code" — pair with a
|
||||
# line-coverage number when reporting.
|
||||
mutate_only_covered_lines = true
|
||||
# Disable rerun/parallel plugins for mutation runs:
|
||||
|
|
|
|||
|
|
@ -25,9 +25,7 @@ class TestServiceLoggerOTEL(unittest.IsolatedAsyncioTestCase):
|
|||
@patch("litellm.integrations.opentelemetry.OpenTelemetry._init_tracing")
|
||||
@patch("litellm.integrations.opentelemetry.OpenTelemetry._init_metrics")
|
||||
@patch("litellm.integrations.opentelemetry.OpenTelemetry._init_logs")
|
||||
async def test_langfuse_otel_ignores_service_logs(
|
||||
self, mock_logs, mock_metrics, mock_tracing
|
||||
):
|
||||
async def test_langfuse_otel_ignores_service_logs(self, mock_logs, mock_metrics, mock_tracing):
|
||||
"""
|
||||
Test that LangfuseOtelLogger overrides the service logging hooks with 'pass'.
|
||||
"""
|
||||
|
|
@ -46,9 +44,7 @@ class TestServiceLoggerOTEL(unittest.IsolatedAsyncioTestCase):
|
|||
@patch("litellm.integrations.opentelemetry.OpenTelemetry._init_tracing")
|
||||
@patch("litellm.integrations.opentelemetry.OpenTelemetry._init_metrics")
|
||||
@patch("litellm.integrations.opentelemetry.OpenTelemetry._init_logs")
|
||||
async def test_langfuse_otel_does_not_create_proxy_request_span(
|
||||
self, mock_logs, mock_metrics, mock_tracing
|
||||
):
|
||||
async def test_langfuse_otel_does_not_create_proxy_request_span(self, mock_logs, mock_metrics, mock_tracing):
|
||||
"""
|
||||
Test that LangfuseOtelLogger returns None for create_litellm_proxy_request_started_span.
|
||||
|
||||
|
|
@ -73,9 +69,7 @@ class TestServiceLoggerOTEL(unittest.IsolatedAsyncioTestCase):
|
|||
@patch("litellm.integrations.opentelemetry.OpenTelemetry._init_tracing")
|
||||
@patch("litellm.integrations.opentelemetry.OpenTelemetry._init_metrics")
|
||||
@patch("litellm.integrations.opentelemetry.OpenTelemetry._init_logs")
|
||||
async def test_service_logging_shadowing_fix(
|
||||
self, mock_logs, mock_metrics, mock_tracing
|
||||
):
|
||||
async def test_service_logging_shadowing_fix(self, mock_logs, mock_metrics, mock_tracing):
|
||||
"""
|
||||
Test the architectural fix: multiple OTEL loggers should receive logs independently.
|
||||
"""
|
||||
|
|
@ -89,9 +83,7 @@ class TestServiceLoggerOTEL(unittest.IsolatedAsyncioTestCase):
|
|||
service_logging = ServiceLogging()
|
||||
|
||||
# 3. Mock the base OpenTelemetry hook
|
||||
with patch.object(
|
||||
OpenTelemetry, "async_service_success_hook", new_callable=AsyncMock
|
||||
) as mock_base_hook:
|
||||
with patch.object(OpenTelemetry, "async_service_success_hook", new_callable=AsyncMock) as mock_base_hook:
|
||||
# Trigger a service event
|
||||
await service_logging.async_service_success_hook(
|
||||
service=ServiceTypes.DB,
|
||||
|
|
@ -112,9 +104,7 @@ class TestServiceLoggerOTEL(unittest.IsolatedAsyncioTestCase):
|
|||
@patch("litellm.integrations.opentelemetry.OpenTelemetry._init_tracing")
|
||||
@patch("litellm.integrations.opentelemetry.OpenTelemetry._init_metrics")
|
||||
@patch("litellm.integrations.opentelemetry.OpenTelemetry._init_logs")
|
||||
async def test_langfuse_otel_env_config_includes_v4_ingestion_header(
|
||||
self, mock_logs, mock_metrics, mock_tracing
|
||||
):
|
||||
async def test_langfuse_otel_env_config_includes_v4_ingestion_header(self, mock_logs, mock_metrics, mock_tracing):
|
||||
logger = LangfuseOtelLogger()
|
||||
|
||||
headers = OpenTelemetry._get_headers_dictionary(logger.config.headers)
|
||||
|
|
@ -147,6 +137,49 @@ class TestServiceLoggerOTEL(unittest.IsolatedAsyncioTestCase):
|
|||
)
|
||||
self.assertTrue(headers["Authorization"].startswith("Basic "))
|
||||
|
||||
def test_langfuse_legacy_callback_emits_deprecation_warning(self):
|
||||
"""
|
||||
Test that instantiating LangFuseLogger emits a DeprecationWarning
|
||||
directing users to switch to the langfuse_otel callback.
|
||||
"""
|
||||
import warnings
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
mock_langfuse_module = MagicMock()
|
||||
mock_langfuse_module.Langfuse = MagicMock()
|
||||
|
||||
with patch.dict(
|
||||
"sys.modules",
|
||||
{
|
||||
"langfuse": mock_langfuse_module,
|
||||
"langfuse.client": MagicMock(),
|
||||
},
|
||||
):
|
||||
with warnings.catch_warnings(record=True) as caught:
|
||||
warnings.simplefilter("always")
|
||||
from litellm.integrations.langfuse.langfuse import LangFuseLogger
|
||||
|
||||
with patch( # test-quality-ok: mocking litellm credential resolver so test runs without real API keys
|
||||
"litellm.integrations.langfuse.langfuse.resolve_langfuse_credentials",
|
||||
return_value=("pk", "sk", "https://cloud.langfuse.com"),
|
||||
):
|
||||
LangFuseLogger(
|
||||
langfuse_public_key="pk",
|
||||
langfuse_secret="sk",
|
||||
langfuse_host="https://cloud.langfuse.com",
|
||||
allow_env_credentials=False,
|
||||
)
|
||||
|
||||
deprecation_warnings = [w for w in caught if issubclass(w.category, DeprecationWarning)]
|
||||
self.assertTrue(
|
||||
len(deprecation_warnings) >= 1,
|
||||
"Expected at least one DeprecationWarning to be emitted",
|
||||
)
|
||||
self.assertIn(
|
||||
"langfuse_otel",
|
||||
str(deprecation_warnings[0].message),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue