fix(langfuse): support LANGFUSE_BASE_URL env var

This commit is contained in:
Hassieb Pakzad 2026-05-07 10:44:29 +02:00
parent a67b7a7e87
commit c42c2792d8
6 changed files with 73 additions and 9 deletions

View file

@ -106,8 +106,10 @@ def resolve_langfuse_credentials(
)
public_key = langfuse_public_key or os.getenv("LANGFUSE_PUBLIC_KEY")
resolved_host = langfuse_host or os.getenv(
"LANGFUSE_HOST", "https://cloud.langfuse.com"
resolved_host = (
langfuse_host
or os.getenv("LANGFUSE_BASE_URL")
or os.getenv("LANGFUSE_HOST", "https://cloud.langfuse.com")
)
return public_key, secret_key, resolved_host

View file

@ -260,9 +260,14 @@ class LangfuseOtelLogger(OpenTelemetry):
Returned in the following order of precedence:
1. LANGFUSE_OTEL_HOST
2. LANGFUSE_HOST
2. LANGFUSE_BASE_URL
3. LANGFUSE_HOST
"""
return os.environ.get("LANGFUSE_OTEL_HOST") or os.environ.get("LANGFUSE_HOST")
return (
os.environ.get("LANGFUSE_OTEL_HOST")
or os.environ.get("LANGFUSE_BASE_URL")
or os.environ.get("LANGFUSE_HOST")
)
def _create_open_telemetry_config_from_langfuse_env(self) -> OpenTelemetryConfig:
"""
@ -311,7 +316,9 @@ class LangfuseOtelLogger(OpenTelemetry):
Environment Variables:
LANGFUSE_PUBLIC_KEY: Required. Langfuse public key for authentication.
LANGFUSE_SECRET_KEY: Required. Langfuse secret key for authentication.
LANGFUSE_HOST: Optional. Custom Langfuse host URL. Defaults to US cloud.
LANGFUSE_OTEL_HOST: Optional. Custom Langfuse OTEL host URL.
LANGFUSE_BASE_URL: Optional. Custom Langfuse base URL.
LANGFUSE_HOST: Optional. Deprecated custom Langfuse host URL. Defaults to US cloud.
Returns:
OpenTelemetryConfig: A Pydantic model containing Langfuse OTEL configuration.

View file

@ -3324,6 +3324,7 @@ class AllCallbacks(LiteLLMPydanticObjectBase):
litellm_callback_params=[
"LANGFUSE_PUBLIC_KEY",
"LANGFUSE_SECRET_KEY",
"LANGFUSE_BASE_URL",
"LANGFUSE_HOST",
],
)

View file

@ -108,6 +108,7 @@ def test_get_callback_env_vars():
assert env_vars == [
"LANGFUSE_PUBLIC_KEY",
"LANGFUSE_SECRET_KEY",
"LANGFUSE_BASE_URL",
"LANGFUSE_HOST",
]

View file

@ -10,15 +10,35 @@ import pytest
import litellm
from litellm.integrations.langfuse import langfuse as langfuse_module
from litellm.integrations.langfuse.langfuse import LangFuseLogger
from litellm.integrations.langfuse.langfuse import (
LangFuseLogger,
resolve_langfuse_credentials,
)
sys.path.insert(0, os.path.abspath("../.."))
from litellm.integrations.langfuse.langfuse import LangFuseLogger
# Import LangfuseUsageDetails directly from the module where it's defined
from litellm.types.integrations.langfuse import *
def test_resolve_langfuse_credentials_prefers_base_url_over_host():
with patch.dict(
os.environ,
{
"LANGFUSE_PUBLIC_KEY": "test-public-key",
"LANGFUSE_SECRET_KEY": "test-secret-key",
"LANGFUSE_BASE_URL": "https://base-url.langfuse.com",
"LANGFUSE_HOST": "https://deprecated-host.langfuse.com",
},
clear=False,
):
public_key, secret_key, host = resolve_langfuse_credentials()
assert public_key == "test-public-key"
assert secret_key == "test-secret-key"
assert host == "https://base-url.langfuse.com"
class TestLangfuseUsageDetails(unittest.TestCase):
def setUp(self):
# Save global Langfuse client counter to restore after test

View file

@ -14,6 +14,7 @@ class TestLangfuseOtelIntegration:
"""Test that config is created correctly with required environment variables."""
# Clean environment of any Langfuse-related variables
env_vars_to_clean = [
"LANGFUSE_BASE_URL",
"LANGFUSE_HOST",
"OTEL_EXPORTER_OTLP_ENDPOINT",
"OTEL_EXPORTER_OTLP_HEADERS",
@ -79,6 +80,21 @@ class TestLangfuseOtelIntegration:
# Endpoint assertion removed as side effect is gone
assert isinstance(config, OpenTelemetryConfig)
def test_get_langfuse_otel_config_with_base_url(self):
"""Test config with LANGFUSE_BASE_URL."""
with patch.dict(
os.environ,
{
"LANGFUSE_PUBLIC_KEY": "test_public_key",
"LANGFUSE_SECRET_KEY": "test_secret_key",
"LANGFUSE_BASE_URL": "https://base-url.langfuse.com",
},
clear=False,
):
config = LangfuseOtelLogger.get_langfuse_otel_config()
assert isinstance(config, OpenTelemetryConfig)
assert config.endpoint == "https://base-url.langfuse.com/api/public/otel"
def test_get_langfuse_otel_config_with_host_no_protocol(self):
"""Test config with custom host without protocol."""
with patch.dict(
@ -393,12 +409,13 @@ class TestLangfuseOtelIntegration:
assert result == {}
def test_get_langfuse_otel_config_with_otel_host_priority(self):
"""LANGFUSE_OTEL_HOST should take priority over LANGFUSE_HOST."""
"""LANGFUSE_OTEL_HOST should take priority over LANGFUSE_BASE_URL and LANGFUSE_HOST."""
with patch.dict(
os.environ,
{
"LANGFUSE_PUBLIC_KEY": "test_public_key",
"LANGFUSE_SECRET_KEY": "test_secret_key",
"LANGFUSE_BASE_URL": "https://base-url.langfuse.com",
"LANGFUSE_HOST": "https://should-not-be-used.com",
"LANGFUSE_OTEL_HOST": "https://otel-host.com",
},
@ -406,7 +423,23 @@ class TestLangfuseOtelIntegration:
):
config = LangfuseOtelLogger.get_langfuse_otel_config()
assert isinstance(config, OpenTelemetryConfig)
# Endpoint assertion removed as side effect is gone
assert config.endpoint == "https://otel-host.com/api/public/otel"
def test_get_langfuse_otel_config_with_base_url_priority_over_host(self):
"""LANGFUSE_BASE_URL should take priority over deprecated LANGFUSE_HOST."""
with patch.dict(
os.environ,
{
"LANGFUSE_PUBLIC_KEY": "test_public_key",
"LANGFUSE_SECRET_KEY": "test_secret_key",
"LANGFUSE_BASE_URL": "https://base-url.langfuse.com",
"LANGFUSE_HOST": "https://deprecated-host.langfuse.com",
},
clear=False,
):
config = LangfuseOtelLogger.get_langfuse_otel_config()
assert isinstance(config, OpenTelemetryConfig)
assert config.endpoint == "https://base-url.langfuse.com/api/public/otel"
class TestLangfuseOtelResponsesAPI: