mirror of
https://github.com/tiennm99/litellm.git
synced 2026-07-11 11:04:32 +00:00
fe92f4af9c
* fix(langfuse_otel): ignore service logs and fix callback shadowing * add test cases for service logger
86 lines
3.1 KiB
Python
86 lines
3.1 KiB
Python
import os
|
|
import sys
|
|
import unittest
|
|
from unittest.mock import patch, AsyncMock, MagicMock
|
|
|
|
# Add the project root to sys.path
|
|
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")))
|
|
|
|
import litellm
|
|
from litellm.integrations.langfuse.langfuse_otel import LangfuseOtelLogger
|
|
from litellm.integrations.opentelemetry import OpenTelemetry
|
|
from litellm.types.services import ServiceTypes
|
|
from litellm._service_logger import ServiceLogging
|
|
|
|
|
|
class TestServiceLoggerOTEL(unittest.IsolatedAsyncioTestCase):
|
|
def setUp(self):
|
|
# Reset callbacks before each test
|
|
litellm.service_callback = []
|
|
os.environ["LANGFUSE_PUBLIC_KEY"] = "pk-lf-123"
|
|
os.environ["LANGFUSE_SECRET_KEY"] = "sk-lf-123"
|
|
|
|
@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
|
|
):
|
|
"""
|
|
Test that LangfuseOtelLogger overrides the service logging hooks with 'pass'.
|
|
"""
|
|
logger = LangfuseOtelLogger()
|
|
|
|
# Verify hooks are overriden
|
|
self.assertEqual(
|
|
logger.async_service_success_hook.__qualname__,
|
|
"LangfuseOtelLogger.async_service_success_hook",
|
|
)
|
|
self.assertEqual(
|
|
logger.async_service_failure_hook.__qualname__,
|
|
"LangfuseOtelLogger.async_service_failure_hook",
|
|
)
|
|
|
|
@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
|
|
):
|
|
"""
|
|
Test the architectural fix: multiple OTEL loggers should receive logs independently.
|
|
"""
|
|
# 1. Initialize two loggers
|
|
langfuse_logger = LangfuseOtelLogger()
|
|
otel_logger = OpenTelemetry()
|
|
|
|
# 2. Setup service_callback list
|
|
litellm.service_callback = [langfuse_logger, otel_logger]
|
|
|
|
service_logging = ServiceLogging()
|
|
|
|
# 3. Mock the base OpenTelemetry 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,
|
|
call_type="success",
|
|
duration=0.1,
|
|
parent_otel_span=MagicMock(),
|
|
start_time=0.0,
|
|
end_time=1.0,
|
|
)
|
|
|
|
# The architectural fix ensures we call each correctly.
|
|
self.assertEqual(
|
|
mock_base_hook.call_count,
|
|
1,
|
|
"Generic OTEL logger should have received the log exactly once.",
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|