mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-24 05:45:11 +00:00
Merge db8ab02ba9 into 82ca10cc2d
This commit is contained in:
commit
00426638d3
3 changed files with 50 additions and 2 deletions
|
|
@ -2764,6 +2764,9 @@ class OpenTelemetry(OTELGenAISemconvMixin, CustomLogger):
|
|||
"""
|
||||
Safely sets an attribute on the span, ensuring the value is a primitive type.
|
||||
"""
|
||||
is_recording: Final = getattr(span, "is_recording", None)
|
||||
if callable(is_recording) and not is_recording():
|
||||
return
|
||||
primitive_value: Final = self._cast_as_primitive_value_type(value)
|
||||
span.set_attribute(key, primitive_value)
|
||||
|
||||
|
|
|
|||
|
|
@ -767,7 +767,8 @@ class OpenTelemetryV2(CustomLogger):
|
|||
# path's ``async_pre_call_hook``). Idempotent.
|
||||
set_request_root_span(server_span)
|
||||
for key, value in bag.items():
|
||||
server_span.set_attribute(key, value)
|
||||
if is_recordable_span(server_span) and server_span.is_recording():
|
||||
server_span.set_attribute(key, value)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import unittest
|
|||
import weakref
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
from types import MappingProxyType
|
||||
from types import MappingProxyType, SimpleNamespace
|
||||
from typing import Final
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
|
|
@ -46,6 +46,9 @@ from litellm.integrations.opentelemetry import (
|
|||
RAW_REQUEST_SPAN_NAME,
|
||||
_normalize_team_metadata_keys,
|
||||
)
|
||||
from litellm.integrations.otel import logger as otel_logger
|
||||
from litellm.integrations.otel.logger import OpenTelemetryV2
|
||||
from litellm.integrations.otel.plumbing.context import set_request_root_span
|
||||
from litellm.litellm_core_utils.safe_json_dumps import safe_dumps
|
||||
from litellm.proxy import proxy_server
|
||||
from litellm.proxy._types import SpanAttributes
|
||||
|
|
@ -387,6 +390,47 @@ def test_v1_malformed_routing_metadata_preserves_inference_attributes(decision:
|
|||
assert not any(key.startswith("litellm.routing.") for key in finished.attributes)
|
||||
|
||||
|
||||
def test_safe_set_attribute_skips_ended_and_non_recording_spans() -> None:
|
||||
provider: Final = TracerProvider()
|
||||
tracer: Final = provider.get_tracer(__name__)
|
||||
otel: Final = OpenTelemetry(tracer_provider=provider)
|
||||
|
||||
with tracer.start_as_current_span("recording") as recording_span:
|
||||
otel.safe_set_attribute(recording_span, "litellm.test", "recorded")
|
||||
assert recording_span.attributes["litellm.test"] == "recorded"
|
||||
|
||||
ended_attributes: Final = dict(recording_span.attributes)
|
||||
assert not recording_span.is_recording()
|
||||
with tracer.start_as_current_span("non-recording") as non_recording_span:
|
||||
pass
|
||||
assert not non_recording_span.is_recording()
|
||||
|
||||
otel.safe_set_attribute(recording_span, "litellm.test", "skipped")
|
||||
otel.safe_set_attribute(non_recording_span, "litellm.test", "skipped")
|
||||
|
||||
assert dict(recording_span.attributes) == ended_attributes
|
||||
|
||||
|
||||
def test_seed_request_identity_preserves_recording_span_and_ignores_ended_span() -> None:
|
||||
exporter: Final = InMemorySpanExporter()
|
||||
provider: Final = TracerProvider()
|
||||
provider.add_span_processor(SimpleSpanProcessor(exporter))
|
||||
logger: Final = OpenTelemetryV2(tracer_provider=provider)
|
||||
auth = SimpleNamespace(team_id="qa-team", api_key="qa-key")
|
||||
|
||||
with provider.get_tracer(__name__).start_as_current_span("server") as server_span:
|
||||
set_request_root_span(server_span)
|
||||
logger.seed_request_identity(auth, model="qa-model")
|
||||
assert server_span.is_recording()
|
||||
assert server_span.attributes["litellm.team.id"] == "qa-team"
|
||||
|
||||
(finished,) = exporter.get_finished_spans()
|
||||
attributes_before = dict(finished.attributes)
|
||||
assert not server_span.is_recording()
|
||||
logger.seed_request_identity(auth, model="qa-model")
|
||||
assert dict(finished.attributes) == attributes_before
|
||||
|
||||
|
||||
class TestOpenTelemetryCostBreakdown(unittest.TestCase):
|
||||
def test_cost_breakdown_emitted_to_otel_span(self):
|
||||
"""
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue