diff --git a/litellm/integrations/opentelemetry.py b/litellm/integrations/opentelemetry.py index 78081837ae3..01664b75f61 100644 --- a/litellm/integrations/opentelemetry.py +++ b/litellm/integrations/opentelemetry.py @@ -1612,13 +1612,13 @@ class OpenTelemetry(OTELGenAISemconvMixin, CustomLogger): def _record_metrics(self, kwargs, response_obj, start_time, end_time): duration_s: Final = (end_time - start_time).total_seconds() params: Final = kwargs.get("litellm_params") or {} - provider: Final = params.get("custom_llm_provider", "Unknown") + provider: Final = params.get("custom_llm_provider") or kwargs.get("custom_llm_provider") or "Unknown" common_attrs = { "gen_ai.operation.name": ( self._gen_ai_operation_name(kwargs) if self._gen_ai_semconv_latest_experimental else "chat" ), - "gen_ai.system": provider, + ("gen_ai.provider.name" if self._gen_ai_semconv_latest_experimental else "gen_ai.system"): provider, "gen_ai.request.model": kwargs.get("model"), "gen_ai.framework": "litellm", } diff --git a/tests/logging_callback_tests/test_opentelemetry_unit_tests.py b/tests/logging_callback_tests/test_opentelemetry_unit_tests.py index fcbd6dbc531..abcf03600c6 100644 --- a/tests/logging_callback_tests/test_opentelemetry_unit_tests.py +++ b/tests/logging_callback_tests/test_opentelemetry_unit_tests.py @@ -208,3 +208,33 @@ class TestOpentelemetryUnitTests(BaseLoggingCallbackTest): mock_span.set_attribute.assert_called_with( ErrorAttributes.ERROR_MESSAGE, "Fallback error message" ) + + def test_record_metrics_semconv_provider_name(self): + """ + Test that _record_metrics emits gen_ai.provider.name under semconv mode. + """ + from litellm.integrations.opentelemetry import OpenTelemetry + from litellm.integrations.opentelemetry_utils.gen_ai_semconv import OTELSemconvCategory + + otel_integration = OpenTelemetry() + mock_histogram = MagicMock() + otel_integration._operation_duration_histogram = mock_histogram + + kwargs = { + "litellm_params": {"custom_llm_provider": "anthropic"}, + "model": "claude-3-5-sonnet", + } + start = datetime.now() + end = datetime.now() + otel_integration._record_metrics(kwargs, None, start, end) + call_attrs = mock_histogram.record.call_args[1]["attributes"] + assert call_attrs.get("gen_ai.system") == "anthropic" + + otel_integration.config.semconv_stability_opt_in = { + OTELSemconvCategory.GEN_AI_LATEST_EXPERIMENTAL + } + otel_integration._record_metrics(kwargs, None, start, end) + call_attrs = mock_histogram.record.call_args[1]["attributes"] + assert call_attrs.get("gen_ai.provider.name") == "anthropic" + assert "gen_ai.system" not in call_attrs +