This commit is contained in:
Ephraim Duncan 2026-08-27 16:35:55 +00:00 committed by GitHub
commit a5047f581b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 107 additions and 0 deletions

View file

@ -130,6 +130,7 @@ _custom_logger_compatible_callbacks_literal = Literal[
"arize",
"arize_phoenix",
"langtrace",
"telemetry_dev",
"gcs_bucket",
"azure_storage",
"opik",

View file

@ -0,0 +1,3 @@
from litellm.integrations.telemetry_dev.telemetry_dev import TelemetryDevLogger
__all__ = ["TelemetryDevLogger"] # mutable-ok: module export list

View file

@ -0,0 +1,38 @@
import os
from litellm.integrations.opentelemetry import OpenTelemetry
from litellm.types.integrations.arize import Protocol
class TelemetryDevConfig:
"""Configuration for the telemetry.dev OTLP integration."""
def __init__(
self,
otlp_auth_headers: str,
protocol: Protocol,
endpoint: str,
) -> None:
self.otlp_auth_headers = otlp_auth_headers
self.protocol = protocol
self.endpoint = endpoint
class TelemetryDevLogger(OpenTelemetry):
"""telemetry.dev logger that extends OpenTelemetry for OTLP export."""
@staticmethod
def get_telemetry_dev_config() -> TelemetryDevConfig:
api_key = os.environ.get("TELEMETRY_DEV_API_KEY")
if not api_key:
raise ValueError(
"TELEMETRY_DEV_API_KEY environment variable is required for the telemetry.dev integration."
)
base_url = os.environ.get("TELEMETRY_DEV_BASE_URL", "https://ingest.telemetry.dev").rstrip("/")
return TelemetryDevConfig(
otlp_auth_headers=f"Authorization=Bearer {api_key}",
protocol="otlp_http",
endpoint=f"{base_url}/v1/traces",
)

View file

@ -47,6 +47,7 @@ from litellm.integrations.posthog import PostHogLogger
from litellm.integrations.prometheus import PrometheusLogger
from litellm.integrations.s3_v2 import S3Logger
from litellm.integrations.sqs import SQSLogger
from litellm.integrations.telemetry_dev.telemetry_dev import TelemetryDevLogger
from litellm.integrations.vantage.vantage_logger import VantageLogger
from litellm.integrations.vector_store_integrations.vector_store_pre_call_hook import (
VectorStorePreCallHook,
@ -85,6 +86,7 @@ class CustomLoggerRegistry:
"langfuse_otel": OpenTelemetry,
"arize_phoenix": OpenTelemetry,
"langtrace": OpenTelemetry,
"telemetry_dev": TelemetryDevLogger,
"weave_otel": OpenTelemetry,
"levo": OpenTelemetry,
"mlflow": MlflowLogger,

View file

@ -4327,6 +4327,26 @@ def _init_custom_logger_compatible_class(
_levo_otel_logger: Final = LevoLogger(config=otel_config, callback_name="levo")
_in_memory_loggers.append(_levo_otel_logger)
return _levo_otel_logger
elif logging_integration == "telemetry_dev":
from litellm.integrations.opentelemetry import OpenTelemetryConfig
from litellm.integrations.telemetry_dev.telemetry_dev import (
TelemetryDevLogger,
)
telemetry_dev_config = TelemetryDevLogger.get_telemetry_dev_config()
otel_config = OpenTelemetryConfig(
exporter=telemetry_dev_config.protocol,
endpoint=telemetry_dev_config.endpoint,
headers=telemetry_dev_config.otlp_auth_headers,
)
for callback in _in_memory_loggers:
if isinstance(callback, TelemetryDevLogger) and callback.callback_name == "telemetry_dev":
return callback
telemetry_dev_logger = TelemetryDevLogger(config=otel_config, callback_name="telemetry_dev")
_in_memory_loggers.append(telemetry_dev_logger)
return telemetry_dev_logger
elif logging_integration == "otel":
# Gate the new typed V2 adapter behind LITELLM_OTEL_V2. When off,
# the legacy 3,227-line god-class is used unchanged. The two are
@ -4926,6 +4946,15 @@ def get_custom_logger_compatible_class(
if isinstance(callback, OpenTelemetry) and callback.callback_name == "langtrace":
return callback
elif logging_integration == "telemetry_dev":
from litellm.integrations.telemetry_dev.telemetry_dev import (
TelemetryDevLogger,
)
for callback in _in_memory_loggers:
if isinstance(callback, TelemetryDevLogger) and callback.callback_name == "telemetry_dev":
return callback
elif logging_integration == "mlflow":
for callback in _in_memory_loggers:
if isinstance(callback, MlflowLogger):

View file

@ -38,6 +38,7 @@ expected_env_vars = {
"GOOGLE_APPLICATION_CREDENTIALS": "gcs_credentials",
"OPIK_API_KEY": "opik_api_key",
"LANGTRACE_API_KEY": "langtrace_api_key",
"TELEMETRY_DEV_API_KEY": "td_live_test",
"LOGFIRE_TOKEN": "logfire_token",
"ARIZE_SPACE_KEY": "arize_space_key",
"ARIZE_API_KEY": "arize_api_key",
@ -314,3 +315,36 @@ def test_get_combined_callback_list_returns_copy_when_dynamic_is_none():
combined_callbacks.append("new_callback")
assert global_callbacks == ["langfuse"]
def test_telemetry_dev_callback_initialization(monkeypatch):
from litellm.integrations.telemetry_dev.telemetry_dev import TelemetryDevLogger
from litellm.litellm_core_utils.litellm_logging import (
_init_custom_logger_compatible_class,
get_custom_logger_compatible_class,
)
monkeypatch.setenv("TELEMETRY_DEV_API_KEY", "td_live_test")
monkeypatch.delenv("TELEMETRY_DEV_BASE_URL", raising=False)
config = TelemetryDevLogger.get_telemetry_dev_config()
assert config.endpoint == "https://ingest.telemetry.dev/v1/traces"
assert config.otlp_auth_headers == "Authorization=Bearer td_live_test"
assert config.protocol == "otlp_http"
monkeypatch.setenv("TELEMETRY_DEV_BASE_URL", "https://example.com/")
assert TelemetryDevLogger.get_telemetry_dev_config().endpoint == "https://example.com/v1/traces"
monkeypatch.delenv("TELEMETRY_DEV_BASE_URL")
logger = _init_custom_logger_compatible_class("telemetry_dev", internal_usage_cache=None, llm_router=None)
assert isinstance(logger, TelemetryDevLogger)
assert logger.callback_name == "telemetry_dev"
assert CustomLoggerRegistry.CALLBACK_CLASS_STR_TO_CLASS_TYPE["telemetry_dev"] is TelemetryDevLogger
# init is cached and lookup resolves to the same instance
assert _init_custom_logger_compatible_class("telemetry_dev", internal_usage_cache=None, llm_router=None) is logger
assert get_custom_logger_compatible_class("telemetry_dev") is logger
monkeypatch.delenv("TELEMETRY_DEV_API_KEY")
with pytest.raises(ValueError, match="TELEMETRY_DEV_API_KEY"):
TelemetryDevLogger.get_telemetry_dev_config()