mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-15 23:31:29 +00:00
fix(langfuse): send v4 ingestion header for otel callback
This commit is contained in:
parent
a67b7a7e87
commit
ef27e618ad
2 changed files with 66 additions and 4 deletions
|
|
@ -25,6 +25,8 @@ else:
|
|||
|
||||
LANGFUSE_CLOUD_EU_ENDPOINT = "https://cloud.langfuse.com/api/public/otel"
|
||||
LANGFUSE_CLOUD_US_ENDPOINT = "https://us.cloud.langfuse.com/api/public/otel"
|
||||
LANGFUSE_OTEL_INGESTION_VERSION_HEADER = "x-langfuse-ingestion-version"
|
||||
LANGFUSE_OTEL_INGESTION_VERSION = "4"
|
||||
|
||||
|
||||
class LangfuseOtelLogger(OpenTelemetry):
|
||||
|
|
@ -295,7 +297,9 @@ class LangfuseOtelLogger(OpenTelemetry):
|
|||
auth_header = LangfuseOtelLogger._get_langfuse_authorization_header(
|
||||
public_key=public_key, secret_key=secret_key
|
||||
)
|
||||
otlp_auth_headers = f"Authorization={auth_header}"
|
||||
otlp_auth_headers = LangfuseOtelLogger._format_otel_headers(
|
||||
LangfuseOtelLogger._build_langfuse_otel_headers(auth_header)
|
||||
)
|
||||
|
||||
return OpenTelemetryConfig(
|
||||
exporter="otlp_http",
|
||||
|
|
@ -344,7 +348,9 @@ class LangfuseOtelLogger(OpenTelemetry):
|
|||
auth_header = LangfuseOtelLogger._get_langfuse_authorization_header(
|
||||
public_key=public_key, secret_key=secret_key
|
||||
)
|
||||
otlp_auth_headers = f"Authorization={auth_header}"
|
||||
otlp_auth_headers = LangfuseOtelLogger._format_otel_headers(
|
||||
LangfuseOtelLogger._build_langfuse_otel_headers(auth_header)
|
||||
)
|
||||
|
||||
# Prevent modification of global env vars which causes leakage
|
||||
# os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = endpoint
|
||||
|
|
@ -365,6 +371,17 @@ class LangfuseOtelLogger(OpenTelemetry):
|
|||
auth_header = base64.b64encode(auth_string.encode()).decode()
|
||||
return f"Basic {auth_header}"
|
||||
|
||||
@staticmethod
|
||||
def _build_langfuse_otel_headers(auth_header: str) -> dict[str, str]:
|
||||
return {
|
||||
"Authorization": auth_header,
|
||||
LANGFUSE_OTEL_INGESTION_VERSION_HEADER: LANGFUSE_OTEL_INGESTION_VERSION,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _format_otel_headers(headers: dict[str, str]) -> str:
|
||||
return ",".join(f"{key}={value}" for key, value in headers.items())
|
||||
|
||||
def construct_dynamic_otel_headers(
|
||||
self, standard_callback_dynamic_params: StandardCallbackDynamicParams
|
||||
) -> Optional[dict]:
|
||||
|
|
@ -389,7 +406,9 @@ class LangfuseOtelLogger(OpenTelemetry):
|
|||
public_key=dynamic_langfuse_public_key,
|
||||
secret_key=dynamic_langfuse_secret_key,
|
||||
)
|
||||
dynamic_headers["Authorization"] = auth_header
|
||||
dynamic_headers = LangfuseOtelLogger._build_langfuse_otel_headers(
|
||||
auth_header
|
||||
)
|
||||
|
||||
return dynamic_headers
|
||||
|
||||
|
|
|
|||
|
|
@ -8,10 +8,15 @@ from unittest.mock import patch, AsyncMock, MagicMock
|
|||
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.langfuse.langfuse_otel import (
|
||||
LANGFUSE_OTEL_INGESTION_VERSION,
|
||||
LANGFUSE_OTEL_INGESTION_VERSION_HEADER,
|
||||
LangfuseOtelLogger,
|
||||
)
|
||||
from litellm.integrations.opentelemetry import OpenTelemetry
|
||||
from litellm.types.services import ServiceTypes
|
||||
from litellm._service_logger import ServiceLogging
|
||||
from litellm.types.utils import StandardCallbackDynamicParams
|
||||
|
||||
|
||||
class TestServiceLoggerOTEL(unittest.IsolatedAsyncioTestCase):
|
||||
|
|
@ -108,6 +113,44 @@ class TestServiceLoggerOTEL(unittest.IsolatedAsyncioTestCase):
|
|||
"Generic OTEL logger should have received the log exactly once.",
|
||||
)
|
||||
|
||||
@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
|
||||
):
|
||||
logger = LangfuseOtelLogger()
|
||||
|
||||
headers = OpenTelemetry._get_headers_dictionary(logger.config.headers)
|
||||
|
||||
self.assertEqual(
|
||||
headers[LANGFUSE_OTEL_INGESTION_VERSION_HEADER],
|
||||
LANGFUSE_OTEL_INGESTION_VERSION,
|
||||
)
|
||||
self.assertTrue(headers["Authorization"].startswith("Basic "))
|
||||
|
||||
@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_dynamic_headers_include_v4_ingestion_header(
|
||||
self, mock_logs, mock_metrics, mock_tracing
|
||||
):
|
||||
logger = LangfuseOtelLogger()
|
||||
|
||||
headers = logger.construct_dynamic_otel_headers(
|
||||
StandardCallbackDynamicParams(
|
||||
langfuse_public_key="pk-lf-dynamic",
|
||||
langfuse_secret_key="sk-lf-dynamic",
|
||||
)
|
||||
)
|
||||
|
||||
self.assertIsNotNone(headers)
|
||||
self.assertEqual(
|
||||
headers[LANGFUSE_OTEL_INGESTION_VERSION_HEADER],
|
||||
LANGFUSE_OTEL_INGESTION_VERSION,
|
||||
)
|
||||
self.assertTrue(headers["Authorization"].startswith("Basic "))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue