diff --git a/litellm/integrations/arize/arize_phoenix.py b/litellm/integrations/arize/arize_phoenix.py index cd345a7f76..759dccdd8a 100644 --- a/litellm/integrations/arize/arize_phoenix.py +++ b/litellm/integrations/arize/arize_phoenix.py @@ -32,16 +32,48 @@ class ArizePhoenixLogger(OpenTelemetry): @staticmethod def set_arize_phoenix_attributes(span: Span, kwargs, response_obj): + from litellm.integrations.opentelemetry_utils.base_otel_llm_obs_attributes import safe_set_attribute + _utils.set_attributes(span, kwargs, response_obj, ArizeOTELAttributes) - - # Set project name on the span for all traces to go to custom Phoenix projects - config = ArizePhoenixLogger.get_arize_phoenix_config() - if config.project_name: - from litellm.integrations.opentelemetry_utils.base_otel_llm_obs_attributes import safe_set_attribute - safe_set_attribute(span, "openinference.project.name", config.project_name) - + + # Dynamic project name: check metadata first, then fall back to env var config + dynamic_project_name = ArizePhoenixLogger._get_dynamic_project_name(kwargs) + if dynamic_project_name: + safe_set_attribute(span, "openinference.project.name", dynamic_project_name) + else: + # Fall back to static config from env var + config = ArizePhoenixLogger.get_arize_phoenix_config() + if config.project_name: + safe_set_attribute(span, "openinference.project.name", config.project_name) + return + @staticmethod + def _get_dynamic_project_name(kwargs) -> Optional[str]: + """ + Retrieve dynamic Phoenix project name from request metadata. + + Users can set `metadata.phoenix_project_name` in their request to route + traces to different Phoenix projects dynamically. + """ + standard_logging_payload = kwargs.get("standard_logging_object") + if standard_logging_payload is not None: + metadata = standard_logging_payload.get("metadata") + if isinstance(metadata, dict): + project_name = metadata.get("phoenix_project_name") + if project_name: + return str(project_name) + + # Also check litellm_params.metadata for SDK usage + litellm_params = kwargs.get("litellm_params") or {} + metadata = litellm_params.get("metadata") or {} + if isinstance(metadata, dict): + project_name = metadata.get("phoenix_project_name") + if project_name: + return str(project_name) + + return None + @staticmethod def get_arize_phoenix_config() -> ArizePhoenixConfig: """ diff --git a/litellm/proxy/image_endpoints/endpoints.py b/litellm/proxy/image_endpoints/endpoints.py index 4a2c05f859..4a8eb8e741 100644 --- a/litellm/proxy/image_endpoints/endpoints.py +++ b/litellm/proxy/image_endpoints/endpoints.py @@ -144,6 +144,12 @@ async def image_generation( litellm_call_id=data.get("litellm_call_id", ""), status="success" ) ) + + ### CALL HOOKS ### - modify outgoing data (guardrails, otel, etc.) + response = await proxy_logging_obj.post_call_success_hook( + data=data, user_api_key_dict=user_api_key_dict, response=response + ) + ### RESPONSE HEADERS ### hidden_params = getattr(response, "_hidden_params", {}) or {} model_id = hidden_params.get("model_id", None) or ""