diff --git a/litellm/_redis.py b/litellm/_redis.py index 693f9582705..e05e9d4eb20 100644 --- a/litellm/_redis.py +++ b/litellm/_redis.py @@ -651,7 +651,9 @@ def get_redis_async_client( if arg in args: url_kwargs[arg] = redis_kwargs[arg] else: - verbose_logger.debug(f"REDIS: ignoring argument: {arg}. Not an allowed async_redis.Redis.from_url arg.") + verbose_logger.debug( + "REDIS: ignoring argument: %s. Not an allowed async_redis.Redis.from_url arg.", arg + ) return async_redis.Redis.from_url(**url_kwargs) # Check for Redis Sentinel @@ -805,6 +807,6 @@ def _pretty_print_redis_config(redis_kwargs: dict) -> None: # Fallback to simple logging if rich is not available masker = SensitiveDataMasker() masked_redis_kwargs = masker.mask_dict(redis_kwargs) - verbose_logger.info(f"Redis configuration: {masked_redis_kwargs}") + verbose_logger.info("Redis configuration: %s", masked_redis_kwargs) except Exception as e: - verbose_logger.error(f"Error pretty printing Redis configuration: {e}") + verbose_logger.error("Error pretty printing Redis configuration: %s", e) diff --git a/litellm/a2a_protocol/card_resolver.py b/litellm/a2a_protocol/card_resolver.py index e4cce56d0e4..81a7813d14c 100644 --- a/litellm/a2a_protocol/card_resolver.py +++ b/litellm/a2a_protocol/card_resolver.py @@ -148,13 +148,13 @@ class LiteLLMA2ACardResolver(_A2ACardResolver): # type: ignore[misc] last_error = None for path in paths: try: - verbose_logger.debug(f"Attempting to fetch agent card from {self.base_url}{path}") + verbose_logger.debug("Attempting to fetch agent card from %s%s", self.base_url, path) return await super().get_agent_card( relative_card_path=path, http_kwargs=http_kwargs, ) except Exception as e: - verbose_logger.debug(f"Failed to fetch agent card from {self.base_url}{path}: {e}") + verbose_logger.debug("Failed to fetch agent card from %s%s: %s", self.base_url, path, e) last_error = e continue diff --git a/litellm/a2a_protocol/exception_mapping_utils.py b/litellm/a2a_protocol/exception_mapping_utils.py index 4d24dd4f1d8..16979667fe5 100644 --- a/litellm/a2a_protocol/exception_mapping_utils.py +++ b/litellm/a2a_protocol/exception_mapping_utils.py @@ -192,9 +192,11 @@ async def handle_a2a_localhost_retry( request_type = "streaming " if is_streaming else "" verbose_logger.warning( - f"A2A {request_type}request to '{error.localhost_url}' failed: {error.original_error}. " - f"Agent card contains localhost/internal URL. " - f"Retrying with base_url '{error.base_url}'." + "A2A %srequest to '%s' failed: %s. Agent card contains localhost/internal URL. Retrying with base_url '%s'.", + request_type, + error.localhost_url, + error.original_error, + error.base_url, ) # Fix the agent card URL diff --git a/litellm/a2a_protocol/litellm_completion_bridge/handler.py b/litellm/a2a_protocol/litellm_completion_bridge/handler.py index 1d46e5c700f..21366602d1a 100644 --- a/litellm/a2a_protocol/litellm_completion_bridge/handler.py +++ b/litellm/a2a_protocol/litellm_completion_bridge/handler.py @@ -76,7 +76,7 @@ class A2ACompletionBridgeHandler: ) if a2a_provider_config is not None: - verbose_logger.info(f"A2A: Using provider config for {custom_llm_provider}") + verbose_logger.info("A2A: Using provider config for %s", custom_llm_provider) return await a2a_provider_config.handle_non_streaming( request_id=request_id, @@ -103,7 +103,7 @@ class A2ACompletionBridgeHandler: else: full_model = model - verbose_logger.info(f"A2A completion bridge: model={full_model}, api_base={api_base}") + verbose_logger.info("A2A completion bridge: model=%s, api_base=%s", full_model, api_base) # Build completion params dict completion_params: dict[str, Any] = { @@ -143,7 +143,7 @@ class A2ACompletionBridgeHandler: request_id=request_id, ) - verbose_logger.info(f"A2A completion bridge completed: request_id={request_id}") + verbose_logger.info("A2A completion bridge completed: request_id=%s", request_id) return a2a_response @@ -185,7 +185,7 @@ class A2ACompletionBridgeHandler: ) if a2a_provider_config is not None: - verbose_logger.info(f"A2A: Using provider config for {custom_llm_provider} (streaming)") + verbose_logger.info("A2A: Using provider config for %s (streaming)", custom_llm_provider) async for chunk in a2a_provider_config.handle_streaming( request_id=request_id, @@ -221,7 +221,7 @@ class A2ACompletionBridgeHandler: else: full_model = model - verbose_logger.info(f"A2A completion bridge streaming: model={full_model}, api_base={api_base}") + verbose_logger.info("A2A completion bridge streaming: model=%s, api_base=%s", full_model, api_base) # Build completion params dict completion_params: dict[str, Any] = { @@ -300,7 +300,9 @@ class A2ACompletionBridgeHandler: ) yield completed_event - verbose_logger.info(f"A2A completion bridge streaming completed: request_id={request_id}, chunks={chunk_count}") + verbose_logger.info( + "A2A completion bridge streaming completed: request_id=%s, chunks=%s", request_id, chunk_count + ) # Convenience functions that delegate to the class methods diff --git a/litellm/a2a_protocol/litellm_completion_bridge/transformation.py b/litellm/a2a_protocol/litellm_completion_bridge/transformation.py index a63221b4a77..e216abb6c6d 100644 --- a/litellm/a2a_protocol/litellm_completion_bridge/transformation.py +++ b/litellm/a2a_protocol/litellm_completion_bridge/transformation.py @@ -109,7 +109,7 @@ class A2ACompletionBridgeTransformation: extra_body = {**extra_body, "metadata": merged_metadata} completion_params["extra_body"] = extra_body - verbose_logger.debug(f"A2A -> completion forward metadata keys={list(forward_metadata.keys())}") + verbose_logger.debug("A2A -> completion forward metadata keys=%s", list(forward_metadata.keys())) @staticmethod def a2a_message_to_openai_messages( @@ -145,7 +145,9 @@ class A2ACompletionBridgeTransformation: # once at run level via extra_body.metadata (LangGraph POST /runs/wait shape). openai_message: dict[str, Any] = {"role": openai_role, "content": content} - verbose_logger.debug(f"A2A -> OpenAI transform: role={role} -> {openai_role}, content_length={len(content)}") + verbose_logger.debug( + "A2A -> OpenAI transform: role=%s -> %s, content_length=%s", role, openai_role, len(content) + ) return [openai_message] @@ -186,7 +188,7 @@ class A2ACompletionBridgeTransformation: "result": a2a_message, } - verbose_logger.debug(f"OpenAI -> A2A transform: content_length={len(content)}") + verbose_logger.debug("OpenAI -> A2A transform: content_length=%s", len(content)) return a2a_response diff --git a/litellm/a2a_protocol/main.py b/litellm/a2a_protocol/main.py index 52d35a988c6..ec2d3ccf1f7 100644 --- a/litellm/a2a_protocol/main.py +++ b/litellm/a2a_protocol/main.py @@ -204,7 +204,7 @@ async def _send_message_via_completion_bridge( Requires request; api_base is optional for providers that derive endpoint from model. """ - verbose_logger.info(f"A2A using completion bridge: provider={custom_llm_provider}, api_base={api_base}") + verbose_logger.info("A2A using completion bridge: provider=%s, api_base=%s", custom_llm_provider, api_base) from litellm.a2a_protocol.litellm_completion_bridge.handler import ( A2ACompletionBridgeHandler, @@ -463,7 +463,7 @@ async def asend_message( agent_name = _get_a2a_model_info(a2a_client, kwargs) - verbose_logger.info(f"A2A send_message request_id={request.id}, agent={agent_name}") + verbose_logger.info("A2A send_message request_id=%s, agent=%s", request.id, agent_name) # Get agent card URL for localhost retry logic agent_card = _get_a2a_client_agent_card(a2a_client) @@ -478,7 +478,7 @@ async def asend_message( agent_name=agent_name, ) - verbose_logger.info(f"A2A send_message completed, request_id={request.id}") + verbose_logger.info("A2A send_message completed, request_id=%s", request.id) # Wrap in LiteLLM response type for _hidden_params support response = LiteLLMSendMessageResponse.from_a2a_response(a2a_response, request_id=str(request.id)) @@ -640,7 +640,7 @@ async def asend_message_streaming( raise ValueError("request is required for completion bridge") # api_base is optional for providers that derive endpoint from model (e.g., bedrock/agentcore) - verbose_logger.info(f"A2A streaming using completion bridge: provider={custom_llm_provider}") + verbose_logger.info("A2A streaming using completion bridge: provider=%s", custom_llm_provider) from litellm.a2a_protocol.litellm_completion_bridge.handler import ( A2ACompletionBridgeHandler, @@ -697,7 +697,7 @@ async def asend_message_streaming( proxy_server_request=proxy_server_request, ) - verbose_logger.info(f"A2A send_message_streaming request_id={request.id}, agent={agent_name}") + verbose_logger.info("A2A send_message_streaming request_id=%s, agent=%s", request.id, agent_name) agent_card = _get_a2a_client_agent_card(a2a_client) card_url = get_agent_card_url(agent_card) if agent_card else None @@ -759,7 +759,7 @@ async def create_a2a_client( "The 'a2a' package is required for A2A agent invocation. Install it with: pip install a2a-sdk" ) - verbose_logger.info(f"Creating A2A client for {base_url}") + verbose_logger.info("Creating A2A client for %s", base_url) # Use get_async_httpx_client with per-agent params so that different agents # (with different extra_headers) get separate cached clients. The params @@ -781,7 +781,7 @@ async def create_a2a_client( httpx_client = _async_handler.client if extra_headers: httpx_client.headers.update(extra_headers) - verbose_proxy_logger.debug(f"A2A client created with extra_headers={list(extra_headers.keys())}") + verbose_proxy_logger.debug("A2A client created with extra_headers=%s", list(extra_headers.keys())) a2a_client = await create_client( # pyright: ignore[reportOptionalCall] base_url, @@ -798,7 +798,7 @@ async def create_a2a_client( if agent_card is not None: a2a_client._litellm_agent_card = agent_card # type: ignore[attr-defined] - verbose_logger.info(f"A2A client created for {base_url}") + verbose_logger.info("A2A client created for %s", base_url) return a2a_client @@ -824,7 +824,7 @@ async def aget_agent_card( "The 'a2a' package is required for A2A agent invocation. Install it with: pip install a2a-sdk" ) - verbose_logger.info(f"Fetching agent card from {base_url}") + verbose_logger.info("Fetching agent card from %s", base_url) # Use LiteLLM's cached httpx client http_handler = get_async_httpx_client( @@ -839,5 +839,5 @@ async def aget_agent_card( ) agent_card = await resolver.get_agent_card() - verbose_logger.info(f"Fetched agent card: {agent_card.name if hasattr(agent_card, 'name') else 'unknown'}") + verbose_logger.info("Fetched agent card: %s", agent_card.name if hasattr(agent_card, "name") else "unknown") return agent_card diff --git a/litellm/a2a_protocol/providers/bedrock_agentcore/handler.py b/litellm/a2a_protocol/providers/bedrock_agentcore/handler.py index 56f5f806e7b..d19137ef4a9 100644 --- a/litellm/a2a_protocol/providers/bedrock_agentcore/handler.py +++ b/litellm/a2a_protocol/providers/bedrock_agentcore/handler.py @@ -53,7 +53,7 @@ class BedrockAgentCoreA2AHandler: agent_extra_headers=agent_extra_headers, ) - verbose_logger.info(f"BedrockAgentCore A2A: Sending non-streaming request to {url}") + verbose_logger.info("BedrockAgentCore A2A: Sending non-streaming request to %s", url) client = get_async_httpx_client( llm_provider=cast(Any, httpxSpecialProvider.A2AProvider), @@ -67,7 +67,7 @@ class BedrockAgentCoreA2AHandler: response_data = response.json() if "error" in response_data: - verbose_logger.warning(f"BedrockAgentCore A2A: Agent returned error: {response_data['error']}") + verbose_logger.warning("BedrockAgentCore A2A: Agent returned error: %s", response_data["error"]) return response_data @@ -100,7 +100,7 @@ class BedrockAgentCoreA2AHandler: agent_extra_headers=agent_extra_headers, ) - verbose_logger.info(f"BedrockAgentCore A2A: Sending streaming request to {url}") + verbose_logger.info("BedrockAgentCore A2A: Sending streaming request to %s", url) client = get_async_httpx_client( llm_provider=cast(Any, httpxSpecialProvider.A2AProvider), diff --git a/litellm/a2a_protocol/providers/bedrock_agentcore/transformation.py b/litellm/a2a_protocol/providers/bedrock_agentcore/transformation.py index f9343d2d3b4..0c1e01e7f9f 100644 --- a/litellm/a2a_protocol/providers/bedrock_agentcore/transformation.py +++ b/litellm/a2a_protocol/providers/bedrock_agentcore/transformation.py @@ -195,5 +195,5 @@ class BedrockAgentCoreA2ATransformation: event = json.loads(data_str) yield event except json.JSONDecodeError: - verbose_logger.debug(f"BedrockAgentCore A2A: Skipping non-JSON SSE line: {data_str[:100]}") + verbose_logger.debug("BedrockAgentCore A2A: Skipping non-JSON SSE line: %s", data_str[:100]) continue diff --git a/litellm/a2a_protocol/providers/pydantic_ai_agents/handler.py b/litellm/a2a_protocol/providers/pydantic_ai_agents/handler.py index 86cb2d47ad3..da1fc1eb657 100644 --- a/litellm/a2a_protocol/providers/pydantic_ai_agents/handler.py +++ b/litellm/a2a_protocol/providers/pydantic_ai_agents/handler.py @@ -47,7 +47,7 @@ class PydanticAIHandler: """ if api_base is None: raise ValueError("api_base is required for Pydantic AI agents") - verbose_logger.info(f"Pydantic AI: Routing to Pydantic AI agent at {api_base}") + verbose_logger.info("Pydantic AI: Routing to Pydantic AI agent at %s", api_base) # Send request directly to Pydantic AI agent response_data = await PydanticAITransformation.send_non_streaming_request( @@ -92,7 +92,7 @@ class PydanticAIHandler: """ if api_base is None: raise ValueError("api_base is required for Pydantic AI agents") - verbose_logger.info(f"Pydantic AI: Faking streaming for Pydantic AI agent at {api_base}") + verbose_logger.info("Pydantic AI: Faking streaming for Pydantic AI agent at %s", api_base) # Get raw task response first (not the transformed A2A format) raw_response = await PydanticAITransformation.send_and_get_raw_response( diff --git a/litellm/a2a_protocol/providers/pydantic_ai_agents/transformation.py b/litellm/a2a_protocol/providers/pydantic_ai_agents/transformation.py index 37127f2fcab..d8b22282d3a 100644 --- a/litellm/a2a_protocol/providers/pydantic_ai_agents/transformation.py +++ b/litellm/a2a_protocol/providers/pydantic_ai_agents/transformation.py @@ -118,7 +118,7 @@ class PydanticAITransformation: status = result.get("status", {}) state = status.get("state", "") - verbose_logger.debug(f"Pydantic AI: Poll attempt {attempt + 1}/{max_attempts}, state={state}") + verbose_logger.debug("Pydantic AI: Poll attempt %s/%s, state=%s", attempt + 1, max_attempts, state) if state == "completed": return poll_data @@ -173,7 +173,7 @@ class PydanticAITransformation: # FastA2A uses root endpoint (/) not /messages endpoint = api_base.rstrip("/") - verbose_logger.info(f"Pydantic AI: Sending non-streaming request to {endpoint}") + verbose_logger.info("Pydantic AI: Sending non-streaming request to %s", endpoint) # Send request to Pydantic AI agent using shared async HTTP client client = get_async_httpx_client( @@ -200,7 +200,7 @@ class PydanticAITransformation: # Need to poll for completion task_id = result.get("id") if task_id: - verbose_logger.info(f"Pydantic AI: Task {task_id} submitted, polling for completion...") + verbose_logger.info("Pydantic AI: Task %s submitted, polling for completion...", task_id) response_data = await PydanticAITransformation._poll_for_completion( client=client, endpoint=endpoint, @@ -209,7 +209,7 @@ class PydanticAITransformation: agent_extra_headers=agent_extra_headers, ) - verbose_logger.info(f"Pydantic AI: Received completed response for request_id={request_id}") + verbose_logger.info("Pydantic AI: Received completed response for request_id=%s", request_id) return response_data @@ -518,4 +518,4 @@ class PydanticAITransformation: } yield completed_event - verbose_logger.info(f"Pydantic AI: Fake streaming completed for request_id={request_id}") + verbose_logger.info("Pydantic AI: Fake streaming completed for request_id=%s", request_id) diff --git a/litellm/a2a_protocol/providers/watsonx_orchestrate/handler.py b/litellm/a2a_protocol/providers/watsonx_orchestrate/handler.py index efb2b38b912..2c7c04cec0b 100644 --- a/litellm/a2a_protocol/providers/watsonx_orchestrate/handler.py +++ b/litellm/a2a_protocol/providers/watsonx_orchestrate/handler.py @@ -135,7 +135,7 @@ class WatsonxOrchestrateHandler: response.raise_for_status() result: dict[str, Any] = response.json() status = result.get("status", "") - verbose_logger.debug(f"WXO: Poll {attempt + 1}/{max_attempts} run='{run_id}' status='{status}'") + verbose_logger.debug("WXO: Poll %s/%s run='%s' status='%s'", attempt + 1, max_attempts, run_id, status) if status in WatsonxOrchestrateTransformation.TERMINAL_STATES: return result @@ -297,8 +297,8 @@ class WatsonxOrchestrateHandler: response.raise_for_status() except httpx.TransportError as exc: verbose_logger.warning( - f"WXO: Streaming request failed before a run was submitted " - f"({exc!r}), falling back to non-streaming + fake streaming", + "WXO: Streaming request failed before a run was submitted (%r), falling back to non-streaming + fake streaming", + exc, exc_info=True, ) result = await WatsonxOrchestrateHandler.handle_non_streaming( diff --git a/litellm/a2a_protocol/providers/watsonx_orchestrate/transformation.py b/litellm/a2a_protocol/providers/watsonx_orchestrate/transformation.py index ab7b8abb3ba..18b0795aa8a 100644 --- a/litellm/a2a_protocol/providers/watsonx_orchestrate/transformation.py +++ b/litellm/a2a_protocol/providers/watsonx_orchestrate/transformation.py @@ -214,4 +214,4 @@ class WatsonxOrchestrateTransformation: }, } - verbose_logger.debug(f"WXO: Fake streaming completed for request_id={request_id}") + verbose_logger.debug("WXO: Fake streaming completed for request_id=%s", request_id) diff --git a/litellm/a2a_protocol/streaming_iterator.py b/litellm/a2a_protocol/streaming_iterator.py index 79056ca336f..f954cb187b5 100644 --- a/litellm/a2a_protocol/streaming_iterator.py +++ b/litellm/a2a_protocol/streaming_iterator.py @@ -138,13 +138,15 @@ class A2AStreamingIterator: ) verbose_logger.info( - f"A2A streaming completed: prompt_tokens={prompt_tokens}, " - f"completion_tokens={completion_tokens}, total_tokens={total_tokens}, " - f"response_cost={response_cost}" + "A2A streaming completed: prompt_tokens=%s, completion_tokens=%s, total_tokens=%s, response_cost=%s", + prompt_tokens, + completion_tokens, + total_tokens, + response_cost, ) except Exception as e: - verbose_logger.debug(f"Error in A2A streaming completion handler: {e}") + verbose_logger.debug("Error in A2A streaming completion handler: %s", e) def _build_logging_result(self, usage: litellm.Usage) -> dict[str, Any]: """Build a result dict for logging.""" diff --git a/litellm/anthropic_beta_headers_manager.py b/litellm/anthropic_beta_headers_manager.py index 542885b5130..063a83e6f38 100644 --- a/litellm/anthropic_beta_headers_manager.py +++ b/litellm/anthropic_beta_headers_manager.py @@ -51,7 +51,7 @@ class GetAnthropicBetaHeadersConfig: ) return content except Exception as e: - verbose_logger.error(f"Failed to load local beta headers config: {e}") + verbose_logger.error("Failed to load local beta headers config: %s", e) # Return empty config as fallback return { "anthropic": {}, @@ -246,7 +246,9 @@ def filter_and_transform_beta_headers( # Check if header is in the mapping if header not in provider_mapping: - verbose_logger.debug(f"Dropping unknown beta header '{header}' for provider '{provider}' (not in mapping)") + verbose_logger.debug( + "Dropping unknown beta header '%s' for provider '%s' (not in mapping)", header, provider + ) continue # Get the mapped header value @@ -254,7 +256,7 @@ def filter_and_transform_beta_headers( # Skip if header is unsupported (null value) if mapped_header is None: - verbose_logger.debug(f"Dropping unsupported beta header '{header}' for provider '{provider}'") + verbose_logger.debug("Dropping unsupported beta header '%s' for provider '%s'", header, provider) continue # Add the mapped header diff --git a/litellm/batches/batch_utils.py b/litellm/batches/batch_utils.py index 2e28aaa14df..4f90b50eaa2 100644 --- a/litellm/batches/batch_utils.py +++ b/litellm/batches/batch_utils.py @@ -258,10 +258,10 @@ async def _fetch_batch_output_file_content( if is_base64_unified_file_id: try: file_id = is_base64_unified_file_id.split("llm_output_file_id,")[1].split(";")[0] - verbose_logger.debug(f"Extracted LLM output file ID from unified file ID: {file_id}") + verbose_logger.debug("Extracted LLM output file ID from unified file ID: %s", file_id) except (IndexError, AttributeError) as e: verbose_logger.error( - f"Failed to extract LLM output file ID from unified file ID: {batch.output_file_id}, error: {e}" + "Failed to extract LLM output file ID from unified file ID: %s, error: %s", batch.output_file_id, e ) # Build kwargs for afile_content with credentials from litellm_params diff --git a/litellm/batches/main.py b/litellm/batches/main.py index 3a057d41744..33f2f4613bf 100644 --- a/litellm/batches/main.py +++ b/litellm/batches/main.py @@ -182,7 +182,7 @@ def create_batch( ) except Exception as e: verbose_logger.exception( - f"litellm.batches.main.py::create_batch() - Error inferring custom_llm_provider - {e}" + "litellm.batches.main.py::create_batch() - Error inferring custom_llm_provider - %s", e ) _is_async = kwargs.pop("acreate_batch", False) is True @@ -890,7 +890,7 @@ def cancel_batch( ) except Exception as e: verbose_logger.exception( - f"litellm.batches.main.py::cancel_batch() - Error inferring custom_llm_provider - {e}" + "litellm.batches.main.py::cancel_batch() - Error inferring custom_llm_provider - %s", e ) optional_params = GenericLiteLLMParams(**kwargs) litellm_params = get_litellm_params( diff --git a/litellm/caching/azure_blob_cache.py b/litellm/caching/azure_blob_cache.py index 80ad645ec7b..755b491f9a0 100644 --- a/litellm/caching/azure_blob_cache.py +++ b/litellm/caching/azure_blob_cache.py @@ -67,7 +67,10 @@ class AzureBlobCache(BaseCache): cached_response = json.loads(as_str) verbose_logger.debug( - f"Got Azure Blob Cache: key: {key}, cached_response {cached_response}. Type Response {type(cached_response)}" + "Got Azure Blob Cache: key: %s, cached_response %s. Type Response %s", + key, + cached_response, + type(cached_response), ) return cached_response @@ -84,7 +87,10 @@ class AzureBlobCache(BaseCache): as_str = as_bytes.decode("utf-8") cached_response = json.loads(as_str) verbose_logger.debug( - f"Got Azure Blob Cache: key: {key}, cached_response {cached_response}. Type Response {type(cached_response)}" + "Got Azure Blob Cache: key: %s, cached_response %s. Type Response %s", + key, + cached_response, + type(cached_response), ) return cached_response except ResourceNotFoundError: diff --git a/litellm/caching/caching.py b/litellm/caching/caching.py index 9542be0999a..758a14afb17 100644 --- a/litellm/caching/caching.py +++ b/litellm/caching/caching.py @@ -676,7 +676,7 @@ class Cache: cache_key, cached_data, kwargs = self._add_cache_logic(result=result, **kwargs) self.cache.set_cache(cache_key, cached_data, **kwargs) except Exception as e: - verbose_logger.exception(f"LiteLLM Cache: Excepton add_cache: {e}") + verbose_logger.exception("LiteLLM Cache: Excepton add_cache: %s", e) async def async_add_cache(self, result, dynamic_cache_object: BaseCache | None = None, **kwargs): """ @@ -695,7 +695,7 @@ class Cache: else: await self.cache.async_set_cache(cache_key, cached_data, **kwargs) except Exception as e: - verbose_logger.exception(f"LiteLLM Cache: Excepton add_cache: {e}") + verbose_logger.exception("LiteLLM Cache: Excepton add_cache: %s", e) def _convert_to_cached_embedding( self, @@ -874,7 +874,7 @@ class Cache: else: await self.cache.async_set_cache_pipeline(cache_list=cache_list, **kwargs) except Exception as e: - verbose_logger.exception(f"LiteLLM Cache: Excepton add_cache: {e}") + verbose_logger.exception("LiteLLM Cache: Excepton add_cache: %s", e) def should_use_cache(self, **kwargs): """ diff --git a/litellm/caching/caching_handler.py b/litellm/caching/caching_handler.py index aed38d6ef65..2655a5ad683 100644 --- a/litellm/caching/caching_handler.py +++ b/litellm/caching/caching_handler.py @@ -271,7 +271,7 @@ class LLMCachingHandler: embedding_all_elements_cache_hit=embedding_all_elements_cache_hit, ) - verbose_logger.debug(f"CACHE RESULT: {cached_result}") + verbose_logger.debug("CACHE RESULT: %s", cached_result) return CachingHandlerResponse( cached_result=cached_result, final_embedding_cached_response=final_embedding_cached_response, diff --git a/litellm/caching/dual_cache.py b/litellm/caching/dual_cache.py index b641c600a0e..a242f4a818e 100644 --- a/litellm/caching/dual_cache.py +++ b/litellm/caching/dual_cache.py @@ -147,7 +147,7 @@ class DualCache(BaseCache): return result except Exception as e: - verbose_logger.error(f"LiteLLM Cache: Excepton async add_cache: {e}") + verbose_logger.error("LiteLLM Cache: Excepton async add_cache: %s", e) raise e def get_cache( @@ -347,7 +347,7 @@ class DualCache(BaseCache): if self.redis_cache is not None and local_only is False: await self.redis_cache.async_set_cache(key, value, **kwargs) except Exception as e: - verbose_logger.exception(f"LiteLLM Cache: Excepton async add_cache: {e}") + verbose_logger.exception("LiteLLM Cache: Excepton async add_cache: %s", e) # async_batch_set_cache async def async_set_cache_pipeline(self, cache_list: list, local_only: bool = False, **kwargs): @@ -366,7 +366,7 @@ class DualCache(BaseCache): cache_list=cache_list, ttl=kwargs.pop("ttl", None), **kwargs ) except Exception as e: - verbose_logger.exception(f"LiteLLM Cache: Excepton async add_cache: {e}") + verbose_logger.exception("LiteLLM Cache: Excepton async add_cache: %s", e) async def async_increment_cache( self, diff --git a/litellm/caching/gcs_cache.py b/litellm/caching/gcs_cache.py index d74c68de770..1e1508669b3 100644 --- a/litellm/caching/gcs_cache.py +++ b/litellm/caching/gcs_cache.py @@ -71,12 +71,15 @@ class GCSCache(BaseCache): if response.status_code == 200: cached_response = json.loads(response.text) verbose_logger.debug( - f"Got GCS Cache: key: {key}, cached_response {cached_response}. Type Response {type(cached_response)}" + "Got GCS Cache: key: %s, cached_response %s. Type Response %s", + key, + cached_response, + type(cached_response), ) return cached_response return None except Exception as e: - verbose_logger.error(f"GCS Caching: get_cache() - Got exception from GCS: {e}") + verbose_logger.error("GCS Caching: get_cache() - Got exception from GCS: %s", e) async def async_get_cache(self, key, **kwargs): try: @@ -89,7 +92,7 @@ class GCSCache(BaseCache): return json.loads(response.text) return None except Exception as e: - verbose_logger.error(f"GCS Caching: async_get_cache() - Got exception from GCS: {e}") + verbose_logger.error("GCS Caching: async_get_cache() - Got exception from GCS: %s", e) def flush_cache(self): pass diff --git a/litellm/caching/redis_cache.py b/litellm/caching/redis_cache.py index e3c0e3616f0..2dfd123d46d 100644 --- a/litellm/caching/redis_cache.py +++ b/litellm/caching/redis_cache.py @@ -346,7 +346,8 @@ class RedisCache(BaseCache): verbose_logger.debug("Ignoring async redis ping. No running event loop.") else: verbose_logger.error( - f"Error connecting to Async Redis client - {e}", + "Error connecting to Async Redis client - %s", + e, extra={"error": str(e)}, ) self._handle_async_ping_error(e) @@ -1139,7 +1140,7 @@ class RedisCache(BaseCache): return decoded_results except Exception as e: - verbose_logger.error(f"Error occurred in batch get cache - {e}") + verbose_logger.error("Error occurred in batch get cache - %s", e) return key_value_dict @_redis_circuit_breaker_guard @@ -1257,7 +1258,7 @@ class RedisCache(BaseCache): parent_otel_span=parent_otel_span, ) ) - verbose_logger.error(f"Error occurred in async batch get cache - {e}") + verbose_logger.error("Error occurred in async batch get cache - %s", e) _record_swallowed_redis_failure(self._circuit_breaker, e) return key_value_dict @@ -1292,7 +1293,7 @@ class RedisCache(BaseCache): error=e, call_type=f"sync_ping <- {_get_call_stack_info()}", ) - verbose_logger.error(f"LiteLLM Redis Cache PING: - Got exception from REDIS : {e}") + verbose_logger.error("LiteLLM Redis Cache PING: - Got exception from REDIS : %s", e) raise e async def ping(self) -> bool: @@ -1326,7 +1327,7 @@ class RedisCache(BaseCache): call_type=f"async_ping <- {_get_call_stack_info()}", ) ) - verbose_logger.error(f"LiteLLM Redis Cache PING: - Got exception from REDIS : {e}") + verbose_logger.error("LiteLLM Redis Cache PING: - Got exception from REDIS : %s", e) raise e @_redis_circuit_breaker_guard @@ -1388,7 +1389,7 @@ class RedisCache(BaseCache): else: return {"status": "failed", "message": "Redis ping returned False"} except Exception as e: - verbose_logger.error(f"Redis connection test failed: {e}") + verbose_logger.error("Redis connection test failed: %s", e) return { "status": "failed", "message": f"Redis connection failed: {e}", @@ -1426,7 +1427,7 @@ class RedisCache(BaseCache): # Execute the pipeline and return results results = await pipe.execute() # only return float values - verbose_logger.debug(f"Increment ASYNC Redis Cache PIPELINE: results: {results}") + verbose_logger.debug("Increment ASYNC Redis Cache PIPELINE: results: %s", results) return [r for r in results if isinstance(r, float)] @_redis_circuit_breaker_guard @@ -1513,7 +1514,7 @@ class RedisCache(BaseCache): return None return ttl except Exception as e: - verbose_logger.debug(f"Redis TTL Error: {e}") + verbose_logger.debug("Redis TTL Error: %s", e) _record_swallowed_redis_failure(self._circuit_breaker, e) return None @@ -1565,7 +1566,7 @@ class RedisCache(BaseCache): call_type=f"async_rpush <- {_get_call_stack_info()}", ) ) - verbose_logger.error(f"LiteLLM Redis Cache RPUSH: - Got exception from REDIS : {e}") + verbose_logger.error("LiteLLM Redis Cache RPUSH: - Got exception from REDIS : %s", e) raise e async def _pipeline_rpush_helper( @@ -1711,7 +1712,7 @@ class RedisCache(BaseCache): call_type=f"async_lpop <- {_get_call_stack_info()}", ) ) - verbose_logger.error(f"LiteLLM Redis Cache LPOP: - Got exception from REDIS : {e}") + verbose_logger.error("LiteLLM Redis Cache LPOP: - Got exception from REDIS : %s", e) raise e async def _pipeline_lpop_helper( diff --git a/litellm/caching/redis_cluster_cache.py b/litellm/caching/redis_cluster_cache.py index 127a5c3bd29..926712e38ec 100644 --- a/litellm/caching/redis_cluster_cache.py +++ b/litellm/caching/redis_cluster_cache.py @@ -100,7 +100,7 @@ class RedisClusterCache(RedisCache): except Exception as e: from litellm._logging import verbose_logger - verbose_logger.error(f"Redis Cluster connection test failed: {e}") + verbose_logger.error("Redis Cluster connection test failed: %s", e) return { "status": "failed", "message": f"Redis Cluster connection failed: {e}", diff --git a/litellm/caching/redis_semantic_cache.py b/litellm/caching/redis_semantic_cache.py index f55274d446d..4fe42d1908e 100644 --- a/litellm/caching/redis_semantic_cache.py +++ b/litellm/caching/redis_semantic_cache.py @@ -138,7 +138,7 @@ class RedisSemanticCache(BaseCache): cache_vectorizer=cache_vectorizer, ) except Exception as e: - verbose_logger.error(f"Redis semantic-cache index build failed: {e}") + verbose_logger.error("Redis semantic-cache index build failed: %s", e) raise @classmethod diff --git a/litellm/caching/s3_cache.py b/litellm/caching/s3_cache.py index 5e185de7526..baad0e29c5e 100644 --- a/litellm/caching/s3_cache.py +++ b/litellm/caching/s3_cache.py @@ -104,12 +104,12 @@ class S3Cache(BaseCache): Compatible with Python 3.8+. """ try: - verbose_logger.debug(f"Set ASYNC S3 Cache: Key={key}. Value={value}") + verbose_logger.debug("Set ASYNC S3 Cache: Key=%s. Value=%s", key, value) loop = asyncio.get_event_loop() func = partial(self.set_cache, key, value, **kwargs) await loop.run_in_executor(None, func) except Exception as e: - verbose_logger.error(f"S3 Caching: async_set_cache() - Got exception from S3: {e}") + verbose_logger.error("S3 Caching: async_set_cache() - Got exception from S3: %s", e) def get_cache(self, key, **kwargs): import botocore @@ -138,17 +138,20 @@ class S3Cache(BaseCache): if not isinstance(cached_response, dict): cached_response = dict(cached_response) verbose_logger.debug( - f"Got S3 Cache: key: {key}, cached_response {cached_response}. Type Response {type(cached_response)}" + "Got S3 Cache: key: %s, cached_response %s. Type Response %s", + key, + cached_response, + type(cached_response), ) return cached_response except botocore.exceptions.ClientError as e: # type: ignore if e.response["Error"]["Code"] == "NoSuchKey": - verbose_logger.debug(f"S3 Cache: The specified key '{key}' does not exist in the S3 bucket.") + verbose_logger.debug("S3 Cache: The specified key '%s' does not exist in the S3 bucket.", key) return None except Exception as e: - verbose_logger.error(f"S3 Caching: get_cache() - Got exception from S3: {e}") + verbose_logger.error("S3 Caching: get_cache() - Got exception from S3: %s", e) async def async_get_cache(self, key, **kwargs): """ @@ -156,13 +159,13 @@ class S3Cache(BaseCache): Compatible with Python 3.8+. """ try: - verbose_logger.debug(f"Get ASYNC S3 Cache: key: {key}") + verbose_logger.debug("Get ASYNC S3 Cache: key: %s", key) loop = asyncio.get_event_loop() func = partial(self.get_cache, key, **kwargs) result = await loop.run_in_executor(None, func) return result except Exception as e: - verbose_logger.error(f"S3 Caching: async_get_cache() - Got exception from S3: {e}") + verbose_logger.error("S3 Caching: async_get_cache() - Got exception from S3: %s", e) return None def flush_cache(self): diff --git a/litellm/completion_extras/litellm_responses_transformation/transformation.py b/litellm/completion_extras/litellm_responses_transformation/transformation.py index 3825854852d..16c90d5a20a 100644 --- a/litellm/completion_extras/litellm_responses_transformation/transformation.py +++ b/litellm/completion_extras/litellm_responses_transformation/transformation.py @@ -408,7 +408,7 @@ class LiteLLMResponsesTransformationHandler(CompletionTransformationBridge): self._map_optional_params_to_responses_api_request(optional_params, responses_api_request) stream = optional_params.get("stream") or litellm_params.get("stream", False) - verbose_logger.debug(f"Chat provider: Stream parameter: {stream}") + verbose_logger.debug("Chat provider: Stream parameter: %s", stream) # Ensure stream is properly set in the request if stream: @@ -418,7 +418,7 @@ class LiteLLMResponsesTransformationHandler(CompletionTransformationBridge): previous_response_id = optional_params.get("previous_response_id") if previous_response_id: # Use the existing session handler for responses API - verbose_logger.debug(f"Chat provider: Warning ignoring previous response ID: {previous_response_id}") + verbose_logger.debug("Chat provider: Warning ignoring previous response ID: %s", previous_response_id) # Convert back to responses API format for the actual request @@ -438,7 +438,7 @@ class LiteLLMResponsesTransformationHandler(CompletionTransformationBridge): "client": client, } - verbose_logger.debug(f"Chat provider: Final request model={api_model}, input_items={len(input_items)}") + verbose_logger.debug("Chat provider: Final request model=%s, input_items=%s", api_model, len(input_items)) self._merge_responses_api_request_into_request_data(request_data, responses_api_request, instructions) @@ -776,29 +776,29 @@ class LiteLLMResponsesTransformationHandler(CompletionTransformationBridge): """Convert chat completion content to responses API format""" from litellm.types.llms.openai import ChatCompletionImageObject - verbose_logger.debug(f"Chat provider: Converting content to responses format - input type: {type(content)}") + verbose_logger.debug("Chat provider: Converting content to responses format - input type: %s", type(content)) if content is None: return [self._convert_content_str_to_input_text("", role)] elif isinstance(content, str): result = [self._convert_content_str_to_input_text(content, role)] - verbose_logger.debug(f"Chat provider: String content -> {result}") + verbose_logger.debug("Chat provider: String content -> %s", result) return result elif isinstance(content, list): result = [] for i, item in enumerate(content): - verbose_logger.debug(f"Chat provider: Processing content item {i}: {type(item)} = {item}") + verbose_logger.debug("Chat provider: Processing content item %s: %s = %s", i, type(item), item) if isinstance(item, str): converted = self._convert_content_str_to_input_text(item, role) result.append(converted) - verbose_logger.debug(f"Chat provider: -> {converted}") + verbose_logger.debug("Chat provider: -> %s", converted) elif isinstance(item, dict): # Handle multimodal content original_type = item.get("type") if original_type == "text": converted = self._convert_content_str_to_input_text(item.get("text", ""), role) result.append(converted) - verbose_logger.debug(f"Chat provider: text -> {converted}") + verbose_logger.debug("Chat provider: text -> %s", converted) elif original_type == "image_url": # Map to responses API image format converted = cast( @@ -808,14 +808,14 @@ class LiteLLMResponsesTransformationHandler(CompletionTransformationBridge): ), ) result.append(converted) - verbose_logger.debug(f"Chat provider: image_url -> {converted}") + verbose_logger.debug("Chat provider: image_url -> %s", converted) else: # Try to map other types to responses API format item_type = original_type or "input_text" if item_type == "image": converted = {"type": "input_image", **item} result.append(converted) - verbose_logger.debug(f"Chat provider: image -> {converted}") + verbose_logger.debug("Chat provider: image -> %s", converted) elif item_type == "file": # Map Chat Completion file to Responses API input_file # {"type": "file", "file": {"file_data": "...", "filename": "..."}} @@ -827,7 +827,7 @@ class LiteLLMResponsesTransformationHandler(CompletionTransformationBridge): if key in file_data: converted[key] = file_data[key] result.append(converted) - verbose_logger.debug(f"Chat provider: file -> {converted}") + verbose_logger.debug("Chat provider: file -> %s", converted) elif item_type in [ "input_text", "input_image", @@ -839,17 +839,17 @@ class LiteLLMResponsesTransformationHandler(CompletionTransformationBridge): ]: # Already in responses API format result.append(item) - verbose_logger.debug(f"Chat provider: passthrough -> {item}") + verbose_logger.debug("Chat provider: passthrough -> %s", item) else: # Default to input_text for unknown types converted = self._convert_content_str_to_input_text(str(item.get("text", item)), role) result.append(converted) - verbose_logger.debug(f"Chat provider: unknown({original_type}) -> {converted}") - verbose_logger.debug(f"Chat provider: Final converted content: {result}") + verbose_logger.debug("Chat provider: unknown(%s) -> %s", original_type, converted) + verbose_logger.debug("Chat provider: Final converted content: %s", result) return result else: result = [self._convert_content_str_to_input_text(str(content), role)] - verbose_logger.debug(f"Chat provider: Other content type -> {result}") + verbose_logger.debug("Chat provider: Other content type -> %s", result) return result def _convert_tools_to_responses_format(self, tools: list[dict[str, Any]]) -> list["ALL_RESPONSES_API_TOOL_PARAMS"]: @@ -1032,13 +1032,13 @@ class LiteLLMResponsesTransformationHandler(CompletionTransformationBridge): annotation_dict = annotation else: # Skip unsupported annotation types - verbose_logger.debug(f"Skipping unsupported annotation type: {type(annotation)}") + verbose_logger.debug("Skipping unsupported annotation type: %s", type(annotation)) continue result.append(annotation_dict) # type: ignore except Exception as e: # Skip malformed annotations - verbose_logger.debug(f"Skipping malformed annotation: {annotation}, error: {e}") + verbose_logger.debug("Skipping malformed annotation: %s, error: %s", annotation, e) continue return result if result else None @@ -1122,11 +1122,11 @@ class OpenAiResponsesToChatCompletionStreamIterator(BaseModelResponseIterator): ): return ModelResponseStream(**parsed_chunk) - verbose_logger.debug(f"Chat provider: Processing event type: {event_type}") + verbose_logger.debug("Chat provider: Processing event type: %s", event_type) if event_type == "response.created": # Initial response creation event - verbose_logger.debug(f"Chat provider: response.created -> {parsed_chunk}") + verbose_logger.debug("Chat provider: response.created -> %s", parsed_chunk) return ModelResponseStream( choices=[ StreamingChoices( @@ -1345,7 +1345,7 @@ class OpenAiResponsesToChatCompletionStreamIterator(BaseModelResponseIterator): else: pass # For any unhandled event types, create a minimal valid chunk or skip - verbose_logger.debug(f"Chat provider: Unhandled event type '{event_type}', creating empty chunk") + verbose_logger.debug("Chat provider: Unhandled event type '%s', creating empty chunk", event_type) # Return a minimal valid chunk for unknown events return ModelResponseStream( @@ -1368,7 +1368,7 @@ class OpenAiResponsesToChatCompletionStreamIterator(BaseModelResponseIterator): Returns: ModelResponseStream: OpenAI-formatted streaming chunk """ - verbose_logger.debug(f"Chat provider: transform_streaming_response called with chunk: {chunk}") + verbose_logger.debug("Chat provider: transform_streaming_response called with chunk: %s", chunk) return self._with_stream_scoped_id( OpenAiResponsesToChatCompletionStreamIterator.translate_responses_chunk_to_openai_stream(chunk) ) diff --git a/litellm/cost_calculator.py b/litellm/cost_calculator.py index f04a9d61d4a..030ff4c372d 100644 --- a/litellm/cost_calculator.py +++ b/litellm/cost_calculator.py @@ -273,7 +273,7 @@ def _get_additional_costs( completion_tokens=completion_tokens, ) except Exception as e: - verbose_logger.debug(f"Error calculating additional costs: {e}") + verbose_logger.debug("Error calculating additional costs: %s", e) return None @@ -715,7 +715,7 @@ def _get_provider_for_cost_calc( _, custom_llm_provider, _, _ = litellm.get_llm_provider(model=model) except Exception as e: verbose_logger.debug( - f"litellm.cost_calculator.py::_get_provider_for_cost_calc() - Error inferring custom_llm_provider - {e}" + "litellm.cost_calculator.py::_get_provider_for_cost_calc() - Error inferring custom_llm_provider - %s", e ) return None @@ -896,7 +896,7 @@ def _get_usage_object( elif isinstance(usage_obj, BaseModel): return Usage(**usage_obj.model_dump()) else: - verbose_logger.debug(f"Unknown usage object type: {type(usage_obj)}, usage_obj: {usage_obj}") + verbose_logger.debug("Unknown usage object type: %s, usage_obj: %s", type(usage_obj), usage_obj) return None @@ -994,16 +994,17 @@ def _apply_cost_margin( if custom_llm_provider and custom_llm_provider in litellm.cost_margin_config: margin_config = litellm.cost_margin_config[custom_llm_provider] if verbose_logger.isEnabledFor(logging.DEBUG): - verbose_logger.debug(f"Found provider-specific margin config for {custom_llm_provider}: {margin_config}") + verbose_logger.debug("Found provider-specific margin config for %s: %s", custom_llm_provider, margin_config) elif "global" in litellm.cost_margin_config: margin_config = litellm.cost_margin_config["global"] if verbose_logger.isEnabledFor(logging.DEBUG): - verbose_logger.debug(f"Using global margin config: {margin_config}") + verbose_logger.debug("Using global margin config: %s", margin_config) else: if verbose_logger.isEnabledFor(logging.DEBUG): verbose_logger.debug( - f"No margin config found. Provider: {custom_llm_provider}, " - f"Available configs: {list(litellm.cost_margin_config.keys())}" + "No margin config found. Provider: %s, Available configs: %s", + custom_llm_provider, + list(litellm.cost_margin_config.keys()), ) if margin_config is not None: @@ -1092,7 +1093,7 @@ def _store_cost_breakdown_in_logging_obj( ) except Exception as breakdown_error: - verbose_logger.debug(f"Error storing cost breakdown: {breakdown_error}") + verbose_logger.debug("Error storing cost breakdown: %s", breakdown_error) # Don't fail the main cost calculation if breakdown storage fails @@ -1219,7 +1220,7 @@ def completion_cost( for idx, model in enumerate(potential_model_names): try: if verbose_logger.isEnabledFor(logging.DEBUG): - verbose_logger.debug(f"selected model name for cost calculation: {model}") + verbose_logger.debug("selected model name for cost calculation: %s", model) if completion_response is not None and ( isinstance(completion_response, BaseModel) or isinstance(completion_response, dict) @@ -1315,7 +1316,8 @@ def completion_cost( ) # strip the llm provider from the model name -> for image gen cost calculation except Exception as e: verbose_logger.debug( - f"litellm.cost_calculator.py::completion_cost() - Error inferring custom_llm_provider - {e}" + "litellm.cost_calculator.py::completion_cost() - Error inferring custom_llm_provider - %s", + e, ) if CostCalculatorUtils._call_type_has_image_response(call_type) and isinstance( completion_response, ImageResponse @@ -1662,7 +1664,7 @@ def completion_cost( return _final_cost except Exception as e: verbose_logger.debug( - f"litellm.cost_calculator.py::completion_cost() - Error calculating cost for model={model} - {e}" + "litellm.cost_calculator.py::completion_cost() - Error calculating cost for model=%s - %s", model, e ) if idx == len(potential_model_names) - 1: raise e @@ -1878,7 +1880,7 @@ def vector_store_search_cost( ) if config is None: - verbose_logger.debug(f"Vector store search is not supported for {custom_llm_provider}") + verbose_logger.debug("Vector store search is not supported for %s", custom_llm_provider) return 0.0, 0.0 return config.calculate_vector_store_cost( @@ -1966,7 +1968,7 @@ def default_image_cost_calculator( # gpt-image-1 models use low, medium, high quality. If user did not specify quality, use medium fot gpt-image-1 model family model_name_with_v2_quality = f"{ImageGenerationRequestQuality.HIGH.value}/{base_model_name}" - verbose_logger.debug(f"Looking up cost for models: {model_name_with_quality}, {base_model_name}") + verbose_logger.debug("Looking up cost for models: %s, %s", model_name_with_quality, base_model_name) model_without_provider = f"{size_str}/{model.split('/')[-1]}" model_with_quality_without_provider = f"{quality}/{model_without_provider}" if quality else model_without_provider @@ -2036,7 +2038,7 @@ def default_video_cost_calculator( model_name_without_custom_llm_provider = model.replace(f"{custom_llm_provider}/", "") base_model_name = f"{custom_llm_provider}/{model_name_without_custom_llm_provider}" - verbose_logger.debug(f"Looking up cost for video model: {base_model_name}") + verbose_logger.debug("Looking up cost for video model: %s", base_model_name) model_without_provider = model.split("/")[-1] @@ -2072,7 +2074,8 @@ def default_video_cost_calculator( # If no cost information found, return 0 verbose_logger.info( - f"No cost information found for video model {model}. Please add pricing to model_prices_and_context_window.json" + "No cost information found for video model %s. Please add pricing to model_prices_and_context_window.json", + model, ) return 0.0 diff --git a/litellm/experimental_mcp_client/client.py b/litellm/experimental_mcp_client/client.py index 8815c38192b..c9d73363242 100644 --- a/litellm/experimental_mcp_client/client.py +++ b/litellm/experimental_mcp_client/client.py @@ -364,7 +364,7 @@ class MCPClient: try: await session_ctx.__aexit__(None, None, None) except BaseException as e: - verbose_logger.debug(f"Error during session context exit: {e}") + verbose_logger.debug("Error during session context exit: %s", e) except BaseException as e: in_flight_error = e raise @@ -372,7 +372,7 @@ class MCPClient: try: await transport_ctx.__aexit__(None, None, None) except BaseException as exit_error: - verbose_logger.debug(f"Error during transport context exit: {exit_error}") + verbose_logger.debug("Error during transport context exit: %s", exit_error) root_cause = _first_non_cancelled_cause(exit_error) if root_cause is not None and isinstance(in_flight_error, asyncio.CancelledError): raise root_cause from in_flight_error @@ -402,7 +402,7 @@ class MCPClient: try: await http_client.aclose() except BaseException as e: - verbose_logger.debug(f"Error during http_client cleanup: {e}") + verbose_logger.debug("Error during http_client cleanup: %s", e) def update_auth_value(self, mcp_auth_value: str | dict[str, str]): """ @@ -464,7 +464,7 @@ class MCPClient: """Create an httpx.AsyncClient with LiteLLM's SSL configuration.""" # Get unified SSL configuration using the same logic as http_handler.py ssl_config = get_ssl_configuration(self.ssl_verify) - verbose_logger.debug(f"MCP client using SSL configuration: {type(ssl_config).__name__}") + verbose_logger.debug("MCP client using SSL configuration: %s", type(ssl_config).__name__) # The MCP SDK's sse_client and streamable_http_client call this factory without # passing auth=, so the fallback is used: a v2-resolved auth if present, else the # SigV4 aws_auth. Both are None for the common case — no behavior change. @@ -490,7 +490,7 @@ class MCPClient: MCP client (triggering the upstream OAuth flow) rather than masking them as "connected, no tools". """ - verbose_logger.debug(f"MCP client listing tools from {self.server_url or 'stdio'}") + verbose_logger.debug("MCP client listing tools from %s", self.server_url or "stdio") async def _list_tools_operation(session: ClientSession): return await session.list_tools() @@ -499,7 +499,9 @@ class MCPClient: result = await self.run_with_session(_list_tools_operation, quiet_on_error=raise_on_error) tool_count = len(result.tools) tool_names = [tool.name for tool in result.tools] - verbose_logger.info(f"MCP client listed {tool_count} tools from {self.server_url or 'stdio'}: {tool_names}") + verbose_logger.info( + "MCP client listed %s tools from %s: %s", tool_count, self.server_url or "stdio", tool_names + ) return result.tools except asyncio.CancelledError: verbose_logger.warning("MCP client list_tools was cancelled") @@ -555,7 +557,7 @@ class MCPClient: an upstream 401 so it can re-mint the exchanged token and retry once; every other caller keeps the default and gets graceful ``isError`` degradation. """ - verbose_logger.info(f"MCP client calling tool '{call_tool_request_params.name}'") + verbose_logger.info("MCP client calling tool '%s'", call_tool_request_params.name) async def on_progress(progress: float, total: float | None, message: str | None): percentage = (progress / total * 100) if total else 0 @@ -568,7 +570,7 @@ class MCPClient: try: await host_progress_callback(progress, total) except Exception as e: - verbose_logger.warning(f"Failed to forward to Host: {e}") + verbose_logger.warning("Failed to forward to Host: %s", e) async def _call_tool_operation(session: ClientSession): verbose_logger.debug("MCP client sending tool call to session") @@ -580,16 +582,16 @@ class MCPClient: try: tool_result = await self.run_with_session(_call_tool_operation, quiet_on_error=raise_on_error) - verbose_logger.info(f"MCP client tool call '{call_tool_request_params.name}' completed successfully") + verbose_logger.info("MCP client tool call '%s' completed successfully", call_tool_request_params.name) return tool_result except asyncio.CancelledError: - verbose_logger.warning(f"MCP client tool call timed out after {self.timeout}s for {self.server_url}") + verbose_logger.warning("MCP client tool call timed out after %ss for %s", self.timeout, self.server_url) raise except Exception as e: import traceback error_trace = traceback.format_exc() - verbose_logger.debug(f"MCP client tool call traceback:\n{error_trace}") + verbose_logger.debug("MCP client tool call traceback:\n%s", error_trace) # Log detailed error information error_type = type(e).__name__ # When the caller opted into raise_on_error it owns the exception and logs it at the @@ -619,7 +621,7 @@ class MCPClient: async def list_prompts(self) -> list[Prompt]: """List available prompts from the server.""" - verbose_logger.debug(f"MCP client listing tools from {self.server_url or 'stdio'}") + verbose_logger.debug("MCP client listing tools from %s", self.server_url or "stdio") async def _list_prompts_operation(session: ClientSession): return await session.list_prompts() @@ -629,7 +631,7 @@ class MCPClient: prompt_count = len(result.prompts) prompt_names = [prompt.name for prompt in result.prompts] verbose_logger.info( - f"MCP client listed {prompt_count} tools from {self.server_url or 'stdio'}: {prompt_names}" + "MCP client listed %s tools from %s: %s", prompt_count, self.server_url or "stdio", prompt_names ) return result.prompts except asyncio.CancelledError: @@ -638,11 +640,11 @@ class MCPClient: except Exception as e: error_type = type(e).__name__ verbose_logger.error( - f"MCP client list_prompts failed - " - f"Error Type: {error_type}, " - f"Error: {e}, " - f"Server: {self.server_url or 'stdio'}, " - f"Transport: {self.transport_type}" + "MCP client list_prompts failed - Error Type: %s, Error: %s, Server: %s, Transport: %s", + error_type, + e, + self.server_url or "stdio", + self.transport_type, ) # Check if it's a stream/connection error if "BrokenResourceError" in error_type or "Broken" in error_type: @@ -655,7 +657,7 @@ class MCPClient: async def get_prompt(self, get_prompt_request_params: GetPromptRequestParams) -> GetPromptResult: """Fetch a prompt definition from the MCP server.""" - verbose_logger.info(f"MCP client fetching prompt '{get_prompt_request_params.name}'") + verbose_logger.info("MCP client fetching prompt '%s'", get_prompt_request_params.name) async def _get_prompt_operation(session: ClientSession): verbose_logger.debug("MCP client sending get_prompt request to session") @@ -666,7 +668,7 @@ class MCPClient: try: get_prompt_result = await self.run_with_session(_get_prompt_operation) - verbose_logger.info(f"MCP client get_prompt '{get_prompt_request_params.name}' completed successfully") + verbose_logger.info("MCP client get_prompt '%s' completed successfully", get_prompt_request_params.name) return get_prompt_result except asyncio.CancelledError: verbose_logger.warning("MCP client get_prompt was cancelled") @@ -675,16 +677,16 @@ class MCPClient: import traceback error_trace = traceback.format_exc() - verbose_logger.debug(f"MCP client get_prompt traceback:\n{error_trace}") + verbose_logger.debug("MCP client get_prompt traceback:\n%s", error_trace) # Log detailed error information error_type = type(e).__name__ verbose_logger.error( - f"MCP client get_prompt failed - " - f"Error Type: {error_type}, " - f"Error: {e}, " - f"Prompt: {get_prompt_request_params.name}, " - f"Server: {self.server_url or 'stdio'}, " - f"Transport: {self.transport_type}" + "MCP client get_prompt failed - Error Type: %s, Error: %s, Prompt: %s, Server: %s, Transport: %s", + error_type, + e, + get_prompt_request_params.name, + self.server_url or "stdio", + self.transport_type, ) # Check if it's a stream/connection error if "BrokenResourceError" in error_type or "Broken" in error_type: @@ -696,7 +698,7 @@ class MCPClient: async def list_resources(self) -> list[Resource]: """List available resources from the server.""" - verbose_logger.debug(f"MCP client listing resources from {self.server_url or 'stdio'}") + verbose_logger.debug("MCP client listing resources from %s", self.server_url or "stdio") async def _list_resources_operation(session: ClientSession): return await session.list_resources() @@ -706,7 +708,7 @@ class MCPClient: resource_count = len(result.resources) resource_names = [resource.name for resource in result.resources] verbose_logger.info( - f"MCP client listed {resource_count} resources from {self.server_url or 'stdio'}: {resource_names}" + "MCP client listed %s resources from %s: %s", resource_count, self.server_url or "stdio", resource_names ) return result.resources except asyncio.CancelledError: @@ -715,11 +717,11 @@ class MCPClient: except Exception as e: error_type = type(e).__name__ verbose_logger.error( - f"MCP client list_resources failed - " - f"Error Type: {error_type}, " - f"Error: {e}, " - f"Server: {self.server_url or 'stdio'}, " - f"Transport: {self.transport_type}" + "MCP client list_resources failed - Error Type: %s, Error: %s, Server: %s, Transport: %s", + error_type, + e, + self.server_url or "stdio", + self.transport_type, ) # Check if it's a stream/connection error if "BrokenResourceError" in error_type or "Broken" in error_type: @@ -732,7 +734,7 @@ class MCPClient: async def list_resource_templates(self) -> list[ResourceTemplate]: """List available resource templates from the server.""" - verbose_logger.debug(f"MCP client listing resource templates from {self.server_url or 'stdio'}") + verbose_logger.debug("MCP client listing resource templates from %s", self.server_url or "stdio") async def _list_resource_templates_operation(session: ClientSession): return await session.list_resource_templates() @@ -742,7 +744,10 @@ class MCPClient: resource_template_count = len(result.resourceTemplates) resource_template_names = [resourceTemplate.name for resourceTemplate in result.resourceTemplates] verbose_logger.info( - f"MCP client listed {resource_template_count} resource templates from {self.server_url or 'stdio'}: {resource_template_names}" + "MCP client listed %s resource templates from %s: %s", + resource_template_count, + self.server_url or "stdio", + resource_template_names, ) return result.resourceTemplates except asyncio.CancelledError: @@ -751,11 +756,11 @@ class MCPClient: except Exception as e: error_type = type(e).__name__ verbose_logger.error( - f"MCP client list_resource_templates failed - " - f"Error Type: {error_type}, " - f"Error: {e}, " - f"Server: {self.server_url or 'stdio'}, " - f"Transport: {self.transport_type}" + "MCP client list_resource_templates failed - Error Type: %s, Error: %s, Server: %s, Transport: %s", + error_type, + e, + self.server_url or "stdio", + self.transport_type, ) # Check if it's a stream/connection error if "BrokenResourceError" in error_type or "Broken" in error_type: @@ -768,7 +773,7 @@ class MCPClient: async def read_resource(self, url: AnyUrl) -> ReadResourceResult: """Fetch resource contents from the MCP server.""" - verbose_logger.info(f"MCP client fetching resource '{url}'") + verbose_logger.info("MCP client fetching resource '%s'", url) async def _read_resource_operation(session: ClientSession): verbose_logger.debug("MCP client sending read_resource request to session") @@ -776,7 +781,7 @@ class MCPClient: try: read_resource_result = await self.run_with_session(_read_resource_operation) - verbose_logger.info(f"MCP client read_resource '{url}' completed successfully") + verbose_logger.info("MCP client read_resource '%s' completed successfully", url) return read_resource_result except asyncio.CancelledError: verbose_logger.warning("MCP client read_resource was cancelled") @@ -785,16 +790,16 @@ class MCPClient: import traceback error_trace = traceback.format_exc() - verbose_logger.debug(f"MCP client read_resource traceback:\n{error_trace}") + verbose_logger.debug("MCP client read_resource traceback:\n%s", error_trace) # Log detailed error information error_type = type(e).__name__ verbose_logger.error( - f"MCP client read_resource failed - " - f"Error Type: {error_type}, " - f"Error: {e}, " - f"Url: {url}, " - f"Server: {self.server_url or 'stdio'}, " - f"Transport: {self.transport_type}" + "MCP client read_resource failed - Error Type: %s, Error: %s, Url: %s, Server: %s, Transport: %s", + error_type, + e, + url, + self.server_url or "stdio", + self.transport_type, ) # Check if it's a stream/connection error if "BrokenResourceError" in error_type or "Broken" in error_type: diff --git a/litellm/google_genai/adapters/transformation.py b/litellm/google_genai/adapters/transformation.py index 7c2800db07b..b13fb71690b 100644 --- a/litellm/google_genai/adapters/transformation.py +++ b/litellm/google_genai/adapters/transformation.py @@ -104,9 +104,10 @@ class GoogleGenAIStreamWrapper(AdapterCompletionStreamWrapper): except json.JSONDecodeError: # This can happen if the stream is abruptly cut off mid-argument string. verbose_logger.warning( - f"Could not parse tool call arguments at end of stream for index {tool_call_index}. " - f"Name: {tool_call_data['name']}. " - f"Partial args: {tool_call_data['arguments']}" + "Could not parse tool call arguments at end of stream for index %s. Name: %s. Partial args: %s", + tool_call_index, + tool_call_data["name"], + tool_call_data["arguments"], ) if parts: final_chunk = { @@ -662,7 +663,7 @@ class GoogleGenAIAdapter: # Optimization: Skip chunks that have no new data if not function_name and not args_chunk: - verbose_logger.debug(f"Skipping empty tool call chunk for index: {tool_call_index}") + verbose_logger.debug("Skipping empty tool call chunk for index: %s", tool_call_index) continue if function_name: diff --git a/litellm/integrations/SlackAlerting/batching_handler.py b/litellm/integrations/SlackAlerting/batching_handler.py index da905b606a5..12b1f772616 100644 --- a/litellm/integrations/SlackAlerting/batching_handler.py +++ b/litellm/integrations/SlackAlerting/batching_handler.py @@ -68,8 +68,8 @@ async def send_to_webhook(slackAlertingInstance: SlackAlertingType, item, count) data=json.dumps(payload), ) if response.status_code != 200: - verbose_proxy_logger.debug(f"Error sending slack alert to url={item['url']}. Error={response.text}") + verbose_proxy_logger.debug("Error sending slack alert to url=%s. Error=%s", item["url"], response.text) except Exception as e: - verbose_proxy_logger.debug(f"Error sending slack alert: {e}") + verbose_proxy_logger.debug("Error sending slack alert: %s", e) finally: _print_alerting_payload_warning(payload, slackAlertingInstance=slackAlertingInstance) diff --git a/litellm/integrations/SlackAlerting/slack_alerting.py b/litellm/integrations/SlackAlerting/slack_alerting.py index 114924e7359..0d842a5889a 100644 --- a/litellm/integrations/SlackAlerting/slack_alerting.py +++ b/litellm/integrations/SlackAlerting/slack_alerting.py @@ -1467,7 +1467,7 @@ Model Info: try: await self._flush_digest_buckets() except Exception as e: - verbose_proxy_logger.debug(f"Error flushing digest buckets: {e}") + verbose_proxy_logger.debug("Error flushing digest buckets: %s", e) await self.flush_queue() async def async_log_success_event(self, kwargs, response_obj, start_time, end_time): @@ -1502,7 +1502,7 @@ Model Info: ) except Exception as e: verbose_proxy_logger.error( - f"[Non-Blocking Error] Slack Alerting: Got error in logging LLM deployment latency: {e}" + "[Non-Blocking Error] Slack Alerting: Got error in logging LLM deployment latency: %s", e ) async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time): @@ -1522,7 +1522,7 @@ Model Info: ) ) except Exception as e: - verbose_logger.debug(f"Exception raises -{e}") + verbose_logger.debug("Exception raises -%s", e) if isinstance(kwargs.get("exception", ""), APIError): if "outage_alerts" in self.alert_types: @@ -1662,9 +1662,9 @@ Model Info: ) except ValueError as ve: - verbose_proxy_logger.error(f"Invalid time range format: {ve}") + verbose_proxy_logger.error("Invalid time range format: %s", ve) except Exception as e: - verbose_proxy_logger.error(f"Error sending spend report: {e}") + verbose_proxy_logger.error("Error sending spend report: %s", e) async def send_monthly_spend_report(self): """ """ diff --git a/litellm/integrations/anthropic_cache_control_hook.py b/litellm/integrations/anthropic_cache_control_hook.py index 751c8c01aae..f52b6bd8415 100644 --- a/litellm/integrations/anthropic_cache_control_hook.py +++ b/litellm/integrations/anthropic_cache_control_hook.py @@ -143,8 +143,8 @@ class AnthropicCacheControlHook(CustomPromptManagement): if limit_reached: verbose_logger.warning( - f"AnthropicCacheControlHook: Reached the Anthropic limit of " - f"{MAX_CACHE_CONTROL_BLOCKS} cache_control blocks. Skipping further injection." + "AnthropicCacheControlHook: Reached the Anthropic limit of %s cache_control blocks. Skipping further injection.", + MAX_CACHE_CONTROL_BLOCKS, ) return messages @@ -174,8 +174,10 @@ class AnthropicCacheControlHook(CustomPromptManagement): return [targetted_index] verbose_logger.warning( - f"AnthropicCacheControlHook: Provided index {original_index} is out of bounds for message list of length {len(messages)}. " - f"Targeted index was {targetted_index}. Skipping cache control injection for this point." + "AnthropicCacheControlHook: Provided index %s is out of bounds for message list of length %s. Targeted index was %s. Skipping cache control injection for this point.", + original_index, + len(messages), + targetted_index, ) return [] diff --git a/litellm/integrations/argilla.py b/litellm/integrations/argilla.py index d41291f9f98..b1cda6a5593 100644 --- a/litellm/integrations/argilla.py +++ b/litellm/integrations/argilla.py @@ -185,9 +185,9 @@ class ArgillaLogger(CustomBatchLogger): ) if response.status_code >= 300: - verbose_logger.error(f"Argilla Error: {response.status_code} - {response.text}") + verbose_logger.error("Argilla Error: %s - %s", response.status_code, response.text) else: - verbose_logger.debug(f"Batch of {len(self.log_queue)} runs successfully created") + verbose_logger.debug("Batch of %s runs successfully created", len(self.log_queue)) self.log_queue.clear() except Exception: @@ -204,7 +204,7 @@ class ArgillaLogger(CustomBatchLogger): random_sample = random.random() if random_sample > sampling_rate: verbose_logger.info( - f"Skipping Langsmith logging. Sampling rate={sampling_rate}, random_sample={random_sample}" + "Skipping Langsmith logging. Sampling rate=%s, random_sample=%s", sampling_rate, random_sample ) return # Skip logging verbose_logger.debug( @@ -217,7 +217,7 @@ class ArgillaLogger(CustomBatchLogger): return self.log_queue.append(data) - verbose_logger.debug(f"Langsmith, event added to queue. Will flush in {self.flush_interval} seconds...") + verbose_logger.debug("Langsmith, event added to queue. Will flush in %s seconds...", self.flush_interval) if len(self.log_queue) >= self.batch_size: self._send_batch() @@ -231,7 +231,7 @@ class ArgillaLogger(CustomBatchLogger): random_sample = random.random() if random_sample > sampling_rate: verbose_logger.info( - f"Skipping Langsmith logging. Sampling rate={sampling_rate}, random_sample={random_sample}" + "Skipping Langsmith logging. Sampling rate=%s, random_sample=%s", sampling_rate, random_sample ) return # Skip logging verbose_logger.debug( @@ -272,7 +272,7 @@ class ArgillaLogger(CustomBatchLogger): random_sample = random.random() if random_sample > sampling_rate: verbose_logger.info( - f"Skipping Langsmith logging. Sampling rate={sampling_rate}, random_sample={random_sample}" + "Skipping Langsmith logging. Sampling rate=%s, random_sample=%s", sampling_rate, random_sample ) return # Skip logging verbose_logger.info("Langsmith Failure Event Logging!") @@ -325,7 +325,7 @@ class ArgillaLogger(CustomBatchLogger): response.raise_for_status() if response.status_code >= 300: - verbose_logger.error(f"Argilla Error: {response.status_code} - {response.text}") + verbose_logger.error("Argilla Error: %s - %s", response.status_code, response.text) else: verbose_logger.debug("Batch of %s runs successfully created", len(self.log_queue)) except httpx.HTTPStatusError: diff --git a/litellm/integrations/arize/_utils.py b/litellm/integrations/arize/_utils.py index 032f490860d..fe5d235e51b 100644 --- a/litellm/integrations/arize/_utils.py +++ b/litellm/integrations/arize/_utils.py @@ -461,7 +461,7 @@ def set_attributes(span: "Span", kwargs, response_obj, attributes: type[BaseLLMO _set_response_attributes(span=span, response_obj=response_obj_for_attrs) except Exception as e: - verbose_logger.error(f"[Arize/Phoenix] Failed to set OpenInference span attributes: {e}") + verbose_logger.error("[Arize/Phoenix] Failed to set OpenInference span attributes: %s", e) if hasattr(span, "record_exception"): span.record_exception(e) diff --git a/litellm/integrations/arize/arize_phoenix.py b/litellm/integrations/arize/arize_phoenix.py index db698dd6b77..ae8a6994488 100644 --- a/litellm/integrations/arize/arize_phoenix.py +++ b/litellm/integrations/arize/arize_phoenix.py @@ -425,7 +425,7 @@ class ArizePhoenixLogger(OpenTelemetry): # type: ignore endpoint = "http://localhost:6006/v1/traces" protocol = "otlp_http" verbose_logger.debug( - f"No PHOENIX_COLLECTOR_ENDPOINT found, using default local Phoenix endpoint: {endpoint}" + "No PHOENIX_COLLECTOR_ENDPOINT found, using default local Phoenix endpoint: %s", endpoint ) otlp_auth_headers = None diff --git a/litellm/integrations/arize/arize_phoenix_prompt_manager.py b/litellm/integrations/arize/arize_phoenix_prompt_manager.py index ca74835e167..9985bc20af0 100644 --- a/litellm/integrations/arize/arize_phoenix_prompt_manager.py +++ b/litellm/integrations/arize/arize_phoenix_prompt_manager.py @@ -339,7 +339,7 @@ class ArizePhoenixPromptManager(CustomPromptManagement): # Log error but don't fail the call import litellm - litellm._logging.verbose_proxy_logger.error(f"Error in Arize Phoenix prompt pre_call_hook: {e}") + litellm._logging.verbose_proxy_logger.error("Error in Arize Phoenix prompt pre_call_hook: %s", e) return messages, litellm_params def get_available_prompts(self) -> list[str]: diff --git a/litellm/integrations/azure_sentinel/azure_sentinel.py b/litellm/integrations/azure_sentinel/azure_sentinel.py index e0ed0cd7cf3..29bbac2912a 100644 --- a/litellm/integrations/azure_sentinel/azure_sentinel.py +++ b/litellm/integrations/azure_sentinel/azure_sentinel.py @@ -203,7 +203,7 @@ class AzureSentinelLogger(CustomBatchLogger): await self.async_send_batch() except Exception as e: - verbose_logger.exception(f"Azure Sentinel Layer Error - {e}\n{traceback.format_exc()}") + verbose_logger.exception("Azure Sentinel Layer Error - %s\n%s", e, traceback.format_exc()) async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time): """ @@ -233,7 +233,7 @@ class AzureSentinelLogger(CustomBatchLogger): await self.async_send_batch() except Exception as e: - verbose_logger.exception(f"Azure Sentinel Layer Error - {e}\n{traceback.format_exc()}") + verbose_logger.exception("Azure Sentinel Layer Error - %s\n%s", e, traceback.format_exc()) async def async_log_audit_log_event(self, audit_log: StandardAuditLogPayload) -> None: """ @@ -256,7 +256,7 @@ class AzureSentinelLogger(CustomBatchLogger): await self.async_send_audit_batch() except Exception as e: - verbose_logger.exception(f"Azure Sentinel Audit Log Layer Error - {e}\n{traceback.format_exc()}") + verbose_logger.exception("Azure Sentinel Audit Log Layer Error - %s\n%s", e, traceback.format_exc()) async def async_send_batch(self): """ @@ -323,7 +323,7 @@ class AzureSentinelLogger(CustomBatchLogger): ) except Exception as e: - verbose_logger.exception(f"Azure Sentinel Error sending batch API - {e}\n{traceback.format_exc()}") + verbose_logger.exception("Azure Sentinel Error sending batch API - %s\n%s", e, traceback.format_exc()) finally: log_queue.clear() diff --git a/litellm/integrations/azure_storage/azure_storage.py b/litellm/integrations/azure_storage/azure_storage.py index d2dd3d37dc7..142a0a56967 100644 --- a/litellm/integrations/azure_storage/azure_storage.py +++ b/litellm/integrations/azure_storage/azure_storage.py @@ -53,7 +53,9 @@ class AzureBlobStorageLogger(CustomBatchLogger): self.log_queue: list[StandardLoggingPayload] = [] super().__init__(**kwargs, flush_lock=self.flush_lock) except Exception as e: - verbose_logger.exception(f"AzureBlobStorageLogger: Got exception on init AzureBlobStorageLogger client {e}") + verbose_logger.exception( + "AzureBlobStorageLogger: Got exception on init AzureBlobStorageLogger client %s", e + ) raise e async def async_log_success_event(self, kwargs, response_obj, start_time, end_time): @@ -77,7 +79,7 @@ class AzureBlobStorageLogger(CustomBatchLogger): self.log_queue.append(standard_logging_payload) except Exception as e: - verbose_logger.exception(f"AzureBlobStorageLogger Layer Error - {e}") + verbose_logger.exception("AzureBlobStorageLogger Layer Error - %s", e) async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time): """ @@ -99,7 +101,7 @@ class AzureBlobStorageLogger(CustomBatchLogger): self.log_queue.append(standard_logging_payload) except Exception as e: - verbose_logger.exception(f"AzureBlobStorageLogger Layer Error - {e}") + verbose_logger.exception("AzureBlobStorageLogger Layer Error - %s", e) async def async_send_batch(self): """ @@ -122,7 +124,7 @@ class AzureBlobStorageLogger(CustomBatchLogger): await self.async_upload_payload_to_azure_blob_storage(payload=payload) except Exception as e: - verbose_logger.exception(f"AzureBlobStorageLogger Error sending batch API - {e}") + verbose_logger.exception("AzureBlobStorageLogger Error sending batch API - %s", e) async def async_upload_payload_to_azure_blob_storage(self, payload: StandardLoggingPayload): """ @@ -148,16 +150,16 @@ class AzureBlobStorageLogger(CustomBatchLogger): await self._append_data(async_client, base_url, json_payload) await self._flush_data(async_client, base_url, len(payload_bytes)) - verbose_logger.debug(f"Successfully uploaded log to Azure Blob Storage: {filename}") + verbose_logger.debug("Successfully uploaded log to Azure Blob Storage: %s", filename) except Exception as e: - verbose_logger.exception(f"Error uploading to Azure Blob Storage: {e}") + verbose_logger.exception("Error uploading to Azure Blob Storage: %s", e) raise e async def _create_file(self, client: AsyncHTTPHandler, base_url: str): """Helper method to create the file resource""" try: - verbose_logger.debug(f"Creating file resource at: {base_url}") + verbose_logger.debug("Creating file resource at: %s", base_url) headers = { "x-ms-version": AZURE_STORAGE_MSFT_VERSION, "Content-Length": "0", @@ -167,13 +169,13 @@ class AzureBlobStorageLogger(CustomBatchLogger): response.raise_for_status() verbose_logger.debug("Successfully created file resource") except Exception as e: - verbose_logger.exception(f"Error creating file resource: {e}") + verbose_logger.exception("Error creating file resource: %s", e) raise async def _append_data(self, client: AsyncHTTPHandler, base_url: str, json_payload: str): """Helper method to append data to the file""" try: - verbose_logger.debug(f"Appending data to file: {base_url}") + verbose_logger.debug("Appending data to file: %s", base_url) headers = { "x-ms-version": AZURE_STORAGE_MSFT_VERSION, "Content-Type": "application/json", @@ -187,13 +189,13 @@ class AzureBlobStorageLogger(CustomBatchLogger): response.raise_for_status() verbose_logger.debug("Successfully appended data") except Exception as e: - verbose_logger.exception(f"Error appending data: {e}") + verbose_logger.exception("Error appending data: %s", e) raise async def _flush_data(self, client: AsyncHTTPHandler, base_url: str, position: int): """Helper method to flush the data""" try: - verbose_logger.debug(f"Flushing data at position {position}") + verbose_logger.debug("Flushing data at position %s", position) headers = { "x-ms-version": AZURE_STORAGE_MSFT_VERSION, "Content-Length": "0", @@ -203,7 +205,7 @@ class AzureBlobStorageLogger(CustomBatchLogger): response.raise_for_status() verbose_logger.debug("Successfully flushed data") except Exception as e: - verbose_logger.exception(f"Error flushing data: {e}") + verbose_logger.exception("Error flushing data: %s", e) raise ####### Helper methods to managing Authentication to Azure Storage ####### @@ -227,7 +229,7 @@ class AzureBlobStorageLogger(CustomBatchLogger): ) # Token typically expires in 1 hour self.token_expiry = datetime.now() + timedelta(hours=1) - verbose_logger.debug(f"New token will expire at {self.token_expiry}") + verbose_logger.debug("New token will expire at %s", self.token_expiry) def get_azure_ad_token_from_azure_storage( self, @@ -322,7 +324,7 @@ class AzureBlobStorageLogger(CustomBatchLogger): # check if the directory exists if not await directory_client.exists(): await directory_client.create_directory() - verbose_logger.debug(f"Created directory: {today}") + verbose_logger.debug("Created directory: %s", today) # Create a file client file_name = f"{payload.get('id') or str(uuid.uuid4())}.json" @@ -340,7 +342,7 @@ class AzureBlobStorageLogger(CustomBatchLogger): # Flush the content to finalize the file await file_client.flush_data(position=len(content), offset=0) - verbose_logger.debug(f"Successfully uploaded and wrote to {today}/{file_name}") + verbose_logger.debug("Successfully uploaded and wrote to %s/%s", today, file_name) except Exception as e: - verbose_logger.exception(f"Error occurred: {e}") + verbose_logger.exception("Error occurred: %s", e) diff --git a/litellm/integrations/bitbucket/bitbucket_prompt_manager.py b/litellm/integrations/bitbucket/bitbucket_prompt_manager.py index c76466b2f40..3a61c900600 100644 --- a/litellm/integrations/bitbucket/bitbucket_prompt_manager.py +++ b/litellm/integrations/bitbucket/bitbucket_prompt_manager.py @@ -320,7 +320,7 @@ class BitBucketPromptManager(CustomPromptManagement): # Log error but don't fail the call import litellm - litellm._logging.verbose_proxy_logger.error(f"Error in BitBucket prompt pre_call_hook: {e}") + litellm._logging.verbose_proxy_logger.error("Error in BitBucket prompt pre_call_hook: %s", e) return messages, litellm_params def _parse_prompt_to_messages(self, prompt_content: str) -> list[AllMessageValues]: diff --git a/litellm/integrations/braintrust_mock_client.py b/litellm/integrations/braintrust_mock_client.py index e2b732d6e9c..c775a8f3ab8 100644 --- a/litellm/integrations/braintrust_mock_client.py +++ b/litellm/integrations/braintrust_mock_client.py @@ -89,7 +89,7 @@ def _mock_http_handler_post( """Monkey-patched HTTPHandler.post that intercepts Braintrust calls with endpoint-specific responses.""" # Only mock Braintrust API calls if isinstance(url, str) and _is_braintrust_url(url): - verbose_logger.info(f"[BRAINTRUST MOCK] POST to {url}") + verbose_logger.info("[BRAINTRUST MOCK] POST to %s", url) time.sleep(_MOCK_LATENCY_SECONDS) # Return appropriate mock response based on endpoint if "/project" in url: diff --git a/litellm/integrations/cloudzero/cloudzero.py b/litellm/integrations/cloudzero/cloudzero.py index 52b41f74fce..5cab952cfea 100644 --- a/litellm/integrations/cloudzero/cloudzero.py +++ b/litellm/integrations/cloudzero/cloudzero.py @@ -38,7 +38,7 @@ class CloudZeroLogger(CustomLogger): self.connection_id = connection_id or os.getenv("CLOUDZERO_CONNECTION_ID") self.timezone = timezone or os.getenv("CLOUDZERO_TIMEZONE", "UTC") verbose_logger.debug( - f"CloudZero Logger initialized with connection ID: {self.connection_id}, timezone: {self.timezone}" + "CloudZero Logger initialized with connection ID: %s, timezone: %s", self.connection_id, self.timezone ) async def initialize_cloudzero_export_job(self): @@ -130,7 +130,7 @@ class CloudZeroLogger(CustomLogger): verbose_logger.debug("CloudZero Logger: No usage data found to export") return - verbose_logger.debug(f"CloudZero Logger: Processing {len(data)} records") + verbose_logger.debug("CloudZero Logger: Processing %s records", len(data)) # Transform data to CloudZero CBF format transformer = CBFTransformer() @@ -147,13 +147,13 @@ class CloudZeroLogger(CustomLogger): user_timezone=self.timezone, ) - verbose_logger.debug(f"CloudZero Logger: Transmitting {len(cbf_data)} records to CloudZero") + verbose_logger.debug("CloudZero Logger: Transmitting %s records to CloudZero", len(cbf_data)) streamer.send_batched(cbf_data, operation=operation) - verbose_logger.debug(f"CloudZero Logger: Successfully exported {len(cbf_data)} records to CloudZero") + verbose_logger.debug("CloudZero Logger: Successfully exported %s records to CloudZero", len(cbf_data)) except Exception as e: - verbose_logger.error(f"CloudZero Logger: Error exporting usage data: {e}") + verbose_logger.error("CloudZero Logger: Error exporting usage data: %s", e) raise async def dry_run_export_usage_data(self, limit: int | None = 10000): @@ -191,7 +191,7 @@ class CloudZeroLogger(CustomLogger): }, } - verbose_logger.debug(f"CloudZero Dry Run: Processing {len(data)} records...") + verbose_logger.debug("CloudZero Dry Run: Processing %s records...", len(data)) # Convert usage data to dict format for response usage_data_sample = data.head(50).to_dicts() # Return first 50 rows @@ -229,7 +229,7 @@ class CloudZeroLogger(CustomLogger): ) total_tokens = sum(record.get("usage/amount", 0) for record in cbf_data_dict) - verbose_logger.debug(f"CloudZero Logger: Dry run completed for {len(cbf_data)} records") + verbose_logger.debug("CloudZero Logger: Dry run completed for %s records", len(cbf_data)) return { "usage_data": usage_data_sample, @@ -244,8 +244,8 @@ class CloudZeroLogger(CustomLogger): } except Exception as e: - verbose_logger.error(f"CloudZero Logger: Error in dry run export: {e}") - verbose_logger.error(f"CloudZero Dry Run Error: {e}") + verbose_logger.error("CloudZero Logger: Error in dry run export: %s", e) + verbose_logger.error("CloudZero Dry Run Error: %s", e) raise def _display_cbf_data_on_screen(self, cbf_data): diff --git a/litellm/integrations/custom_batch_logger.py b/litellm/integrations/custom_batch_logger.py index 98a8e4ba739..7559bc83cfa 100644 --- a/litellm/integrations/custom_batch_logger.py +++ b/litellm/integrations/custom_batch_logger.py @@ -47,7 +47,7 @@ class CustomBatchLogger(CustomLogger): async def periodic_flush(self): while True: await asyncio.sleep(self.flush_interval) - verbose_logger.debug(f"CustomLogger periodic flush after {self.flush_interval} seconds") + verbose_logger.debug("CustomLogger periodic flush after %s seconds", self.flush_interval) await self.flush_queue() async def flush_queue(self): diff --git a/litellm/integrations/custom_guardrail.py b/litellm/integrations/custom_guardrail.py index 743c539c36f..d9d65375ea8 100644 --- a/litellm/integrations/custom_guardrail.py +++ b/litellm/integrations/custom_guardrail.py @@ -864,7 +864,7 @@ class CustomGuardrail(CustomLogger): if premium_user is not True: verbose_logger.warning( - f"Trying to use premium guardrail without premium user {CommonProxyErrors.not_premium_user.value}" + "Trying to use premium guardrail without premium user %s", CommonProxyErrors.not_premium_user.value ) return False return True @@ -1028,7 +1028,7 @@ class CustomGuardrail(CustomLogger): else: guardrail_response = "allow" - verbose_logger.debug(f"Guardrail response: {response}") + verbose_logger.debug("Guardrail response: %s", response) self.add_standard_logging_guardrail_information_to_request_data( guardrail_json_response=guardrail_response, diff --git a/litellm/integrations/custom_logger.py b/litellm/integrations/custom_logger.py index 9915224ba09..9df0cf6e84d 100644 --- a/litellm/integrations/custom_logger.py +++ b/litellm/integrations/custom_logger.py @@ -915,19 +915,19 @@ class CustomLogger: # https://docs.litellm.ai/docs/observability/custom_callbac for callback_obj in all_callbacks: if hasattr(callback_obj, "increment_callback_logging_failure"): - verbose_logger.debug(f"Incrementing callback failure metric for {callback_name}") + verbose_logger.debug("Incrementing callback failure metric for %s", callback_name) callback_obj.increment_callback_logging_failure(callback_name=callback_name) # type: ignore return verbose_logger.debug( - f"No callback with increment_callback_logging_failure method found for {callback_name}. " - "Ensure 'prometheus' is in your callbacks config." + "No callback with increment_callback_logging_failure method found for %s. Ensure 'prometheus' is in your callbacks config.", + callback_name, ) except Exception as e: from litellm._logging import verbose_logger - verbose_logger.debug(f"Error in handle_callback_failure for {callback_name}: {e}") + verbose_logger.debug("Error in handle_callback_failure for %s: %s", callback_name, e) async def _strip_base64_from_messages( self, @@ -946,7 +946,7 @@ class CustomLogger: # https://docs.litellm.ai/docs/observability/custom_callbac """ raw_messages: Any = payload.get("messages", []) messages: list[Any] = raw_messages if isinstance(raw_messages, list) else [] - verbose_logger.debug(f"[CustomLogger] Stripping base64 from {len(messages)} messages") + verbose_logger.debug("[CustomLogger] Stripping base64 from %s messages", len(messages)) if messages: payload["messages"] = self._process_messages(messages=messages, max_depth=max_depth) @@ -958,7 +958,7 @@ class CustomLogger: # https://docs.litellm.ai/docs/observability/custom_callbac if isinstance(content, list): total_items += len(content) - verbose_logger.debug(f"[CustomLogger] Completed base64 strip; retained {total_items} content items") + verbose_logger.debug("[CustomLogger] Completed base64 strip; retained %s content items", total_items) return payload def _strip_base64_from_messages_sync( @@ -978,7 +978,7 @@ class CustomLogger: # https://docs.litellm.ai/docs/observability/custom_callbac """ raw_messages: Any = payload.get("messages", []) messages: list[Any] = raw_messages if isinstance(raw_messages, list) else [] - verbose_logger.debug(f"[CustomLogger] Stripping base64 from {len(messages)} messages") + verbose_logger.debug("[CustomLogger] Stripping base64 from %s messages", len(messages)) if messages: payload["messages"] = self._process_messages(messages=messages, max_depth=max_depth) @@ -990,7 +990,7 @@ class CustomLogger: # https://docs.litellm.ai/docs/observability/custom_callbac if isinstance(content, list): total_items += len(content) - verbose_logger.debug(f"[CustomLogger] Completed base64 strip; retained {total_items} content items") + verbose_logger.debug("[CustomLogger] Completed base64 strip; retained %s content items", total_items) return payload def _redact_base64( @@ -1001,12 +1001,12 @@ class CustomLogger: # https://docs.litellm.ai/docs/observability/custom_callbac ) -> Any: """Recursively redact inline base64 from any nested structure with a max recursion depth limit.""" if depth > max_depth: - verbose_logger.warning(f"[CustomLogger] Max recursion depth {max_depth} reached while redacting base64") + verbose_logger.warning("[CustomLogger] Max recursion depth %s reached while redacting base64", max_depth) return "[MAX_DEPTH_REACHED]" if isinstance(value, str): if _BASE64_INLINE_PATTERN.search(value): - verbose_logger.debug(f"[CustomLogger] Redacted inline base64 string: {value[:40]}...") + verbose_logger.debug("[CustomLogger] Redacted inline base64 string: %s...", value[:40]) return _BASE64_INLINE_PATTERN.sub("[BASE64_REDACTED]", value) return value diff --git a/litellm/integrations/custom_secret_manager.py b/litellm/integrations/custom_secret_manager.py index 8cb7f02b798..e59842d409a 100644 --- a/litellm/integrations/custom_secret_manager.py +++ b/litellm/integrations/custom_secret_manager.py @@ -237,7 +237,7 @@ class CustomSecretManager(BaseSecretManager): Returns: True if the secret manager is healthy, False otherwise """ - verbose_logger.debug(f"Health check not implemented for {self.secret_manager_name}") + verbose_logger.debug("Health check not implemented for %s", self.secret_manager_name) return True def __repr__(self) -> str: diff --git a/litellm/integrations/datadog/datadog.py b/litellm/integrations/datadog/datadog.py index fa14e1fa459..ce6dda96820 100644 --- a/litellm/integrations/datadog/datadog.py +++ b/litellm/integrations/datadog/datadog.py @@ -171,7 +171,7 @@ class DataDogLogger( batch_size=_resolve_dd_batch_size(), ) except Exception as e: - verbose_logger.exception(f"Datadog: Got exception on init Datadog client {e}") + verbose_logger.exception("Datadog: Got exception on init Datadog client %s", e) raise e def _get_datadog_params(self) -> dict: @@ -210,7 +210,7 @@ class DataDogLogger( self.DD_API_KEY = dd_api_key or ( os.getenv("DD_API_KEY") if allow_env_credentials else None ) # Optional when using agent - verbose_logger.debug(f"Datadog: Using DD Agent at {self.intake_url}") + verbose_logger.debug("Datadog: Using DD Agent at %s", self.intake_url) def _configure_dd_direct_api( self, @@ -257,7 +257,7 @@ class DataDogLogger( await self._log_async_event(kwargs, response_obj, start_time, end_time) except Exception as e: - verbose_logger.exception(f"Datadog Layer Error - {e}\n{traceback.format_exc()}") + verbose_logger.exception("Datadog Layer Error - %s\n%s", e, traceback.format_exc()) async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time): try: @@ -265,7 +265,7 @@ class DataDogLogger( await self._log_async_event(kwargs, response_obj, start_time, end_time) except Exception as e: - verbose_logger.exception(f"Datadog Layer Error - {e}\n{traceback.format_exc()}") + verbose_logger.exception("Datadog Layer Error - %s\n%s", e, traceback.format_exc()) async def async_post_call_failure_hook( self, @@ -340,7 +340,7 @@ class DataDogLogger( if len(self.log_queue) >= self.batch_size: await self.flush_queue() except Exception as e: - verbose_logger.exception(f"Datadog: async_post_call_failure_hook - {e}\n{traceback.format_exc()}") + verbose_logger.exception("Datadog: async_post_call_failure_hook - %s\n%s", e, traceback.format_exc()) return None async def async_send_batch(self): @@ -376,11 +376,11 @@ class DataDogLogger( self.log_queue = undelivered + self.log_queue if self.is_mock_mode: - verbose_logger.debug(f"[DATADOG MOCK] Batch of {len(batch_to_send)} events successfully mocked") + verbose_logger.debug("[DATADOG MOCK] Batch of %s events successfully mocked", len(batch_to_send)) except Exception as e: self.log_queue = batch_to_send + self.log_queue - verbose_logger.exception(f"Datadog Error sending batch API - {e}\n{traceback.format_exc()}") + verbose_logger.exception("Datadog Error sending batch API - %s\n%s", e, traceback.format_exc()) async def _send_with_413_split(self, batch: list) -> list: """ @@ -411,7 +411,7 @@ class DataDogLogger( if isinstance(e, MaskedHTTPStatusError) and e.status_code == 413: response = e.response else: - verbose_logger.exception(f"Datadog Error sending batch API - {e}") + verbose_logger.exception("Datadog Error sending batch API - %s", e) return self._undelivered(chunk, pending) if response.status_code == 413: @@ -515,7 +515,7 @@ class DataDogLogger( ) except Exception as e: - verbose_logger.exception(f"Datadog Layer Error - {e}\n{traceback.format_exc()}") + verbose_logger.exception("Datadog Layer Error - %s\n%s", e, traceback.format_exc()) async def _log_async_event(self, kwargs, response_obj, start_time, end_time): dd_payload = self.create_datadog_logging_payload( @@ -526,7 +526,7 @@ class DataDogLogger( ) self.log_queue.append(dd_payload) - verbose_logger.debug(f"Datadog, event added to queue. Will flush in {self.flush_interval} seconds...") + verbose_logger.debug("Datadog, event added to queue. Will flush in %s seconds...", self.flush_interval) if len(self.log_queue) >= self.batch_size: await self.flush_queue() @@ -653,7 +653,7 @@ class DataDogLogger( self.log_queue.append(_dd_payload) except Exception as e: - verbose_logger.exception(f"Datadog: Logger - Exception in async_service_failure_hook: {e}") + verbose_logger.exception("Datadog: Logger - Exception in async_service_failure_hook: %s", e) async def async_service_success_hook( self, @@ -692,7 +692,7 @@ class DataDogLogger( self.log_queue.append(_dd_payload) except Exception as e: - verbose_logger.exception(f"Datadog: Logger - Exception in async_service_failure_hook: {e}") + verbose_logger.exception("Datadog: Logger - Exception in async_service_failure_hook: %s", e) def _create_v0_logging_payload( self, diff --git a/litellm/integrations/datadog/datadog_cost_management.py b/litellm/integrations/datadog/datadog_cost_management.py index da45f94f02b..21a289877c2 100644 --- a/litellm/integrations/datadog/datadog_cost_management.py +++ b/litellm/integrations/datadog/datadog_cost_management.py @@ -84,7 +84,7 @@ class DatadogCostManagementLogger(CustomBatchLogger): await self.async_send_batch() except Exception as e: - verbose_logger.exception(f"Datadog Cost Management: Error in async_log_success_event: {e}") + verbose_logger.exception("Datadog Cost Management: Error in async_log_success_event: %s", e) async def async_send_batch(self): if not self.log_queue: @@ -104,7 +104,7 @@ class DatadogCostManagementLogger(CustomBatchLogger): await self._upload_to_datadog(aggregated_entries) except Exception as e: self.log_queue = batch_to_send + self.log_queue - verbose_logger.exception(f"Datadog Cost Management: Error in async_send_batch: {e}") + verbose_logger.exception("Datadog Cost Management: Error in async_send_batch: %s", e) def _aggregate_costs(self, logs: list[StandardLoggingPayload]) -> list[DatadogFOCUSCostEntry]: """ @@ -159,7 +159,7 @@ class DatadogCostManagementLogger(CustomBatchLogger): aggregator[key]["BilledCost"] += cost except Exception as e: - verbose_logger.warning(f"Error processing log for cost aggregation: {e}") + verbose_logger.warning("Error processing log for cost aggregation: %s", e) continue return list(aggregator.values()) @@ -254,5 +254,5 @@ class DatadogCostManagementLogger(CustomBatchLogger): response.raise_for_status() verbose_logger.debug( - f"Datadog Cost Management: Uploaded {len(payload)} cost entries. Status: {response.status_code}" + "Datadog Cost Management: Uploaded %s cost entries. Status: %s", len(payload), response.status_code ) diff --git a/litellm/integrations/datadog/datadog_llm_obs.py b/litellm/integrations/datadog/datadog_llm_obs.py index 02e1affd361..8d7ed415315 100644 --- a/litellm/integrations/datadog/datadog_llm_obs.py +++ b/litellm/integrations/datadog/datadog_llm_obs.py @@ -89,7 +89,7 @@ class DataDogLLMObsLogger(CustomBatchLogger): kwargs.update(dict_datadog_llm_obs_params) CustomBatchLogger.__init__(self, **kwargs, flush_lock=self.flush_lock) except Exception as e: - verbose_logger.exception(f"DataDogLLMObs: Error initializing - {e}") + verbose_logger.exception("DataDogLLMObs: Error initializing - %s", e) raise e def _configure_dd_agent(self, dd_agent_host: str): @@ -103,7 +103,7 @@ class DataDogLLMObsLogger(CustomBatchLogger): agent_port = os.getenv("LITELLM_DD_LLM_OBS_PORT", "8126") self.DD_SITE = "localhost" # Not used for URL construction in agent mode self.intake_url = f"http://{dd_agent_host}:{agent_port}/api/intake/llm-obs/v1/trace/spans" - verbose_logger.debug(f"DataDogLLMObs: Using DD Agent at {self.intake_url}") + verbose_logger.debug("DataDogLLMObs: Using DD Agent at %s", self.intake_url) def _configure_dd_direct_api(self): """ @@ -137,34 +137,34 @@ class DataDogLLMObsLogger(CustomBatchLogger): async def async_log_success_event(self, kwargs, response_obj, start_time, end_time): try: - verbose_logger.debug(f"DataDogLLMObs: Logging success event for model {kwargs.get('model', 'unknown')}") + verbose_logger.debug("DataDogLLMObs: Logging success event for model %s", kwargs.get("model", "unknown")) payload = self.create_llm_obs_payload(kwargs, start_time, end_time) - verbose_logger.debug(f"DataDogLLMObs: Payload: {payload}") + verbose_logger.debug("DataDogLLMObs: Payload: %s", payload) self.log_queue.append(payload) if len(self.log_queue) >= self.batch_size: await self.async_send_batch() except Exception as e: - verbose_logger.exception(f"DataDogLLMObs: Error logging success event - {e}") + verbose_logger.exception("DataDogLLMObs: Error logging success event - %s", e) async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time): try: - verbose_logger.debug(f"DataDogLLMObs: Logging failure event for model {kwargs.get('model', 'unknown')}") + verbose_logger.debug("DataDogLLMObs: Logging failure event for model %s", kwargs.get("model", "unknown")) payload = self.create_llm_obs_payload(kwargs, start_time, end_time) - verbose_logger.debug(f"DataDogLLMObs: Payload: {payload}") + verbose_logger.debug("DataDogLLMObs: Payload: %s", payload) self.log_queue.append(payload) if len(self.log_queue) >= self.batch_size: await self.async_send_batch() except Exception as e: - verbose_logger.exception(f"DataDogLLMObs: Error logging failure event - {e}") + verbose_logger.exception("DataDogLLMObs: Error logging failure event - %s", e) async def async_send_batch(self): try: if not self.log_queue: return - verbose_logger.debug(f"DataDogLLMObs: Flushing {len(self.log_queue)} events") + verbose_logger.debug("DataDogLLMObs: Flushing %s events", len(self.log_queue)) if self.is_mock_mode: verbose_logger.debug("[DATADOG MOCK] Mock mode enabled - API calls will be intercepted") @@ -207,14 +207,14 @@ class DataDogLLMObsLogger(CustomBatchLogger): ) if self.is_mock_mode: - verbose_logger.debug(f"[DATADOG MOCK] Batch of {len(self.log_queue)} events successfully mocked") + verbose_logger.debug("[DATADOG MOCK] Batch of %s events successfully mocked", len(self.log_queue)) else: - verbose_logger.debug(f"DataDogLLMObs: Successfully sent batch - status_code: {response.status_code}") + verbose_logger.debug("DataDogLLMObs: Successfully sent batch - status_code: %s", response.status_code) self.log_queue.clear() except httpx.HTTPStatusError as e: - verbose_logger.exception(f"DataDogLLMObs: Error sending batch - {e.response.text}") + verbose_logger.exception("DataDogLLMObs: Error sending batch - %s", e.response.text) except Exception as e: - verbose_logger.exception(f"DataDogLLMObs: Error sending batch - {e}") + verbose_logger.exception("DataDogLLMObs: Error sending batch - %s", e) def create_llm_obs_payload(self, kwargs: dict, start_time: datetime, end_time: datetime) -> LLMObsPayload: standard_logging_payload: StandardLoggingPayload | None = kwargs.get("standard_logging_object") @@ -613,7 +613,7 @@ class DataDogLLMObsLogger(CustomBatchLogger): try: spend_metrics["user_api_key_spend"] = float(user_api_key_spend) except (ValueError, TypeError): - verbose_logger.debug(f"Invalid user_api_key_spend value: {user_api_key_spend}") + verbose_logger.debug("Invalid user_api_key_spend value: %s", user_api_key_spend) # API key budget reset datetime user_api_key_budget_reset_at = metadata.get("user_api_key_budget_reset_at") @@ -640,10 +640,10 @@ class DataDogLLMObsLogger(CustomBatchLogger): spend_metrics["user_api_key_budget_reset_at"] = iso_string # Debug logging to verify the conversion - verbose_logger.debug(f"Converted budget_reset_at to ISO format: {iso_string}") + verbose_logger.debug("Converted budget_reset_at to ISO format: %s", iso_string) except Exception as e: - verbose_logger.debug(f"Error processing budget reset datetime: {e}") - verbose_logger.debug(f"Original value: {user_api_key_budget_reset_at}") + verbose_logger.debug("Error processing budget reset datetime: %s", e) + verbose_logger.debug("Original value: %s", user_api_key_budget_reset_at) return spend_metrics @@ -707,7 +707,7 @@ class DataDogLLMObsLogger(CustomBatchLogger): kv_pairs[f"tool_calls.{idx}.function.arguments"] = json.dumps(function_arguments) except (KeyError, TypeError, ValueError) as e: - verbose_logger.debug(f"DataDogLLMObs: Error processing tool call {idx}: {e}") + verbose_logger.debug("DataDogLLMObs: Error processing tool call %s: %s", idx, e) continue return kv_pairs @@ -747,6 +747,6 @@ class DataDogLLMObsLogger(CustomBatchLogger): tool_call_metadata[f"output_{key}"] = value except Exception as e: - verbose_logger.debug(f"DataDogLLMObs: Error extracting tool call metadata: {e}") + verbose_logger.debug("DataDogLLMObs: Error extracting tool call metadata: %s", e) return tool_call_metadata diff --git a/litellm/integrations/datadog/datadog_metrics.py b/litellm/integrations/datadog/datadog_metrics.py index 9fb86bfb125..c33c44e4249 100644 --- a/litellm/integrations/datadog/datadog_metrics.py +++ b/litellm/integrations/datadog/datadog_metrics.py @@ -180,7 +180,7 @@ class DatadogMetricsLogger(CustomBatchLogger): await self.flush_queue() except Exception as e: - verbose_logger.exception(f"Datadog Metrics: Error in async_log_success_event: {e}") + verbose_logger.exception("Datadog Metrics: Error in async_log_success_event: %s", e) async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time): try: @@ -202,7 +202,7 @@ class DatadogMetricsLogger(CustomBatchLogger): await self.flush_queue() except Exception as e: - verbose_logger.exception(f"Datadog Metrics: Error in async_log_failure_event: {e}") + verbose_logger.exception("Datadog Metrics: Error in async_log_failure_event: %s", e) async def async_send_batch(self): if not self.log_queue: @@ -214,7 +214,7 @@ class DatadogMetricsLogger(CustomBatchLogger): try: await self._upload_to_datadog(payload_data) except Exception as e: - verbose_logger.exception(f"Datadog Metrics: Error in async_send_batch: {e}") + verbose_logger.exception("Datadog Metrics: Error in async_send_batch: %s", e) raise async def _upload_to_datadog(self, payload: DatadogMetricsPayload): @@ -242,7 +242,7 @@ class DatadogMetricsLogger(CustomBatchLogger): response.raise_for_status() verbose_logger.debug( - f"Datadog Metrics: Uploaded {len(payload['series'])} metric points. Status: {response.status_code}" + "Datadog Metrics: Uploaded %s metric points. Status: %s", len(payload["series"]), response.status_code ) async def async_health_check(self) -> IntegrationHealthCheckStatus: diff --git a/litellm/integrations/deepeval/api.py b/litellm/integrations/deepeval/api.py index adca8928df4..512c74e035c 100644 --- a/litellm/integrations/deepeval/api.py +++ b/litellm/integrations/deepeval/api.py @@ -23,9 +23,9 @@ def log_retry_error(details): exception = details.get("exception") tries = details.get("tries") if exception: - logging.error(f"Confident AI Error: {exception}. Retrying: {tries} time(s)...") + logging.error("Confident AI Error: %s. Retrying: %s time(s)...", exception, tries) else: - logging.error(f"Retrying: {tries} time(s)...") + logging.error("Retrying: %s time(s)...", tries) class HttpMethods(Enum): diff --git a/litellm/integrations/gcs_bucket/gcs_bucket.py b/litellm/integrations/gcs_bucket/gcs_bucket.py index b5b3d4e81a3..e402e4962b7 100644 --- a/litellm/integrations/gcs_bucket/gcs_bucket.py +++ b/litellm/integrations/gcs_bucket/gcs_bucket.py @@ -76,7 +76,7 @@ class GCSBucketLogger(GCSBucketBase, AdditionalLoggingUtils): await self.log_queue.put(GCSLogQueueItem(payload=logging_payload, kwargs=kwargs, response_obj=response_obj)) except Exception as e: - verbose_logger.exception(f"GCS Bucket logging error: {e}") + verbose_logger.exception("GCS Bucket logging error: %s", e) async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time): try: @@ -95,7 +95,7 @@ class GCSBucketLogger(GCSBucketBase, AdditionalLoggingUtils): await self.log_queue.put(GCSLogQueueItem(payload=logging_payload, kwargs=kwargs, response_obj=response_obj)) except Exception as e: - verbose_logger.exception(f"GCS Bucket logging error: {e}") + verbose_logger.exception("GCS Bucket logging error: %s", e) def _drain_queue_batch(self) -> list[GCSLogQueueItem]: """ @@ -218,7 +218,7 @@ class GCSBucketLogger(GCSBucketBase, AdditionalLoggingUtils): except Exception as e: success_count = 0 error_count = len(items) - verbose_logger.exception(f"GCS Bucket error logging batch payload to GCS bucket: {e}") + verbose_logger.exception("GCS Bucket error logging batch payload to GCS bucket: %s", e) return (success_count, error_count) async def _send_individual_logs(self, items: list[GCSLogQueueItem]) -> None: @@ -255,7 +255,7 @@ class GCSBucketLogger(GCSBucketBase, AdditionalLoggingUtils): logging_payload=item["payload"], ) except Exception as e: - verbose_logger.exception(f"GCS Bucket error logging individual payload to GCS bucket: {e}") + verbose_logger.exception("GCS Bucket error logging individual payload to GCS bucket: %s", e) async def async_send_batch(self): """ @@ -336,7 +336,7 @@ class GCSBucketLogger(GCSBucketBase, AdditionalLoggingUtils): loaded_response = json.loads(response) return loaded_response except Exception as e: - verbose_logger.debug(f"Failed to fetch payload for date {date_str}: {e}") + verbose_logger.debug("Failed to fetch payload for date %s: %s", date_str, e) continue return None @@ -370,7 +370,7 @@ class GCSBucketLogger(GCSBucketBase, AdditionalLoggingUtils): """ while True: await asyncio.sleep(self.flush_interval) - verbose_logger.debug(f"GCS Bucket periodic flush after {self.flush_interval} seconds") + verbose_logger.debug("GCS Bucket periodic flush after %s seconds", self.flush_interval) await self.flush_queue() async def async_health_check(self) -> IntegrationHealthCheckStatus: diff --git a/litellm/integrations/gcs_bucket/gcs_bucket_mock_client.py b/litellm/integrations/gcs_bucket/gcs_bucket_mock_client.py index 86cf8617dd5..20e89c0647b 100644 --- a/litellm/integrations/gcs_bucket/gcs_bucket_mock_client.py +++ b/litellm/integrations/gcs_bucket/gcs_bucket_mock_client.py @@ -45,7 +45,7 @@ async def _mock_async_handler_get(self, url, params=None, headers=None, follow_r """Monkey-patched AsyncHTTPHandler.get that intercepts GCS calls.""" # Only mock GCS API calls if isinstance(url, str) and "storage.googleapis.com" in url: - verbose_logger.info(f"[GCS MOCK] GET to {url}") + verbose_logger.info("[GCS MOCK] GET to %s", url) await asyncio.sleep(_MOCK_LATENCY_SECONDS) # Return a minimal but valid StandardLoggingPayload JSON string as bytes # This matches what GCS returns when downloading with ?alt=media @@ -117,7 +117,7 @@ async def _mock_async_handler_delete( """Monkey-patched AsyncHTTPHandler.delete that intercepts GCS calls.""" # Only mock GCS API calls if isinstance(url, str) and "storage.googleapis.com" in url: - verbose_logger.info(f"[GCS MOCK] DELETE to {url}") + verbose_logger.info("[GCS MOCK] DELETE to %s", url) await asyncio.sleep(_MOCK_LATENCY_SECONDS) # DELETE returns 204 No Content with empty body (not JSON) return MockResponse( diff --git a/litellm/integrations/gcs_pubsub/pub_sub.py b/litellm/integrations/gcs_pubsub/pub_sub.py index b43e7626b77..d915c7341df 100644 --- a/litellm/integrations/gcs_pubsub/pub_sub.py +++ b/litellm/integrations/gcs_pubsub/pub_sub.py @@ -132,7 +132,7 @@ class GcsPubSubLogger(CustomBatchLogger): await self.async_send_batch() except Exception as e: - verbose_logger.exception(f"PubSub Layer Error - {e}\n{traceback.format_exc()}") + verbose_logger.exception("PubSub Layer Error - %s\n%s", e, traceback.format_exc()) async def async_send_batch(self): """ @@ -142,13 +142,13 @@ class GcsPubSubLogger(CustomBatchLogger): if not self.log_queue: return - verbose_logger.debug(f"PubSub - about to flush {len(self.log_queue)} events") + verbose_logger.debug("PubSub - about to flush %s events", len(self.log_queue)) for message in self.log_queue: await self.publish_message(message) except Exception as e: - verbose_logger.exception(f"PubSub Error sending batch - {e}\n{traceback.format_exc()}") + verbose_logger.exception("PubSub Error sending batch - %s\n%s", e, traceback.format_exc()) finally: self.log_queue.clear() diff --git a/litellm/integrations/generic_api/generic_api_callback.py b/litellm/integrations/generic_api/generic_api_callback.py index c7f2661a5ad..3e02826ee5d 100644 --- a/litellm/integrations/generic_api/generic_api_callback.py +++ b/litellm/integrations/generic_api/generic_api_callback.py @@ -42,7 +42,7 @@ def load_compatible_callbacks() -> dict: with open(json_path, "r") as f: return json.load(f) except Exception as e: - verbose_logger.warning(f"Error loading generic_api_compatible_callbacks.json: {e}") + verbose_logger.warning("Error loading generic_api_compatible_callbacks.json: %s", e) return {} @@ -124,7 +124,7 @@ class GenericAPILogger(CustomBatchLogger): ######################################################### if callback_name: if is_callback_compatible(callback_name): - verbose_logger.debug(f"Loading configuration for callback: {callback_name}") + verbose_logger.debug("Loading configuration for callback: %s", callback_name) callback_config = get_callback_config(callback_name) # Use config from JSON if not explicitly provided @@ -145,7 +145,7 @@ class GenericAPILogger(CustomBatchLogger): log_format = callback_config["log_format"] else: verbose_logger.warning( - f"callback_name '{callback_name}' not found in generic_api_compatible_callbacks.json" + "callback_name '%s' not found in generic_api_compatible_callbacks.json", callback_name ) ######################################################### @@ -177,7 +177,12 @@ class GenericAPILogger(CustomBatchLogger): self.log_format: LOG_FORMAT_TYPES = log_format or "json_array" verbose_logger.debug( - f"in init GenericAPILogger, callback_name: {self.callback_name}, endpoint {self.endpoint}, headers {self.headers}, event_types: {self.event_types}, log_format: {self.log_format}" + "in init GenericAPILogger, callback_name: %s, endpoint %s, headers %s, event_types: %s, log_format: %s", + self.callback_name, + self.endpoint, + self.headers, + self.event_types, + self.log_format, ) ######################################################### @@ -214,7 +219,7 @@ class GenericAPILogger(CustomBatchLogger): key, value = item.split("=", 1) headers_dict[key.strip()] = value.strip() except Exception as e: - verbose_logger.warning(f"Error parsing headers from environment variables: {e}") + verbose_logger.warning("Error parsing headers from environment variables: %s", e) # 2. Update with litellm generic headers if available if litellm.generic_logger_headers: @@ -308,7 +313,7 @@ class GenericAPILogger(CustomBatchLogger): await self.async_send_batch() except Exception as e: - verbose_logger.exception(f"Generic API Logger Error - {e}\n{traceback.format_exc()}") + verbose_logger.exception("Generic API Logger Error - %s\n%s", e, traceback.format_exc()) async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time): """ @@ -339,7 +344,7 @@ class GenericAPILogger(CustomBatchLogger): await self.async_send_batch() except Exception as e: - verbose_logger.exception(f"Generic API Logger Error - {e}\n{traceback.format_exc()}") + verbose_logger.exception("Generic API Logger Error - %s\n%s", e, traceback.format_exc()) async def async_send_batch(self): """ @@ -355,7 +360,7 @@ class GenericAPILogger(CustomBatchLogger): return verbose_logger.debug( - f"Generic API Logger - about to flush {len(self.log_queue)} events in '{self.log_format}' format" + "Generic API Logger - about to flush %s events in '%s' format", len(self.log_queue), self.log_format ) if self.log_format == "single": @@ -371,11 +376,13 @@ class GenericAPILogger(CustomBatchLogger): # Log results for idx, result in enumerate(responses): if isinstance(result, Exception): - verbose_logger.exception(f"Generic API Logger - Error sending log {idx}: {result}") + verbose_logger.exception("Generic API Logger - Error sending log %s: %s", idx, result) else: # result is a Response object verbose_logger.debug( - f"Generic API Logger - sent log {idx}, status: {result.status_code}" # type: ignore + "Generic API Logger - sent log %s, status: %s", + idx, + result.status_code, # type: ignore ) else: # Format the payload based on log_format @@ -390,12 +397,14 @@ class GenericAPILogger(CustomBatchLogger): response = await self._post_with_retries(data=data) verbose_logger.debug( - f"Generic API Logger - sent batch to {self.endpoint}, " - f"status: {response.status_code}, format: {self.log_format}" + "Generic API Logger - sent batch to %s, status: %s, format: %s", + self.endpoint, + response.status_code, + self.log_format, ) except Exception as e: - verbose_logger.exception(f"Generic API Logger Error sending batch - {e}\n{traceback.format_exc()}") + verbose_logger.exception("Generic API Logger Error sending batch - %s\n%s", e, traceback.format_exc()) finally: self.log_queue.clear() @@ -405,7 +414,7 @@ class GenericAPILogger(CustomBatchLogger): Returns a dict of the payload to send to the Generic API Endpoint """ - verbose_logger.debug(f"GenericAPILogger Logging - Enters logging function for model {kwargs}") + verbose_logger.debug("GenericAPILogger Logging - Enters logging function for model %s", kwargs) # construct payload to send custom logger # follows the same params as langfuse.py diff --git a/litellm/integrations/gitlab/gitlab_prompt_manager.py b/litellm/integrations/gitlab/gitlab_prompt_manager.py index 54e0a3ad02e..9fda4ebcc19 100644 --- a/litellm/integrations/gitlab/gitlab_prompt_manager.py +++ b/litellm/integrations/gitlab/gitlab_prompt_manager.py @@ -379,7 +379,7 @@ class GitLabPromptManager(CustomPromptManagement): except Exception as e: import litellm - litellm._logging.verbose_proxy_logger.error(f"Error in GitLab prompt pre_call_hook: {e}") + litellm._logging.verbose_proxy_logger.error("Error in GitLab prompt pre_call_hook: %s", e) return messages, litellm_params def _parse_prompt_to_messages(self, prompt_content: str) -> list[AllMessageValues]: diff --git a/litellm/integrations/lago.py b/litellm/integrations/lago.py index 3186f1bf58b..000d3e2c79a 100644 --- a/litellm/integrations/lago.py +++ b/litellm/integrations/lago.py @@ -117,7 +117,7 @@ class LagoLogger(CustomLogger): } } - verbose_logger.debug(f"\033[91mLogged Lago Object:\n{returned_val}\033[0m\n") + verbose_logger.debug("\x1b[91mLogged Lago Object:\n%s\x1b[0m\n", returned_val) return returned_val def log_success_event(self, kwargs, response_obj, start_time, end_time): @@ -149,7 +149,7 @@ class LagoLogger(CustomLogger): except Exception as e: error_response = getattr(e, "response", None) if error_response is not None and hasattr(error_response, "text"): - verbose_logger.debug(f"\nError Message: {error_response.text}") + verbose_logger.debug("\nError Message: %s", error_response.text) raise e async def async_log_success_event(self, kwargs, response_obj, start_time, end_time): @@ -184,8 +184,8 @@ class LagoLogger(CustomLogger): response.raise_for_status() - verbose_logger.debug(f"Logged Lago Object: {response.text}") + verbose_logger.debug("Logged Lago Object: %s", response.text) except Exception as e: if response is not None and hasattr(response, "text"): - verbose_logger.debug(f"\nError Message: {response.text}") + verbose_logger.debug("\nError Message: %s", response.text) raise e diff --git a/litellm/integrations/langfuse/langfuse.py b/litellm/integrations/langfuse/langfuse.py index 2dab1874c01..d10c7a699f5 100644 --- a/litellm/integrations/langfuse/langfuse.py +++ b/litellm/integrations/langfuse/langfuse.py @@ -199,7 +199,7 @@ class LangFuseLogger: ) langfuse_client = Langfuse(**parameters) litellm.initialized_langfuse_clients += 1 - verbose_logger.debug(f"Created langfuse client number {litellm.initialized_langfuse_clients}") + verbose_logger.debug("Created langfuse client number %s", litellm.initialized_langfuse_clients) return langfuse_client @staticmethod @@ -226,9 +226,9 @@ class LangFuseLogger: if metadata_param_key.startswith("langfuse_"): trace_param_key = metadata_param_key.replace("langfuse_", "", 1) if trace_param_key in metadata: - verbose_logger.warning(f"Overwriting Langfuse `{trace_param_key}` from request header") + verbose_logger.warning("Overwriting Langfuse `%s` from request header", trace_param_key) else: - verbose_logger.debug(f"Found Langfuse `{trace_param_key}` in request header") + verbose_logger.debug("Found Langfuse `%s` in request header", trace_param_key) metadata[trace_param_key] = proxy_headers.get(metadata_param_key) return metadata @@ -256,7 +256,7 @@ class LangFuseLogger: Logs a success or error event on Langfuse """ try: - verbose_logger.debug(f"Langfuse Logging - Enters logging function for model {kwargs}") + verbose_logger.debug("Langfuse Logging - Enters logging function for model %s", kwargs) # set default values for input/output for langfuse logging input = None @@ -295,7 +295,7 @@ class LangFuseLogger: level=level, status_message=status_message, ) - verbose_logger.debug(f"OUTPUT IN LANGFUSE: {output}; original: {response_obj}") + verbose_logger.debug("OUTPUT IN LANGFUSE: %s; original: %s", output, response_obj) trace_id = None generation_id = None if self._is_langfuse_v2(): @@ -325,12 +325,12 @@ class LangFuseLogger: input=input, response_obj=response_obj, ) - verbose_logger.debug(f"Langfuse Layer Logging - final response object: {response_obj}") + verbose_logger.debug("Langfuse Layer Logging - final response object: %s", response_obj) verbose_logger.info("Langfuse Layer Logging - logging success") return {"trace_id": trace_id, "generation_id": generation_id} except Exception as e: - verbose_logger.exception(f"Langfuse Layer Error(): Exception occured - {e}") + verbose_logger.exception("Langfuse Layer Error(): Exception occured - %s", e) return {"trace_id": None, "generation_id": None} def _get_langfuse_input_output_content( @@ -625,7 +625,7 @@ class LangFuseLogger: trace_params["metadata"] = {"metadata_passed_to_litellm": metadata} cost = kwargs.get("response_cost", None) - verbose_logger.debug(f"trace: {cost}") + verbose_logger.debug("trace: %s", cost) clean_metadata["litellm_response_cost"] = cost if standard_logging_object is not None: @@ -780,12 +780,13 @@ class LangFuseLogger: if hasattr(generation_client, "trace_id") and generation_client.trace_id: if generation_client.trace_id != trace_id: verbose_logger.warning( - f"Langfuse trace_id mismatch: set {trace_id}, but langfuse returned {generation_client.trace_id}. " - "Using our intended trace_id for consistency." + "Langfuse trace_id mismatch: set %s, but langfuse returned %s. Using our intended trace_id for consistency.", + trace_id, + generation_client.trace_id, ) return trace_id, generation_id except Exception: - verbose_logger.error(f"Langfuse Layer Error - {traceback.format_exc()}") + verbose_logger.error("Langfuse Layer Error - %s", traceback.format_exc()) return None, None @staticmethod @@ -902,7 +903,7 @@ class LangFuseLogger: # For other types, try to apply the function directly return masking_function(data) except Exception as e: - verbose_logger.warning(f"Failed to apply masking function: {e}. Returning original data.") + verbose_logger.warning("Failed to apply masking function: %s. Returning original data.", e) return data @staticmethod @@ -966,7 +967,7 @@ class LangFuseLogger: end_time=guardrail_entry.get("end_time", None), # type: ignore ) - verbose_logger.debug(f"Logged guardrail information as span: {span}") + verbose_logger.debug("Logged guardrail information as span: %s", span) span.end() @@ -1035,7 +1036,7 @@ def _add_prompt_to_generation_params( try: generation_params["prompt"] = langfuse_client.get_prompt(prompt_management_metadata["prompt_id"]) except Exception as e: - verbose_logger.debug(f"[Non-blocking] Langfuse Logger: Error getting prompt client for logging: {e}") + verbose_logger.debug("[Non-blocking] Langfuse Logger: Error getting prompt client for logging: %s", e) else: generation_params["prompt"] = user_prompt diff --git a/litellm/integrations/langfuse/langfuse_otel.py b/litellm/integrations/langfuse/langfuse_otel.py index 143362f3468..d7e9460a580 100644 --- a/litellm/integrations/langfuse/langfuse_otel.py +++ b/litellm/integrations/langfuse/langfuse_otel.py @@ -315,10 +315,10 @@ class LangfuseOtelLogger(OpenTelemetry): if langfuse_host: normalized_host = langfuse_host if langfuse_host.startswith("http") else f"https://{langfuse_host}" endpoint = f"{normalized_host.rstrip('/')}/api/public/otel" - verbose_logger.debug(f"Using Langfuse OTEL endpoint from host: {endpoint}") + verbose_logger.debug("Using Langfuse OTEL endpoint from host: %s", endpoint) else: endpoint = LANGFUSE_CLOUD_US_ENDPOINT - verbose_logger.debug(f"Using Langfuse US cloud endpoint: {endpoint}") + verbose_logger.debug("Using Langfuse US cloud endpoint: %s", endpoint) auth_header = LangfuseOtelLogger._get_langfuse_authorization_header( public_key=public_key, secret_key=secret_key diff --git a/litellm/integrations/langfuse/langfuse_prompt_management.py b/litellm/integrations/langfuse/langfuse_prompt_management.py index 56383b45a8c..f7fc63c0866 100644 --- a/litellm/integrations/langfuse/langfuse_prompt_management.py +++ b/litellm/integrations/langfuse/langfuse_prompt_management.py @@ -317,7 +317,7 @@ class LangfusePromptManagement(LangFuseLogger, PromptManagementBase, CustomLogge except Exception as e: from litellm._logging import verbose_logger - verbose_logger.exception(f"Langfuse Layer Error - Exception occurred while logging success event: {e}") + verbose_logger.exception("Langfuse Layer Error - Exception occurred while logging success event: %s", e) self.handle_callback_failure(callback_name="langfuse") async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time): @@ -347,5 +347,5 @@ class LangfusePromptManagement(LangFuseLogger, PromptManagementBase, CustomLogge except Exception as e: from litellm._logging import verbose_logger - verbose_logger.exception(f"Langfuse Layer Error - Exception occurred while logging failure event: {e}") + verbose_logger.exception("Langfuse Layer Error - Exception occurred while logging failure event: %s", e) self.handle_callback_failure(callback_name="langfuse") diff --git a/litellm/integrations/langsmith.py b/litellm/integrations/langsmith.py index 1f5d3179fb3..6dd0863cc41 100644 --- a/litellm/integrations/langsmith.py +++ b/litellm/integrations/langsmith.py @@ -194,7 +194,7 @@ class LangsmithLogger(CustomBatchLogger): fields = self._extract_metadata_fields(metadata, credentials) verbose_logger.debug( - f"Langsmith Logging - project_name: {fields['project_name']}, run_name {fields['run_name']}" + "Langsmith Logging - project_name: %s, run_name %s", fields["project_name"], fields["run_name"] ) payload: StandardLoggingPayload | None = kwargs.get("standard_logging_object", None) @@ -244,7 +244,7 @@ class LangsmithLogger(CustomBatchLogger): random_sample = random.random() if random_sample > sampling_rate: verbose_logger.info( - f"Skipping Langsmith logging. Sampling rate={sampling_rate}, random_sample={random_sample}" + "Skipping Langsmith logging. Sampling rate=%s, random_sample=%s", sampling_rate, random_sample ) return # Skip logging verbose_logger.debug( @@ -267,7 +267,7 @@ class LangsmithLogger(CustomBatchLogger): credentials=credentials, ) ) - verbose_logger.debug(f"Langsmith, event added to queue. Will flush in {self.flush_interval} seconds...") + verbose_logger.debug("Langsmith, event added to queue. Will flush in %s seconds...", self.flush_interval) if len(self.log_queue) >= self.batch_size: self._send_batch() @@ -282,7 +282,7 @@ class LangsmithLogger(CustomBatchLogger): random_sample = random.random() if random_sample > sampling_rate: verbose_logger.info( - f"Skipping Langsmith logging. Sampling rate={sampling_rate}, random_sample={random_sample}" + "Skipping Langsmith logging. Sampling rate=%s, random_sample=%s", sampling_rate, random_sample ) return # Skip logging verbose_logger.debug( @@ -321,7 +321,7 @@ class LangsmithLogger(CustomBatchLogger): random_sample = random.random() if random_sample > sampling_rate: verbose_logger.info( - f"Skipping Langsmith logging. Sampling rate={sampling_rate}, random_sample={random_sample}" + "Skipping Langsmith logging. Sampling rate=%s, random_sample=%s", sampling_rate, random_sample ) return # Skip logging verbose_logger.info("Langsmith Failure Event Logging!") @@ -422,16 +422,16 @@ class LangsmithLogger(CustomBatchLogger): response.raise_for_status() if response.status_code >= 300: - verbose_logger.error(f"Langsmith Error: {response.status_code} - {response.text}") + verbose_logger.error("Langsmith Error: %s - %s", response.status_code, response.text) else: if self.is_mock_mode: - verbose_logger.debug(f"[LANGSMITH MOCK] Batch of {len(elements_to_log)} runs successfully mocked") + verbose_logger.debug("[LANGSMITH MOCK] Batch of %s runs successfully mocked", len(elements_to_log)) else: - verbose_logger.debug(f"Batch of {len(self.log_queue)} runs successfully created") + verbose_logger.debug("Batch of %s runs successfully created", len(self.log_queue)) except httpx.HTTPStatusError as e: - verbose_logger.exception(f"Langsmith HTTP Error: {e.response.status_code} - {e.response.text}") + verbose_logger.exception("Langsmith HTTP Error: %s - %s", e.response.status_code, e.response.text) except Exception: - verbose_logger.exception(f"Langsmith Layer Error - {traceback.format_exc()}") + verbose_logger.exception("Langsmith Layer Error - %s", traceback.format_exc()) def _group_batches_by_credentials(self) -> dict[CredentialsKey, BatchGroup]: """Groups queue objects by credentials using a proper key structure""" diff --git a/litellm/integrations/literal_ai.py b/litellm/integrations/literal_ai.py index a54fdcf4dbc..a17a35f6a0e 100644 --- a/litellm/integrations/literal_ai.py +++ b/litellm/integrations/literal_ai.py @@ -94,9 +94,9 @@ class LiteralAILogger(CustomBatchLogger): ) if response.status_code >= 300: - verbose_logger.error(f"Literal AI Error: {response.status_code} - {response.text}") + verbose_logger.error("Literal AI Error: %s - %s", response.status_code, response.text) else: - verbose_logger.debug(f"Batch of {len(self.log_queue)} runs successfully created") + verbose_logger.debug("Batch of %s runs successfully created", len(self.log_queue)) except Exception: verbose_logger.exception("Literal AI Layer Error") @@ -152,11 +152,11 @@ class LiteralAILogger(CustomBatchLogger): headers=self.headers, ) if response.status_code >= 300: - verbose_logger.error(f"Literal AI Error: {response.status_code} - {response.text}") + verbose_logger.error("Literal AI Error: %s - %s", response.status_code, response.text) else: - verbose_logger.debug(f"Batch of {len(self.log_queue)} runs successfully created") + verbose_logger.debug("Batch of %s runs successfully created", len(self.log_queue)) except httpx.HTTPStatusError as e: - verbose_logger.exception(f"Literal AI HTTP Error: {e.response.status_code} - {e.response.text}") + verbose_logger.exception("Literal AI HTTP Error: %s - %s", e.response.status_code, e.response.text) except Exception: verbose_logger.exception("Literal AI Layer Error") diff --git a/litellm/integrations/logfire_logger.py b/litellm/integrations/logfire_logger.py index c94fb832ccc..814e2b88ba1 100644 --- a/litellm/integrations/logfire_logger.py +++ b/litellm/integrations/logfire_logger.py @@ -90,7 +90,7 @@ class LogfireLogger: try: import logfire - verbose_logger.debug(f"logfire Logging - Enters logging function for model {kwargs}") + verbose_logger.debug("logfire Logging - Enters logging function for model %s", kwargs) if not response_obj: response_obj = {} @@ -159,4 +159,4 @@ class LogfireLogger: print_verbose(f"Logfire Layer Logging - final response object: {response_obj}") except Exception as e: - verbose_logger.debug(f"Logfire Layer Error - {e}\n{traceback.format_exc()}") + verbose_logger.debug("Logfire Layer Error - %s\n%s", e, traceback.format_exc()) diff --git a/litellm/integrations/mlflow.py b/litellm/integrations/mlflow.py index 7ce5b3d3eea..f41de320843 100644 --- a/litellm/integrations/mlflow.py +++ b/litellm/integrations/mlflow.py @@ -99,7 +99,7 @@ class MlflowLogger(CustomLogger): ) except Exception as e: - verbose_logger.debug(f"MLflow Logging Error - {e}", stack_info=True) + verbose_logger.debug("MLflow Logging Error - %s", e, stack_info=True) def _handle_stream_event(self, kwargs, response_obj, start_time, end_time): """ diff --git a/litellm/integrations/mock_client_factory.py b/litellm/integrations/mock_client_factory.py index 2aab1792618..f1bc2db16ef 100644 --- a/litellm/integrations/mock_client_factory.py +++ b/litellm/integrations/mock_client_factory.py @@ -144,7 +144,7 @@ def create_mock_client_factory(config: MockClientConfig): ): """Monkey-patched AsyncHTTPHandler.post that intercepts API calls.""" if isinstance(url, str) and _is_mock_url(url): - verbose_logger.info(f"[{config.name} MOCK] POST to {url}") + verbose_logger.info("[%s MOCK] POST to %s", config.name, url) await asyncio.sleep(_MOCK_LATENCY_SECONDS) return MockResponse( status_code=config.default_status_code, @@ -172,7 +172,7 @@ def create_mock_client_factory(config: MockClientConfig): def _mock_sync_client_post(self, url, **kwargs): """Monkey-patched httpx.Client.post that intercepts API calls.""" if _is_mock_url(url): - verbose_logger.info(f"[{config.name} MOCK] POST to {url} (sync)") + verbose_logger.info("[%s MOCK] POST to %s (sync)", config.name, url) return MockResponse( status_code=config.default_status_code, json_data=config.default_json_data, @@ -198,7 +198,7 @@ def create_mock_client_factory(config: MockClientConfig): ): """Monkey-patched HTTPHandler.post that intercepts API calls.""" if isinstance(url, str) and _is_mock_url(url): - verbose_logger.info(f"[{config.name} MOCK] POST to {url}") + verbose_logger.info("[%s MOCK] POST to %s", config.name, url) import time time.sleep(_MOCK_LATENCY_SECONDS) @@ -236,29 +236,29 @@ def create_mock_client_factory(config: MockClientConfig): if _mocks_initialized: return - verbose_logger.debug(f"[{config.name} MOCK] Initializing {config.name} mock client...") + verbose_logger.debug("[%s MOCK] Initializing %s mock client...", config.name, config.name) if config.patch_async_handler and _original_async_handler_post is None: from litellm.llms.custom_httpx.http_handler import AsyncHTTPHandler _original_async_handler_post = AsyncHTTPHandler.post AsyncHTTPHandler.post = _mock_async_handler_post # type: ignore - verbose_logger.debug(f"[{config.name} MOCK] Patched AsyncHTTPHandler.post") + verbose_logger.debug("[%s MOCK] Patched AsyncHTTPHandler.post", config.name) if config.patch_sync_client and _original_sync_client_post is None: _original_sync_client_post = httpx.Client.post httpx.Client.post = _mock_sync_client_post # type: ignore - verbose_logger.debug(f"[{config.name} MOCK] Patched httpx.Client.post") + verbose_logger.debug("[%s MOCK] Patched httpx.Client.post", config.name) if config.patch_http_handler and _original_http_handler_post is None: from litellm.llms.custom_httpx.http_handler import HTTPHandler _original_http_handler_post = HTTPHandler.post HTTPHandler.post = _mock_http_handler_post # type: ignore - verbose_logger.debug(f"[{config.name} MOCK] Patched HTTPHandler.post") + verbose_logger.debug("[%s MOCK] Patched HTTPHandler.post", config.name) verbose_logger.debug(f"[{config.name} MOCK] Mock latency set to {_MOCK_LATENCY_SECONDS * 1000:.0f}ms") - verbose_logger.debug(f"[{config.name} MOCK] {config.name} mock client initialization complete") + verbose_logger.debug("[%s MOCK] %s mock client initialization complete", config.name, config.name) _mocks_initialized = True @@ -274,7 +274,7 @@ def create_mock_client_factory(config: MockClientConfig): result = bool(result) if result is not None else False if result: - verbose_logger.info(f"{config.name} Mock Mode: ENABLED - API calls will be mocked") + verbose_logger.info("%s Mock Mode: ENABLED - API calls will be mocked", config.name) return result diff --git a/litellm/integrations/newrelic/newrelic.py b/litellm/integrations/newrelic/newrelic.py index 5511cb06174..bf8ab29d384 100644 --- a/litellm/integrations/newrelic/newrelic.py +++ b/litellm/integrations/newrelic/newrelic.py @@ -116,11 +116,12 @@ class NewRelicLogger(CustomLogger): self.enabled = True verbose_logger.info( - f"New Relic AI Monitoring initialized for app: {self.app_name}, " - f"content recording: {self.record_content}" + "New Relic AI Monitoring initialized for app: %s, content recording: %s", + self.app_name, + self.record_content, ) except Exception as e: - verbose_logger.error(f"Failed to initialize New Relic agent: {e}. Integration will be disabled.") + verbose_logger.error("Failed to initialize New Relic agent: %s. Integration will be disabled.", e) self.enabled = False def _get_newrelic_params(self) -> dict: @@ -170,9 +171,10 @@ class NewRelicLogger(CustomLogger): if value in ("0", "false", "no", "off"): return False verbose_logger.warning( - f"{var_name}={raw!r} is not a recognised boolean " - f"(accepts true/false, 1/0, yes/no, on/off). " - f"Falling back to default ({default})." + "%s=%r is not a recognised boolean (accepts true/false, 1/0, yes/no, on/off). Falling back to default (%s).", + var_name, + raw, + default, ) return default @@ -188,7 +190,7 @@ class NewRelicLogger(CustomLogger): return version("litellm") except Exception as e: - verbose_logger.warning(f"Unable to determine litellm version: {e}") + verbose_logger.warning("Unable to determine litellm version: %s", e) return "unknown" def _emit_supportability_metric(self): @@ -216,12 +218,12 @@ class NewRelicLogger(CustomLogger): if app and app.enabled: app.record_custom_metric(metric_name, 1) - verbose_logger.info(f"Emitted New Relic supportability metric: {metric_name}") + verbose_logger.info("Emitted New Relic supportability metric: %s", metric_name) else: verbose_logger.info("New Relic application is not enabled; skipping metric recording.") except Exception as e: - verbose_logger.warning(f"Failed to emit supportability metric: {e}") + verbose_logger.warning("Failed to emit supportability metric: %s", e) def _check_and_emit_periodic_metric(self): """ @@ -294,14 +296,13 @@ class NewRelicLogger(CustomLogger): trace_id = slo_trace_id except Exception as e: - verbose_logger.warning(f"Unable to parse New Relic trace context from upstream sources: {e}") + verbose_logger.warning("Unable to parse New Relic trace context from upstream sources: %s", e) if not trace_id: trace_id = uuid.uuid4().hex verbose_logger.debug( - f"New Relic trace_id not available from distributed tracing headers or " - f"StandardLoggingPayload. Generated trace_id={trace_id} for AI monitoring " - f"event grouping." + "New Relic trace_id not available from distributed tracing headers or StandardLoggingPayload. Generated trace_id=%s for AI monitoring event grouping.", + trace_id, ) return trace_id @@ -638,7 +639,7 @@ class NewRelicLogger(CustomLogger): verbose_logger.warning("New Relic application is not enabled; skipping summary event recording.") except Exception as e: - verbose_logger.warning(f"Failed to record New Relic summary event: {e}") + verbose_logger.warning("Failed to record New Relic summary event: %s", e) self.handle_callback_failure("newrelic") def _record_message_events( @@ -699,7 +700,7 @@ class NewRelicLogger(CustomLogger): app.record_custom_event("LlmChatCompletionMessage", event_data) except Exception as e: - verbose_logger.warning(f"Failed to record New Relic message events: {e}") + verbose_logger.warning("Failed to record New Relic message events: %s", e) self.handle_callback_failure("newrelic") def _record_error_metric(self): @@ -714,7 +715,7 @@ class NewRelicLogger(CustomLogger): if app and app.enabled: app.record_custom_metric("LLM/LiteLLM/Error", 1) except Exception as e: - verbose_logger.warning(f"Failed to record New Relic error metric: {e}") + verbose_logger.warning("Failed to record New Relic error metric: %s", e) self.handle_callback_failure("newrelic") def _process_success( @@ -846,7 +847,7 @@ class NewRelicLogger(CustomLogger): try: self._process_success(kwargs, response_obj, start_time, end_time) except Exception as e: - verbose_logger.warning(f"Error in New Relic log_success_event: {e}") + verbose_logger.warning("Error in New Relic log_success_event: %s", e) self.handle_callback_failure("newrelic") async def async_log_success_event(self, kwargs, response_obj, start_time, end_time): @@ -859,7 +860,7 @@ class NewRelicLogger(CustomLogger): try: self._process_success(kwargs, response_obj, start_time, end_time) except Exception as e: - verbose_logger.warning(f"Error in New Relic async_log_success_event: {e}") + verbose_logger.warning("Error in New Relic async_log_success_event: %s", e) self.handle_callback_failure("newrelic") def log_failure_event(self, kwargs, response_obj, start_time, end_time): @@ -872,7 +873,7 @@ class NewRelicLogger(CustomLogger): self._record_error_metric() except Exception as e: - verbose_logger.warning(f"Error in New Relic log_failure_event: {e}") + verbose_logger.warning("Error in New Relic log_failure_event: %s", e) self.handle_callback_failure("newrelic") async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time): @@ -885,5 +886,5 @@ class NewRelicLogger(CustomLogger): self._record_error_metric() except Exception as e: - verbose_logger.warning(f"Error in New Relic async_log_failure_event: {e}") + verbose_logger.warning("Error in New Relic async_log_failure_event: %s", e) self.handle_callback_failure("newrelic") diff --git a/litellm/integrations/opentelemetry.py b/litellm/integrations/opentelemetry.py index 5342894a04f..94902460c81 100644 --- a/litellm/integrations/opentelemetry.py +++ b/litellm/integrations/opentelemetry.py @@ -2688,7 +2688,8 @@ class OpenTelemetry(OTELGenAISemconvMixin, CustomLogger): ) except json.JSONDecodeError: verbose_logger.debug( - f"litellm.integrations.opentelemetry.py::set_raw_request_attributes() - raw_response not json string - {_raw_response}" + "litellm.integrations.opentelemetry.py::set_raw_request_attributes() - raw_response not json string - %s", + _raw_response, ) self.safe_set_attribute( diff --git a/litellm/integrations/opik/opik.py b/litellm/integrations/opik/opik.py index e4d40a1af8f..afb6fef9d71 100644 --- a/litellm/integrations/opik/opik.py +++ b/litellm/integrations/opik/opik.py @@ -81,7 +81,7 @@ class OpikLogger(CustomBatchLogger): self.flush_lock: asyncio.Lock | None = asyncio.Lock() except Exception as e: verbose_logger.exception( - f"OpikLogger - Asynchronous processing not initialized as we are not running in an async context {e}" + "OpikLogger - Asynchronous processing not initialized as we are not running in an async context %s", e ) self.flush_lock = None @@ -154,14 +154,14 @@ class OpikLogger(CustomBatchLogger): self.log_queue.append(span_payload.__dict__) verbose_logger.debug( - f"OpikLogger added event to log_queue - Will flush in {self.flush_interval} seconds..." + "OpikLogger added event to log_queue - Will flush in %s seconds...", self.flush_interval ) if len(self.log_queue) >= self.batch_size: verbose_logger.debug("OpikLogger - Flushing batch") await self.flush_queue() except Exception as e: - verbose_logger.exception(f"OpikLogger failed to log success event - {e}\n{traceback.format_exc()}") + verbose_logger.exception("OpikLogger failed to log success event - %s\n%s", e, traceback.format_exc()) def _sync_send(self, url: str, headers: dict[str, str], batch: dict[str, Any]) -> None: try: @@ -174,7 +174,7 @@ class OpikLogger(CustomBatchLogger): if response.status_code != 204: raise Exception(f"Response from opik API status_code: {response.status_code}, text: {response.text}") except Exception as e: - verbose_logger.exception(f"OpikLogger failed to send batch - {e}\n{traceback.format_exc()}") + verbose_logger.exception("OpikLogger failed to send batch - %s\n%s", e, traceback.format_exc()) def log_success_event( self, @@ -245,7 +245,7 @@ class OpikLogger(CustomBatchLogger): batch={"spans": [span_payload.__dict__]}, ) except Exception as e: - verbose_logger.exception(f"OpikLogger failed to log success event - {e}\n{traceback.format_exc()}") + verbose_logger.exception("OpikLogger failed to log success event - %s\n%s", e, traceback.format_exc()) async def _submit_batch(self, url: str, headers: dict[str, str], batch: dict[str, Any]) -> None: try: @@ -257,11 +257,11 @@ class OpikLogger(CustomBatchLogger): response.raise_for_status() if response.status_code >= 300: - verbose_logger.error(f"OpikLogger - Error: {response.status_code} - {response.text}") + verbose_logger.error("OpikLogger - Error: %s - %s", response.status_code, response.text) else: - verbose_logger.info(f"OpikLogger - {len(self.log_queue)} Opik events submitted") + verbose_logger.info("OpikLogger - %s Opik events submitted", len(self.log_queue)) except Exception as e: - verbose_logger.exception(f"OpikLogger failed to send batch - {e}") + verbose_logger.exception("OpikLogger failed to send batch - %s", e) def _create_opik_headers(self) -> dict[str, str]: headers: dict[str, str] = {} @@ -283,7 +283,7 @@ class OpikLogger(CustomBatchLogger): # Send trace batch if len(traces) > 0: await self._submit_batch(url=self.trace_url, headers=self.headers, batch={"traces": traces}) - verbose_logger.info(f"Sent {len(traces)} traces") + verbose_logger.info("Sent %s traces", len(traces)) if len(spans) > 0: await self._submit_batch(url=self.span_url, headers=self.headers, batch={"spans": spans}) - verbose_logger.info(f"Sent {len(spans)} spans") + verbose_logger.info("Sent %s spans", len(spans)) diff --git a/litellm/integrations/opik/opik_payload_builder/extractors.py b/litellm/integrations/opik/opik_payload_builder/extractors.py index f95bd110cb3..ccc59cde751 100644 --- a/litellm/integrations/opik/opik_payload_builder/extractors.py +++ b/litellm/integrations/opik/opik_payload_builder/extractors.py @@ -66,7 +66,7 @@ def extract_opik_metadata( if requester_opik: opik_meta.update(requester_opik) - _logging.verbose_logger.debug(f"litellm_opik_metadata - {json.dumps(opik_meta, default=str)}") + _logging.verbose_logger.debug("litellm_opik_metadata - %s", json.dumps(opik_meta, default=str)) return opik_meta @@ -92,7 +92,7 @@ def extract_span_identifiers( try: return current_span_data.trace_id, current_span_data.id except AttributeError: - _logging.verbose_logger.warning(f"Unexpected current_span_data format: {type(current_span_data)}") + _logging.verbose_logger.warning("Unexpected current_span_data format: %s", type(current_span_data)) return None, None @@ -152,7 +152,7 @@ def apply_proxy_header_overrides( if isinstance(parsed_tags, list): tags.extend(parsed_tags) except (json.JSONDecodeError, TypeError): - _logging.verbose_logger.warning(f"Failed to parse tags from header: {value}") + _logging.verbose_logger.warning("Failed to parse tags from header: %s", value) return project_name, tags, thread_id diff --git a/litellm/integrations/opik/opik_payload_builder/payload_builders.py b/litellm/integrations/opik/opik_payload_builder/payload_builders.py index 517d5431b70..19e1dd1042c 100644 --- a/litellm/integrations/opik/opik_payload_builder/payload_builders.py +++ b/litellm/integrations/opik/opik_payload_builder/payload_builders.py @@ -61,7 +61,7 @@ def build_span_payload( created = response_obj.get("created", 0) span_name = f"{model}_{obj_type}_{created}" - _logging.verbose_logger.debug(f"OpikLogger creating span with id {span_id} for trace {trace_id}") + _logging.verbose_logger.debug("OpikLogger creating span with id %s for trace %s", span_id, trace_id) return types.SpanPayload( id=span_id, diff --git a/litellm/integrations/posthog.py b/litellm/integrations/posthog.py index 216edc44d3f..e6620535d81 100644 --- a/litellm/integrations/posthog.py +++ b/litellm/integrations/posthog.py @@ -72,7 +72,7 @@ class PostHogLogger(CustomBatchLogger): super().__init__(**kwargs, flush_lock=None, batch_size=POSTHOG_MAX_BATCH_SIZE) except Exception as e: - verbose_logger.exception(f"PostHog: Got exception on init PostHog client {e}") + verbose_logger.exception("PostHog: Got exception on init PostHog client %s", e) raise e def log_success_event(self, kwargs, response_obj, start_time, end_time): @@ -107,7 +107,7 @@ class PostHogLogger(CustomBatchLogger): verbose_logger.debug("PostHog: Sync event successfully sent") except Exception as e: - verbose_logger.exception(f"PostHog Sync Layer Error - {e}") + verbose_logger.exception("PostHog Sync Layer Error - %s", e) async def async_log_success_event(self, kwargs, response_obj, start_time, end_time): try: @@ -115,7 +115,7 @@ class PostHogLogger(CustomBatchLogger): self._ensure_async_setup() # Lazy initialization await self._log_async_event(kwargs, response_obj, start_time, end_time) except Exception as e: - verbose_logger.exception(f"PostHog Layer Error - {e}") + verbose_logger.exception("PostHog Layer Error - %s", e) async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time): try: @@ -123,7 +123,7 @@ class PostHogLogger(CustomBatchLogger): self._ensure_async_setup() # Lazy initialization await self._log_async_event(kwargs, response_obj, start_time, end_time) except Exception as e: - verbose_logger.exception(f"PostHog Layer Error - {e}") + verbose_logger.exception("PostHog Layer Error - %s", e) async def _log_async_event(self, kwargs, response_obj=None, start_time=0.0, end_time=0.0): # Note: response_obj, start_time, end_time not used - all data comes from kwargs @@ -132,7 +132,7 @@ class PostHogLogger(CustomBatchLogger): # Store event with its credentials for batch sending self.log_queue.append({"event": event_payload, "api_key": api_key, "api_url": api_url}) - verbose_logger.debug(f"PostHog, event added to queue. Will flush in {self.flush_interval} seconds...") + verbose_logger.debug("PostHog, event added to queue. Will flush in %s seconds...", self.flush_interval) if len(self.log_queue) >= self.batch_size: await self.flush_queue() @@ -328,7 +328,7 @@ class PostHogLogger(CustomBatchLogger): if not self.log_queue: return - verbose_logger.debug(f"PostHog: Sending batch of {len(self.log_queue)} events") + verbose_logger.debug("PostHog: Sending batch of %s events", len(self.log_queue)) if self.is_mock_mode: verbose_logger.debug("[POSTHOG MOCK] Mock mode enabled - API calls will be intercepted") @@ -363,11 +363,11 @@ class PostHogLogger(CustomBatchLogger): ) if self.is_mock_mode: - verbose_logger.debug(f"[POSTHOG MOCK] Batch of {len(self.log_queue)} events successfully mocked") + verbose_logger.debug("[POSTHOG MOCK] Batch of %s events successfully mocked", len(self.log_queue)) else: - verbose_logger.debug(f"PostHog: Batch of {len(self.log_queue)} events successfully sent") + verbose_logger.debug("PostHog: Batch of %s events successfully sent", len(self.log_queue)) except Exception as e: - verbose_logger.exception(f"PostHog Error sending batch API - {e}") + verbose_logger.exception("PostHog Error sending batch API - %s", e) def _ensure_async_setup(self): if not self._async_initialized: @@ -377,7 +377,7 @@ class PostHogLogger(CustomBatchLogger): self._async_initialized = True verbose_logger.debug("PostHog: Async components initialized") except Exception as e: - verbose_logger.error(f"PostHog: Failed to initialize async components: {e}") + verbose_logger.error("PostHog: Failed to initialize async components: %s", e) raise def _extract_metadata(self, kwargs: dict[str, Any]) -> dict[str, Any]: @@ -408,7 +408,7 @@ class PostHogLogger(CustomBatchLogger): if not self.log_queue: return - verbose_logger.debug(f"PostHog: Flushing {len(self.log_queue)} remaining events on exit") + verbose_logger.debug("PostHog: Flushing %s remaining events on exit", len(self.log_queue)) try: # Group events by credentials (same logic as async_send_batch) @@ -436,13 +436,13 @@ class PostHogLogger(CustomBatchLogger): response.raise_for_status() if response.status_code != 200: - verbose_logger.error(f"PostHog: Failed to flush on exit - status {response.status_code}") + verbose_logger.error("PostHog: Failed to flush on exit - status %s", response.status_code) if self.is_mock_mode: - verbose_logger.debug(f"[POSTHOG MOCK] Successfully flushed {len(self.log_queue)} events on exit") + verbose_logger.debug("[POSTHOG MOCK] Successfully flushed %s events on exit", len(self.log_queue)) else: - verbose_logger.debug(f"PostHog: Successfully flushed {len(self.log_queue)} events on exit") + verbose_logger.debug("PostHog: Successfully flushed %s events on exit", len(self.log_queue)) self.log_queue.clear() except Exception as e: - verbose_logger.error(f"PostHog: Error flushing events on exit: {e}") + verbose_logger.error("PostHog: Error flushing events on exit: %s", e) diff --git a/litellm/integrations/prometheus.py b/litellm/integrations/prometheus.py index b7705a40e0c..78f4e213f50 100644 --- a/litellm/integrations/prometheus.py +++ b/litellm/integrations/prometheus.py @@ -697,7 +697,7 @@ class PrometheusLogger(CustomLogger): if not config: return {} - verbose_logger.debug(f"prometheus config: {config}") + verbose_logger.debug("prometheus config: %s", config) # Parse and validate all configuration groups parsed_configs = [] @@ -963,7 +963,10 @@ class PrometheusLogger(CustomLogger): except ImportError: # Fallback to simple logging if rich is not available verbose_logger.error( - f"Invalid labels for metric '{metric_name}': {invalid_labels}. Valid labels: {sorted(valid_labels)}" + "Invalid labels for metric '%s': %s. Valid labels: %s", + metric_name, + invalid_labels, + sorted(valid_labels), ) def _pretty_print_invalid_metric_error(self, invalid_metric_name: str, valid_metrics: tuple) -> None: @@ -1003,7 +1006,9 @@ class PrometheusLogger(CustomLogger): except ImportError: # Fallback to simple logging if rich is not available - verbose_logger.error(f"Invalid metric name: {invalid_metric_name}. Valid metrics: {sorted(valid_metrics)}") + verbose_logger.error( + "Invalid metric name: %s. Valid metrics: %s", invalid_metric_name, sorted(valid_metrics) + ) ######################################################### # End of pretty print functions @@ -1078,9 +1083,10 @@ class PrometheusLogger(CustomLogger): except ImportError: # Fallback to simple logging if rich is not available verbose_logger.info( - f"Enabled metrics: {sorted(self.enabled_metrics) if hasattr(self, 'enabled_metrics') else 'All metrics'}" + "Enabled metrics: %s", + sorted(self.enabled_metrics) if hasattr(self, "enabled_metrics") else "All metrics", ) - verbose_logger.info(f"Label filters: {label_filters}") + verbose_logger.info("Label filters: %s", label_filters) def _is_metric_enabled(self, metric_name: str) -> bool: """Check if a metric is enabled based on configuration""" @@ -1866,7 +1872,9 @@ class PrometheusLogger(CustomLogger): for i, r in enumerate(results): if isinstance(r, Exception): verbose_logger.debug( - f"[Non-Blocking] Prometheus: Budget metric lookup {['key', 'team', 'user', 'org'][i]} failed: {r}" + "[Non-Blocking] Prometheus: Budget metric lookup %s failed: %s", + ["key", "team", "user", "org"][i], + r, ) def _increment_top_level_request_and_spend_metrics( @@ -2132,7 +2140,7 @@ class PrometheusLogger(CustomLogger): response_cost=0, ) except Exception as e: - verbose_logger.exception(f"prometheus Layer Error(): Exception occured - {e}") + verbose_logger.exception("prometheus Layer Error(): Exception occured - %s", e) def _extract_status_code( self, @@ -2262,8 +2270,9 @@ class PrometheusLogger(CustomLogger): if self._is_invalid_api_key_request(status_code, exception=exception): verbose_logger.debug( - "Skipping Prometheus metrics for invalid API key request: " - f"status_code={status_code}, exception={type(exception).__name__ if exception else None}" + "Skipping Prometheus metrics for invalid API key request: status_code=%s, exception=%s", + status_code, + type(exception).__name__ if exception else None, ) return True @@ -2383,7 +2392,7 @@ class PrometheusLogger(CustomLogger): ) except Exception as e: - verbose_logger.exception(f"prometheus Layer Error(): Exception occured - {e}") + verbose_logger.exception("prometheus Layer Error(): Exception occured - %s", e) async def async_post_call_success_hook(self, data: dict, user_api_key_dict: UserAPIKeyAuth, response): """ @@ -2608,7 +2617,7 @@ class PrometheusLogger(CustomLogger): ) except Exception as e: - verbose_logger.debug(f"Prometheus Error: set_llm_deployment_failure_metrics. Exception occured - {e}") + verbose_logger.debug("Prometheus Error: set_llm_deployment_failure_metrics. Exception occured - %s", e) def _set_deployment_tpm_rpm_limit_metrics( self, @@ -2722,7 +2731,7 @@ class PrometheusLogger(CustomLogger): ) self.litellm_remaining_requests_metric.labels(**_labels).set(remaining_requests) except Exception as e: - verbose_logger.exception(f"Prometheus Error: _async_set_router_remaining_metrics. Exception occured - {e}") + verbose_logger.exception("Prometheus Error: _async_set_router_remaining_metrics. Exception occured - %s", e) def set_llm_deployment_success_metrics( self, @@ -2865,7 +2874,7 @@ class PrometheusLogger(CustomLogger): self.litellm_deployment_latency_per_output_token.labels(**_labels).observe(latency_per_token) except Exception as e: - verbose_logger.exception(f"Prometheus Error: set_llm_deployment_success_metrics. Exception occured - {e}") + verbose_logger.exception("Prometheus Error: set_llm_deployment_success_metrics. Exception occured - %s", e) return def _record_guardrail_metrics( @@ -2910,7 +2919,7 @@ class PrometheusLogger(CustomLogger): hook_type=hook_type, ).inc() except Exception as e: - verbose_logger.debug(f"Error recording guardrail metrics: {e}") + verbose_logger.debug("Error recording guardrail metrics: %s", e) ######################################## # Managed Batch Metric Recording Methods @@ -2933,7 +2942,7 @@ class PrometheusLogger(CustomLogger): api_key_alias=api_key_alias, ).inc() except Exception as e: - verbose_logger.warning(f"Error recording batch created metric: {e}") + verbose_logger.warning("Error recording batch created metric: %s", e) def record_managed_file_size( self, @@ -2954,7 +2963,7 @@ class PrometheusLogger(CustomLogger): user=user or "", ).set(size_bytes) except Exception as e: - verbose_logger.warning(f"Error recording file size metric: {e}") + verbose_logger.warning("Error recording file size metric: %s", e) def record_managed_batch_duration( self, @@ -2968,7 +2977,7 @@ class PrometheusLogger(CustomLogger): api_provider=api_provider or "", ).observe(duration_seconds) except Exception as e: - verbose_logger.warning(f"Error recording batch duration metric: {e}") + verbose_logger.warning("Error recording batch duration metric: %s", e) def record_managed_file_created( self, @@ -2987,14 +2996,14 @@ class PrometheusLogger(CustomLogger): api_key_alias=api_key_alias, ).inc() except Exception as e: - verbose_logger.warning(f"Error recording file created metric: {e}") + verbose_logger.warning("Error recording file created metric: %s", e) def record_managed_file_deleted(self, result: str): """Record a managed file deletion attempt. result is 'success' or 'blocked'.""" try: self.litellm_managed_file_deleted_total.labels(result=result).inc() except Exception as e: - verbose_logger.warning(f"Error recording file deleted metric: {e}") + verbose_logger.warning("Error recording file deleted metric: %s", e) def record_check_batch_cost_run( self, @@ -3021,7 +3030,7 @@ class PrometheusLogger(CustomLogger): api_provider=api_provider or "", ).inc() except Exception as e: - verbose_logger.warning(f"Error recording check batch cost metrics: {e}") + verbose_logger.warning("Error recording check batch cost metrics: %s", e) def record_check_batch_cost_error(self, error_type: str): try: @@ -3029,7 +3038,7 @@ class PrometheusLogger(CustomLogger): error_type=error_type, ).inc() except Exception as e: - verbose_logger.warning(f"Error recording check batch cost error metric: {e}") + verbose_logger.warning("Error recording check batch cost error metric: %s", e) @staticmethod def _get_exception_class_name(exception: Exception) -> str: @@ -3313,7 +3322,7 @@ class PrometheusLogger(CustomLogger): await set_metrics_function(data) except Exception as e: - verbose_logger.exception(f"Error initializing {data_type} budget metrics: {e}") + verbose_logger.exception("Error initializing %s budget metrics: %s", data_type, e) async def _initialize_team_budget_metrics(self): """ @@ -3493,18 +3502,18 @@ class PrometheusLogger(CustomLogger): # Get total user count total_users = await UserRepository(prisma_client).table.count() self.litellm_total_users_metric.set(total_users) - verbose_logger.debug(f"Prometheus: set litellm_total_users to {total_users}") + verbose_logger.debug("Prometheus: set litellm_total_users to %s", total_users) billable_users = await UserRepository(prisma_client).count_billable_users() self.litellm_active_users_metric.set(billable_users) - verbose_logger.debug(f"Prometheus: set litellm_active_users to {billable_users}") + verbose_logger.debug("Prometheus: set litellm_active_users to %s", billable_users) # Get total team count total_teams = await TeamRepository(prisma_client).table.count() self.litellm_teams_count_metric.set(total_teams) - verbose_logger.debug(f"Prometheus: set litellm_teams_count to {total_teams}") + verbose_logger.debug("Prometheus: set litellm_teams_count to %s", total_teams) except Exception as e: - verbose_logger.exception(f"Error initializing user/team count metrics: {e}") + verbose_logger.exception("Error initializing user/team count metrics: %s", e) async def _set_key_list_budget_metrics(self, keys: list[str | UserAPIKeyAuth]): """Helper function to set budget metrics for a list of keys""" @@ -3595,7 +3604,7 @@ class PrometheusLogger(CustomLogger): user_api_key_cache=user_api_key_cache, ) except Exception as e: - verbose_logger.debug(f"[Non-Blocking] Prometheus: Error getting team info: {e}") + verbose_logger.debug("[Non-Blocking] Prometheus: Error getting team info: %s", e) return team_object if team_info: @@ -3693,7 +3702,7 @@ class PrometheusLogger(CustomLogger): include_budget_table=True, ) except Exception as e: - verbose_logger.debug(f"[Non-Blocking] Prometheus: Error getting org info: {e}") + verbose_logger.debug("[Non-Blocking] Prometheus: Error getting org info: %s", e) return if org_info is None: @@ -3850,7 +3859,7 @@ class PrometheusLogger(CustomLogger): if key_object: user_api_key_dict.budget_reset_at = key_object.budget_reset_at except Exception as e: - verbose_logger.debug(f"[Non-Blocking] Prometheus: Error getting key info: {e}") + verbose_logger.debug("[Non-Blocking] Prometheus: Error getting key info: %s", e) return user_api_key_dict @@ -3915,7 +3924,7 @@ class PrometheusLogger(CustomLogger): check_db_only=False, ) except Exception as e: - verbose_logger.debug(f"[Non-Blocking] Prometheus: Error getting user info: {e}") + verbose_logger.debug("[Non-Blocking] Prometheus: Error getting user info: %s", e) return user_object if user_info: diff --git a/litellm/integrations/prometheus_services.py b/litellm/integrations/prometheus_services.py index 002d61265a4..446287441d7 100644 --- a/litellm/integrations/prometheus_services.py +++ b/litellm/integrations/prometheus_services.py @@ -92,7 +92,7 @@ class PrometheusServicesLogger: metrics = DEFAULT_SERVICE_CONFIGS.get(service, {}).get("metrics", []) if not metrics: - verbose_logger.debug(f"No metrics found for service {service}") + verbose_logger.debug("No metrics found for service %s", service) return DEFAULT_METRICS return metrics diff --git a/litellm/integrations/rubrik.py b/litellm/integrations/rubrik.py index 4bcbe8bae37..1ca5e0e5a66 100644 --- a/litellm/integrations/rubrik.py +++ b/litellm/integrations/rubrik.py @@ -161,9 +161,9 @@ class RubrikLogger(CustomGuardrail, CustomBatchLogger): parsed_rate = float(rbrk_sampling_rate.strip()) self.sampling_rate = max(0.0, min(1.0, parsed_rate)) if parsed_rate != self.sampling_rate: - verbose_logger.warning(f"RUBRIK_SAMPLING_RATE={parsed_rate} clamped to {self.sampling_rate}") + verbose_logger.warning("RUBRIK_SAMPLING_RATE=%s clamped to %s", parsed_rate, self.sampling_rate) except ValueError: - verbose_logger.warning(f"Invalid RUBRIK_SAMPLING_RATE: {rbrk_sampling_rate!r}, using 1.0") + verbose_logger.warning("Invalid RUBRIK_SAMPLING_RATE: %r, using 1.0", rbrk_sampling_rate) def _parse_batch_size(self) -> None: _batch_size = os.getenv("RUBRIK_BATCH_SIZE") @@ -171,11 +171,11 @@ class RubrikLogger(CustomGuardrail, CustomBatchLogger): try: parsed_size = int(_batch_size) if parsed_size <= 0: - verbose_logger.warning(f"RUBRIK_BATCH_SIZE={_batch_size!r} must be > 0, using default") + verbose_logger.warning("RUBRIK_BATCH_SIZE=%r must be > 0, using default", _batch_size) else: self.batch_size = parsed_size except ValueError: - verbose_logger.warning(f"Invalid RUBRIK_BATCH_SIZE: {_batch_size!r}, using default") + verbose_logger.warning("Invalid RUBRIK_BATCH_SIZE: %r, using default", _batch_size) def _setup_clients(self, webhook_url: str) -> None: self.response_moderation_endpoint = f"{webhook_url}{_WEBHOOK_PATH_RESPONSE_MODERATION}" @@ -277,7 +277,9 @@ class RubrikLogger(CustomGuardrail, CustomBatchLogger): return inputs except Exception as e: verbose_logger.error( - f"{label} hook failed: {e}. Returning original inputs unchanged.", + "%s hook failed: %s. Returning original inputs unchanged.", + label, + e, exc_info=True, ) return inputs @@ -386,8 +388,9 @@ class RubrikLogger(CustomGuardrail, CustomBatchLogger): if logging_obj is None: verbose_logger.error( "Rubrik: moderation block fired with logging_obj=None for " - f"litellm_call_id={request_data.get('litellm_call_id')}; " - "cannot suppress success event or attach failure payload." + "litellm_call_id=%s; " + "cannot suppress success event or attach failure payload.", + request_data.get("litellm_call_id"), ) request_data["_rubrik_logging_obj"] = None return @@ -648,14 +651,15 @@ class RubrikLogger(CustomGuardrail, CustomBatchLogger): payload["messages"] = (system_scaffold, messages) except Exception as e: verbose_logger.warning( - f"Rubrik: failed to prepend system prompt: {e}", + "Rubrik: failed to prepend system prompt: %s", + e, exc_info=True, ) async def _prepare_log_payload(self, kwargs: Mapping[str, Any], event_type: str) -> StandardLoggingPayload | None: """Shared logic for success logging (sampled).""" if random.random() > self.sampling_rate: - verbose_logger.debug(f"Skipping Rubrik {event_type} logging (sampling_rate={self.sampling_rate})") + verbose_logger.debug("Skipping Rubrik %s logging (sampling_rate=%s)", event_type, self.sampling_rate) return None # Deep-copy so mutations don't affect other callbacks sharing this object @@ -699,7 +703,9 @@ class RubrikLogger(CustomGuardrail, CustomBatchLogger): await self._append_and_maybe_flush(payload) except Exception as e: verbose_logger.error( - f"Rubrik {event_type} logging hook failed: {e}. Skipping logging for this event.", + "Rubrik %s logging hook failed: %s. Skipping logging for this event.", + event_type, + e, exc_info=True, ) @@ -708,7 +714,8 @@ class RubrikLogger(CustomGuardrail, CustomBatchLogger): # skip here to avoid double-logging the pre-block response. if kwargs.get("_rubrik_blocked"): verbose_logger.debug( - f"Rubrik: skipping success event for blocked request litellm_call_id={kwargs.get('litellm_call_id')}" + "Rubrik: skipping success event for blocked request litellm_call_id=%s", + kwargs.get("litellm_call_id"), ) return await self._enqueue_log_event(kwargs, "success") @@ -753,11 +760,11 @@ class RubrikLogger(CustomGuardrail, CustomBatchLogger): # way we cannot build the payload. verbose_logger.warning( "Rubrik: block exception without stashed logging_obj. " - f"litellm_call_id={request_data.get('litellm_call_id')}, " - f"model={request_data.get('model')}, " - f"user_id={getattr(user_api_key_dict, 'user_id', None)}, " - f"raising_guardrail=" - f"{getattr(original_exception, 'guardrail_name', None)}" + "litellm_call_id=%s, model=%s, user_id=%s, raising_guardrail=%s", + request_data.get("litellm_call_id"), + request_data.get("model"), + getattr(user_api_key_dict, "user_id", None), + getattr(original_exception, "guardrail_name", None), ) return @@ -783,8 +790,9 @@ class RubrikLogger(CustomGuardrail, CustomBatchLogger): payload = self._prepare_block_failure_payload(logging_obj, exception) except (AttributeError, KeyError, TypeError) as e: verbose_logger.error( - f"Rubrik: failed to build blocked-tool payload for " - f"litellm_call_id={call_id}: {e}. Event will NOT be logged.", + "Rubrik: failed to build blocked-tool payload for litellm_call_id=%s: %s. Event will NOT be logged.", + call_id, + e, exc_info=True, ) return @@ -793,7 +801,9 @@ class RubrikLogger(CustomGuardrail, CustomBatchLogger): await self._append_and_maybe_flush(payload) except Exception as e: verbose_logger.error( - f"Rubrik: failed to enqueue blocked-tool event for litellm_call_id={call_id}: {e}.", + "Rubrik: failed to enqueue blocked-tool event for litellm_call_id=%s: %s.", + call_id, + e, exc_info=True, ) @@ -845,8 +855,9 @@ class RubrikLogger(CustomGuardrail, CustomBatchLogger): else: verbose_logger.debug( "Rubrik: standard_logging_object not yet on model_call_details " - f"for litellm_call_id={call_details.get('litellm_call_id')}; " - "using best-effort fallback payload." + "for litellm_call_id=%s; " + "using best-effort fallback payload.", + call_details.get("litellm_call_id"), ) payload = self._build_fallback_payload(call_details) @@ -906,7 +917,7 @@ class RubrikLogger(CustomGuardrail, CustomBatchLogger): ) response.raise_for_status() except httpx.HTTPStatusError as e: - verbose_logger.exception(f"Rubrik HTTP Error: {e.response.status_code} - {e.response.text}") + verbose_logger.exception("Rubrik HTTP Error: %s - %s", e.response.status_code, e.response.text) raise except Exception: verbose_logger.exception("Rubrik Layer Error") @@ -963,7 +974,7 @@ class RubrikLogger(CustomGuardrail, CustomBatchLogger): Exception: If the service is unavailable or returns an error. TypeError: If the response JSON is not a dict. """ - verbose_logger.debug(f"Sending request to {service_name}: {endpoint}") + verbose_logger.debug("Sending request to %s: %s", service_name, endpoint) http_response = await self.moderation_client.post( endpoint, json=payload, diff --git a/litellm/integrations/s3.py b/litellm/integrations/s3.py index c35cc88107f..a4bd488221c 100644 --- a/litellm/integrations/s3.py +++ b/litellm/integrations/s3.py @@ -31,7 +31,7 @@ class S3Logger: import boto3 try: - verbose_logger.debug(f"in init s3 logger - s3_callback_params {litellm.s3_callback_params}") + verbose_logger.debug("in init s3 logger - s3_callback_params %s", litellm.s3_callback_params) s3_use_team_prefix = False @@ -62,7 +62,7 @@ class S3Logger: self.s3_server_side_encryption, self.s3_sse_kms_key_id = resolve_sse_params( s3_server_side_encryption, s3_sse_kms_key_id ) - verbose_logger.debug(f"s3 logger using endpoint url {s3_endpoint_url}") + verbose_logger.debug("s3 logger using endpoint url %s", s3_endpoint_url) # Create an S3 client with custom endpoint URL self.s3_client = boto3.client( "s3", @@ -86,7 +86,7 @@ class S3Logger: def log_event(self, kwargs, response_obj, start_time, end_time, print_verbose): try: - verbose_logger.debug(f"s3 Logging - Enters logging function for model {kwargs}") + verbose_logger.debug("s3 Logging - Enters logging function for model %s", kwargs) # construct payload to send to s3 # follows the same params as langfuse.py @@ -168,14 +168,14 @@ class S3Logger: print_verbose(f"s3 Layer Logging - final response object: {response_obj}") return response except Exception as e: - verbose_logger.exception(f"s3 Layer Error - {e}") + verbose_logger.exception("s3 Layer Error - %s", e) def _validated_sse_value(name: str, value: str | None) -> str | None: if value is None or isinstance(value, str): return value verbose_logger.warning( - f"s3 logging: ignoring {name} because it has invalid type {type(value).__name__}; expected a string" + "s3 logging: ignoring %s because it has invalid type %s; expected a string", name, type(value).__name__ ) return None @@ -191,8 +191,8 @@ def resolve_sse_params( return None, None if valid_key_id and not algorithm.startswith("aws:kms"): verbose_logger.warning( - f"s3 logging: ignoring s3_sse_kms_key_id because s3_server_side_encryption is {algorithm}; " - "set it to aws:kms to encrypt with the KMS key" + "s3 logging: ignoring s3_sse_kms_key_id because s3_server_side_encryption is %s; set it to aws:kms to encrypt with the KMS key", + algorithm, ) return algorithm, None return algorithm, valid_key_id diff --git a/litellm/integrations/s3_v2.py b/litellm/integrations/s3_v2.py index 44c6e42f9f0..c197b65696f 100644 --- a/litellm/integrations/s3_v2.py +++ b/litellm/integrations/s3_v2.py @@ -64,12 +64,12 @@ class S3Logger(CustomBatchLogger, BaseAWSLLM): _masker = SensitiveDataMasker() if s3_callback_params_override is not None: verbose_logger.debug( - f"in init s3 logger (audit override) - {_masker.mask_dict(dict(s3_callback_params_override))}" + "in init s3 logger (audit override) - %s", _masker.mask_dict(dict(s3_callback_params_override)) ) else: verbose_logger.debug( - f"in init s3 logger - s3_callback_params " - f"{_masker.mask_dict(dict(litellm.s3_callback_params or {}))}" + "in init s3 logger - s3_callback_params %s", + _masker.mask_dict(dict(litellm.s3_callback_params or {})), ) # Initialize S3 params first to get the correct s3_verify value @@ -98,11 +98,11 @@ class S3Logger(CustomBatchLogger, BaseAWSLLM): s3_server_side_encryption=s3_server_side_encryption, s3_sse_kms_key_id=s3_sse_kms_key_id, ) - verbose_logger.debug(f"s3 logger using endpoint url {s3_endpoint_url}") + verbose_logger.debug("s3 logger using endpoint url %s", s3_endpoint_url) # IMPORTANT # Create httpx client AFTER _init_s3_params so we have the correct s3_verify value - verbose_logger.debug(f"s3_v2 logger creating async httpx client with s3_verify={self.s3_verify}") + verbose_logger.debug("s3_v2 logger creating async httpx client with s3_verify=%s", self.s3_verify) self.async_httpx_client = get_async_httpx_client( llm_provider=httpxSpecialProvider.LoggingCallback, params={"ssl_verify": self.s3_verify}, @@ -111,7 +111,7 @@ class S3Logger(CustomBatchLogger, BaseAWSLLM): asyncio.create_task(self.periodic_flush()) self.flush_lock = asyncio.Lock() - verbose_logger.debug(f"s3 flush interval: {s3_flush_interval}, s3 batch size: {s3_batch_size}") + verbose_logger.debug("s3 flush interval: %s, s3 batch size: %s", s3_flush_interval, s3_batch_size) # Call CustomLogger's __init__ CustomBatchLogger.__init__( self, @@ -259,7 +259,7 @@ class S3Logger(CustomBatchLogger, BaseAWSLLM): async def _async_log_event_base(self, kwargs, response_obj, start_time, end_time): try: - verbose_logger.debug(f"s3 Logging - Enters logging function for model {kwargs}") + verbose_logger.debug("s3 Logging - Enters logging function for model %s", kwargs) s3_batch_logging_element = self.create_s3_batch_logging_element( start_time=start_time, @@ -284,7 +284,7 @@ class S3Logger(CustomBatchLogger, BaseAWSLLM): self.batch_size, ) except Exception as e: - verbose_logger.exception(f"s3 Layer Error - {e}") + verbose_logger.exception("s3 Layer Error - %s", e) self.handle_callback_failure(callback_name="S3Logger") async def async_upload_data_to_s3(self, batch_logging_element: s3BatchLoggingElement): @@ -313,8 +313,8 @@ class S3Logger(CustomBatchLogger, BaseAWSLLM): aws_sts_endpoint=self.s3_aws_sts_endpoint, ) - verbose_logger.debug(f"s3_v2 logger - uploading data to s3 - {batch_logging_element.s3_object_key}") - verbose_logger.debug(f"s3_v2 logger - s3_verify setting: {self.s3_verify}") + verbose_logger.debug("s3_v2 logger - uploading data to s3 - %s", batch_logging_element.s3_object_key) + verbose_logger.debug("s3_v2 logger - s3_verify setting: %s", self.s3_verify) # Prepare the URL url = f"https://{self.s3_bucket_name}.s3.{self.s3_region_name}.amazonaws.com/{batch_logging_element.s3_object_key}" @@ -374,16 +374,19 @@ class S3Logger(CustomBatchLogger, BaseAWSLLM): if response.status_code in (500, 503) and attempt < max_retries - 1: wait_time = 2**attempt # 1s, 2s verbose_logger.warning( - f"S3 upload returned {response.status_code}, retrying in {wait_time}s " - f"(attempt {attempt + 1}/{max_retries}) " - f"key={batch_logging_element.s3_object_key}" + "S3 upload returned %s, retrying in %ss (attempt %s/%s) key=%s", + response.status_code, + wait_time, + attempt + 1, + max_retries, + batch_logging_element.s3_object_key, ) await asyncio.sleep(wait_time) continue response.raise_for_status() break except Exception as e: - verbose_logger.exception(f"Error uploading to s3: {e}") + verbose_logger.exception("Error uploading to s3: %s", e) self.handle_callback_failure(callback_name="S3Logger") async def async_send_batch(self): @@ -395,7 +398,7 @@ class S3Logger(CustomBatchLogger, BaseAWSLLM): Raises: Does not raise an exception, will only verbose_logger.exception() """ - verbose_logger.debug(f"s3_v2 logger - sending batch of {len(self.log_queue)}") + verbose_logger.debug("s3_v2 logger - sending batch of %s", len(self.log_queue)) if not self.log_queue: return @@ -447,7 +450,10 @@ class S3Logger(CustomBatchLogger, BaseAWSLLM): s3_file_name = litellm.utils.get_logging_id(start_time, standard_logging_payload) or "" verbose_logger.debug( - f"Creating s3 file with prefix_components={prefix_components},prefix_path={prefix_path} and {s3_file_name}" + "Creating s3 file with prefix_components=%s,prefix_path=%s and %s", + prefix_components, + prefix_path, + s3_file_name, ) s3_object_key = get_s3_object_key( s3_path=cast(str | None, self.s3_path) or "", @@ -455,7 +461,7 @@ class S3Logger(CustomBatchLogger, BaseAWSLLM): start_time=start_time, s3_file_name=s3_file_name, ) - verbose_logger.debug(f"s3_object_key={s3_object_key}") + verbose_logger.debug("s3_object_key=%s", s3_object_key) s3_object_download_filename = ( f"time-{start_time.strftime('%Y-%m-%dT%H-%M-%S-%f')}_{standard_logging_payload['id']}.json" @@ -479,7 +485,7 @@ class S3Logger(CustomBatchLogger, BaseAWSLLM): except ImportError: raise ImportError("Missing boto3 to call bedrock. Run 'pip install boto3'.") try: - verbose_logger.debug(f"s3_v2 logger - uploading data to s3 - {batch_logging_element.s3_object_key}") + verbose_logger.debug("s3_v2 logger - uploading data to s3 - %s", batch_logging_element.s3_object_key) credentials: Credentials = self.get_credentials( aws_access_key_id=self.s3_aws_access_key_id, aws_secret_access_key=self.s3_aws_secret_access_key, @@ -548,16 +554,19 @@ class S3Logger(CustomBatchLogger, BaseAWSLLM): if response.status_code in (500, 503) and attempt < max_retries - 1: wait_time = 2**attempt # 1s, 2s verbose_logger.warning( - f"S3 upload returned {response.status_code}, retrying in {wait_time}s " - f"(attempt {attempt + 1}/{max_retries}) " - f"key={batch_logging_element.s3_object_key}" + "S3 upload returned %s, retrying in %ss (attempt %s/%s) key=%s", + response.status_code, + wait_time, + attempt + 1, + max_retries, + batch_logging_element.s3_object_key, ) time.sleep(wait_time) continue response.raise_for_status() break except Exception as e: - verbose_logger.exception(f"Error uploading to s3: {e}") + verbose_logger.exception("Error uploading to s3: %s", e) self.handle_callback_failure(callback_name="S3Logger") async def _download_object_from_s3(self, s3_object_key: str) -> dict | None: @@ -596,7 +605,7 @@ class S3Logger(CustomBatchLogger, BaseAWSLLM): aws_sts_endpoint=self.s3_aws_sts_endpoint, ) - verbose_logger.debug(f"s3_v2 logger - downloading data from s3 - {s3_object_key}") + verbose_logger.debug("s3_v2 logger - downloading data from s3 - %s", s3_object_key) # Prepare the URL url = f"https://{self.s3_bucket_name}.s3.{self.s3_region_name}.amazonaws.com/{s3_object_key}" @@ -642,7 +651,7 @@ class S3Logger(CustomBatchLogger, BaseAWSLLM): return response.json() except Exception as e: - verbose_logger.exception(f"Error downloading from S3: {e}") + verbose_logger.exception("Error downloading from S3: %s", e) return None async def get_proxy_server_request_from_cold_storage_with_object_key( @@ -666,5 +675,5 @@ class S3Logger(CustomBatchLogger, BaseAWSLLM): downloaded_object = await self._download_object_from_s3(object_key) return downloaded_object except Exception as e: - verbose_logger.exception(f"Error retrieving object {object_key} from cold storage: {e}") + verbose_logger.exception("Error retrieving object %s from cold storage: %s", object_key, e) return None diff --git a/litellm/integrations/sqs.py b/litellm/integrations/sqs.py index 56618b62368..267bc0def22 100644 --- a/litellm/integrations/sqs.py +++ b/litellm/integrations/sqs.py @@ -68,7 +68,7 @@ class SQSLogger(CustomBatchLogger, BaseAWSLLM): **kwargs, ) -> None: try: - verbose_logger.debug(f"in init sqs logger - sqs_callback_params {litellm.aws_sqs_callback_params}") + verbose_logger.debug("in init sqs logger - sqs_callback_params %s", litellm.aws_sqs_callback_params) self.async_httpx_client = get_async_httpx_client( llm_provider=httpxSpecialProvider.LoggingCallback, @@ -100,7 +100,7 @@ class SQSLogger(CustomBatchLogger, BaseAWSLLM): asyncio.create_task(self.periodic_flush()) self.flush_lock = asyncio.Lock() - verbose_logger.debug(f"sqs flush interval: {sqs_flush_interval}, sqs batch size: {sqs_batch_size}") + verbose_logger.debug("sqs flush interval: %s, sqs batch size: %s", sqs_flush_interval, sqs_batch_size) CustomBatchLogger.__init__( self, @@ -215,7 +215,7 @@ class SQSLogger(CustomBatchLogger, BaseAWSLLM): self.batch_size, ) except Exception as e: - verbose_logger.exception(f"sqs Layer Error - {e}") + verbose_logger.exception("sqs Layer Error - %s", e) async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time): try: @@ -233,10 +233,10 @@ class SQSLogger(CustomBatchLogger, BaseAWSLLM): ) except Exception as e: - verbose_logger.exception(f"Datadog Layer Error - {e}\n{traceback.format_exc()}") + verbose_logger.exception("Datadog Layer Error - %s\n%s", e, traceback.format_exc()) async def async_send_batch(self) -> None: - verbose_logger.debug(f"sqs logger - sending batch of {len(self.log_queue)}") + verbose_logger.debug("sqs logger - sending batch of %s", len(self.log_queue)) if not self.log_queue: return @@ -305,7 +305,7 @@ class SQSLogger(CustomBatchLogger, BaseAWSLLM): ) response.raise_for_status() except Exception as e: - verbose_logger.exception(f"Error sending to SQS: {e}") + verbose_logger.exception("Error sending to SQS: %s", e) async def async_health_check(self) -> IntegrationHealthCheckStatus: """ diff --git a/litellm/integrations/traceloop.py b/litellm/integrations/traceloop.py index 77f20972f7a..f5d28fd369f 100644 --- a/litellm/integrations/traceloop.py +++ b/litellm/integrations/traceloop.py @@ -15,7 +15,9 @@ class TraceloopLogger: from traceloop.sdk.tracing.tracing import TracerWrapper except ModuleNotFoundError as e: verbose_logger.error( - f"Traceloop not installed, try running 'pip install traceloop-sdk' to fix this error: {e}\n{traceback.format_exc()}" + "Traceloop not installed, try running 'pip install traceloop-sdk' to fix this error: %s\n%s", + e, + traceback.format_exc(), ) raise e diff --git a/litellm/integrations/vector_store_integrations/vector_store_pre_call_hook.py b/litellm/integrations/vector_store_integrations/vector_store_pre_call_hook.py index 6eac7a27e73..2e533b488b6 100644 --- a/litellm/integrations/vector_store_integrations/vector_store_pre_call_hook.py +++ b/litellm/integrations/vector_store_integrations/vector_store_pre_call_hook.py @@ -124,7 +124,7 @@ class VectorStorePreCallHook(CustomLogger): }, ) - verbose_logger.debug(f"search_response: {search_response}") + verbose_logger.debug("search_response: %s", search_response) # Store search results for later use in citations all_search_results.append(search_response) @@ -137,7 +137,7 @@ class VectorStorePreCallHook(CustomLogger): # Get the number of results for logging num_results = 0 num_results = len(search_response.get("data", []) or []) - verbose_logger.debug(f"Vector store search completed. Added context from {num_results} results") + verbose_logger.debug("Vector store search completed. Added context from %s results", num_results) # Store search results as-is (already in OpenAI-compatible format) if litellm_logging_obj and all_search_results: @@ -146,7 +146,7 @@ class VectorStorePreCallHook(CustomLogger): return model, modified_messages, non_default_params except Exception as e: - verbose_logger.exception(f"Error in VectorStorePreCallHook: {e}") + verbose_logger.exception("Error in VectorStorePreCallHook: %s", e) # Return original parameters on error return model, messages, non_default_params @@ -243,14 +243,14 @@ class VectorStorePreCallHook(CustomLogger): verbose_logger.debug("No litellm_logging_obj in request_data") return None - verbose_logger.debug(f"model_call_details keys: {list(litellm_logging_obj.model_call_details.keys())}") + verbose_logger.debug("model_call_details keys: %s", list(litellm_logging_obj.model_call_details.keys())) # Get search results from model_call_details (already in OpenAI format) search_results: list[VectorStoreSearchResponse] | None = litellm_logging_obj.model_call_details.get( "search_results" ) - verbose_logger.debug(f"Search results found: {search_results is not None}") + verbose_logger.debug("Search results found: %s", search_results is not None) if not search_results: verbose_logger.debug("No search results found") @@ -269,13 +269,13 @@ class VectorStorePreCallHook(CustomLogger): # Set the provider_specific_fields setattr(choice.message, "provider_specific_fields", provider_fields) - verbose_logger.debug(f"Added {len(search_results)} search results to response") + verbose_logger.debug("Added %s search results to response", len(search_results)) # Return modified response return response except Exception as e: - verbose_logger.exception(f"Error adding search results to response: {e}") + verbose_logger.exception("Error adding search results to response: %s", e) # Don't fail the request if search results fail to be added return None @@ -297,7 +297,7 @@ class VectorStorePreCallHook(CustomLogger): # Get search results from model_call_details (already in OpenAI format) search_results: list[VectorStoreSearchResponse] | None = request_data.get("search_results") - verbose_logger.debug(f"Search results found for streaming chunk: {search_results is not None}") + verbose_logger.debug("Search results found for streaming chunk: %s", search_results is not None) if not search_results: verbose_logger.debug("No search results found for streaming chunk") @@ -316,12 +316,12 @@ class VectorStorePreCallHook(CustomLogger): # Set the provider_specific_fields choice.delta.provider_specific_fields = provider_fields - verbose_logger.debug(f"Added {len(search_results)} search results to streaming chunk") + verbose_logger.debug("Added %s search results to streaming chunk", len(search_results)) # Return modified chunk return response_chunk except Exception as e: - verbose_logger.exception(f"Error adding search results to streaming chunk: {e}") + verbose_logger.exception("Error adding search results to streaming chunk: %s", e) # Don't fail the request if search results fail to be added return response_chunk diff --git a/litellm/integrations/weave/weave_otel.py b/litellm/integrations/weave/weave_otel.py index 321dda2983d..ffa30582771 100644 --- a/litellm/integrations/weave/weave_otel.py +++ b/litellm/integrations/weave/weave_otel.py @@ -148,10 +148,10 @@ def get_weave_otel_config() -> WeaveOtelConfig: host = "https://" + host # Self-managed instances use a different path endpoint = host.rstrip("/") + WEAVE_OTEL_ENDPOINT - verbose_logger.debug(f"Using Weave OTEL endpoint from host: {endpoint}") + verbose_logger.debug("Using Weave OTEL endpoint from host: %s", endpoint) else: endpoint = WEAVE_BASE_URL + WEAVE_OTEL_ENDPOINT - verbose_logger.debug(f"Using Weave cloud endpoint: {endpoint}") + verbose_logger.debug("Using Weave cloud endpoint: %s", endpoint) # Weave uses Basic auth with format: api: auth_header = _get_weave_authorization_header(api_key=api_key) diff --git a/litellm/integrations/websearch_interception/handler.py b/litellm/integrations/websearch_interception/handler.py index 718f7b8fcd7..effc53d1c08 100644 --- a/litellm/integrations/websearch_interception/handler.py +++ b/litellm/integrations/websearch_interception/handler.py @@ -155,8 +155,8 @@ class WebSearchInterceptionLogger(CustomLogger): ) if anthropic_config is not None and anthropic_config.handles_web_search_natively(): verbose_logger.debug( - f"WebSearchInterception: Skipping short-circuit for {provider_str} " - "(provider handles web search natively via the agentic loop)" + "WebSearchInterception: Skipping short-circuit for %s (provider handles web search natively via the agentic loop)", + provider_str, ) return None except (ValueError, Exception): @@ -176,7 +176,7 @@ class WebSearchInterceptionLogger(CustomLogger): return None verbose_logger.debug( - f"WebSearchInterception: Short-circuit search detected (provider={provider_str}, query='{query}')" + "WebSearchInterception: Short-circuit search detected (provider=%s, query='%s')", provider_str, query ) # Native clients (Claude Desktop / Cowork / Anthropic SDK) make a @@ -198,7 +198,7 @@ class WebSearchInterceptionLogger(CustomLogger): else: search_result_text, structured = await self._execute_search(query, kwargs=kwargs) except Exception as e: - verbose_logger.error(f"WebSearchInterception: Short-circuit search failed: {e}") + verbose_logger.error("WebSearchInterception: Short-circuit search failed: %s", e) search_result_text, structured = f"Search failed: {e}", None content: list[dict[str, object]] = [] @@ -235,9 +235,9 @@ class WebSearchInterceptionLogger(CustomLogger): } verbose_logger.debug( - "WebSearchInterception: Short-circuit search completed, " - f"returning synthetic response ({len(search_result_text)} chars, " - f"native_blocks={native_tool is not None})" + "WebSearchInterception: Short-circuit search completed, returning synthetic response (%s chars, native_blocks=%s)", + len(search_result_text), + native_tool is not None, ) return response @@ -294,8 +294,10 @@ class WebSearchInterceptionLogger(CustomLogger): converted_tool = get_litellm_web_search_tool_openai() converted_tools.append(converted_tool) verbose_logger.debug( - f"WebSearchInterception: Converted {tool.get('name', 'unknown')} " - f"(type={tool.get('type', 'none')}) to {LITELLM_WEB_SEARCH_TOOL_NAME}" + "WebSearchInterception: Converted %s (type=%s) to %s", + tool.get("name", "unknown"), + tool.get("type", "none"), + LITELLM_WEB_SEARCH_TOOL_NAME, ) else: # Keep other tools as-is @@ -419,14 +421,14 @@ class WebSearchInterceptionLogger(CustomLogger): custom_llm_provider = kwargs.get("litellm_params", {}).get("custom_llm_provider", "") verbose_logger.debug( - f"WebSearchInterception: Pre-request hook called" - f" - custom_llm_provider={custom_llm_provider}" - f" - enabled_providers={self.enabled_providers or 'ALL'}" + "WebSearchInterception: Pre-request hook called - custom_llm_provider=%s - enabled_providers=%s", + custom_llm_provider, + self.enabled_providers or "ALL", ) if self.enabled_providers is not None and custom_llm_provider not in self.enabled_providers: verbose_logger.debug( - f"WebSearchInterception: Skipping - provider {custom_llm_provider} not in {self.enabled_providers}" + "WebSearchInterception: Skipping - provider %s not in %s", custom_llm_provider, self.enabled_providers ) return None @@ -440,7 +442,7 @@ class WebSearchInterceptionLogger(CustomLogger): if not has_websearch: return None - verbose_logger.debug(f"WebSearchInterception: Pre-request hook triggered for provider={custom_llm_provider}") + verbose_logger.debug("WebSearchInterception: Pre-request hook triggered for provider=%s", custom_llm_provider) # If the client sent an Anthropic-native web_search_* tool, mark the # request so the agentic loop emits native web_search_tool_result @@ -457,15 +459,17 @@ class WebSearchInterceptionLogger(CustomLogger): standard_tool = get_litellm_web_search_tool() converted_tools.append(standard_tool) verbose_logger.debug( - f"WebSearchInterception: Converted {tool.get('name', 'unknown')} " - f"(type={tool.get('type', 'none')}) to {LITELLM_WEB_SEARCH_TOOL_NAME}" + "WebSearchInterception: Converted %s (type=%s) to %s", + tool.get("name", "unknown"), + tool.get("type", "none"), + LITELLM_WEB_SEARCH_TOOL_NAME, ) else: converted_tools.append(tool) kwargs["tools"] = converted_tools verbose_logger.debug( - f"WebSearchInterception: Tools after conversion: {[t.get('name') for t in converted_tools]}" + "WebSearchInterception: Tools after conversion: %s", [t.get("name") for t in converted_tools] ) if "tool_choice" in kwargs: @@ -511,15 +515,17 @@ class WebSearchInterceptionLogger(CustomLogger): kwargs=kwargs, ) - verbose_logger.debug(f"WebSearchInterception: Hook called! provider={custom_llm_provider}, stream={stream}") - verbose_logger.debug(f"WebSearchInterception: Response type: {type(response)}") + verbose_logger.debug("WebSearchInterception: Hook called! provider=%s, stream=%s", custom_llm_provider, stream) + verbose_logger.debug("WebSearchInterception: Response type: %s", type(response)) # Check if provider should be intercepted # Note: custom_llm_provider is already normalized by get_llm_provider() # (e.g., "bedrock/invoke/..." -> "bedrock") if self.enabled_providers is not None and custom_llm_provider not in self.enabled_providers: verbose_logger.debug( - f"WebSearchInterception: Skipping provider {custom_llm_provider} (not in enabled list: {self.enabled_providers})" + "WebSearchInterception: Skipping provider %s (not in enabled list: %s)", + custom_llm_provider, + self.enabled_providers, ) return False, {} @@ -541,7 +547,7 @@ class WebSearchInterceptionLogger(CustomLogger): return False, {} verbose_logger.debug( - f"WebSearchInterception: Detected {len(tool_calls)} WebSearch tool call(s), executing agentic loop" + "WebSearchInterception: Detected %s WebSearch tool call(s), executing agentic loop", len(tool_calls) ) # Extract thinking blocks from response content. @@ -576,7 +582,7 @@ class WebSearchInterceptionLogger(CustomLogger): if thinking_blocks: verbose_logger.debug( - f"WebSearchInterception: Extracted {len(thinking_blocks)} thinking block(s) from response" + "WebSearchInterception: Extracted %s thinking block(s) from response", len(thinking_blocks) ) # Return tools dict with tool calls and thinking blocks @@ -606,14 +612,16 @@ class WebSearchInterceptionLogger(CustomLogger): """ verbose_logger.debug( - f"WebSearchInterception: Chat completion hook called! provider={custom_llm_provider}, stream={stream}" + "WebSearchInterception: Chat completion hook called! provider=%s, stream=%s", custom_llm_provider, stream ) - verbose_logger.debug(f"WebSearchInterception: Response type: {type(response)}") + verbose_logger.debug("WebSearchInterception: Response type: %s", type(response)) # Check if provider should be intercepted if self.enabled_providers is not None and custom_llm_provider not in self.enabled_providers: verbose_logger.debug( - f"WebSearchInterception: Skipping provider {custom_llm_provider} (not in enabled list: {self.enabled_providers})" + "WebSearchInterception: Skipping provider %s (not in enabled list: %s)", + custom_llm_provider, + self.enabled_providers, ) return False, {} @@ -635,7 +643,7 @@ class WebSearchInterceptionLogger(CustomLogger): return False, {} verbose_logger.debug( - f"WebSearchInterception: Detected {len(tool_calls)} WebSearch tool call(s), executing agentic loop" + "WebSearchInterception: Detected %s WebSearch tool call(s), executing agentic loop", len(tool_calls) ) # Return tools dict with tool calls @@ -659,12 +667,14 @@ class WebSearchInterceptionLogger(CustomLogger): ) -> tuple[bool, dict]: """Check if WebSearch interception is needed for the Responses API.""" verbose_logger.debug( - f"WebSearchInterception: Responses hook called! provider={custom_llm_provider}, stream={stream}" + "WebSearchInterception: Responses hook called! provider=%s, stream=%s", custom_llm_provider, stream ) if self.enabled_providers is not None and custom_llm_provider not in self.enabled_providers: verbose_logger.debug( - f"WebSearchInterception: Skipping provider {custom_llm_provider} (not in enabled list: {self.enabled_providers})" + "WebSearchInterception: Skipping provider %s (not in enabled list: %s)", + custom_llm_provider, + self.enabled_providers, ) return False, {} @@ -684,7 +694,7 @@ class WebSearchInterceptionLogger(CustomLogger): return False, {} verbose_logger.debug( - f"WebSearchInterception: Detected {len(tool_calls)} WebSearch function_call(s), executing agentic loop" + "WebSearchInterception: Detected %s WebSearch function_call(s), executing agentic loop", len(tool_calls) ) tools_dict = { @@ -716,7 +726,7 @@ class WebSearchInterceptionLogger(CustomLogger): tool_calls = tools["tool_calls"] thinking_blocks = tools.get("thinking_blocks", []) - verbose_logger.debug(f"WebSearchInterception: Executing agentic loop for {len(tool_calls)} search(es)") + verbose_logger.debug("WebSearchInterception: Executing agentic loop for %s search(es)", len(tool_calls)) return await self._execute_agentic_loop( model=model, @@ -853,7 +863,8 @@ class WebSearchInterceptionLogger(CustomLogger): # Object refused write — fall through and leave the response # untouched rather than crash the request. verbose_logger.debug( - f"WebSearchInterception: could not inject native blocks into response of type {type(response).__name__}" + "WebSearchInterception: could not inject native blocks into response of type %s", + type(response).__name__, ) return response @@ -878,7 +889,7 @@ class WebSearchInterceptionLogger(CustomLogger): response_format = tools.get("response_format", "openai") verbose_logger.debug( - f"WebSearchInterception: Executing chat completion agentic loop for {len(tool_calls)} search(es)" + "WebSearchInterception: Executing chat completion agentic loop for %s search(es)", len(tool_calls) ) return await self._execute_chat_completion_agentic_loop( @@ -962,7 +973,7 @@ class WebSearchInterceptionLogger(CustomLogger): for tool_call in tool_calls ] - verbose_logger.debug(f"WebSearchInterception: Executing {len(search_tasks)} responses search(es) in parallel") + verbose_logger.debug("WebSearchInterception: Executing %s responses search(es) in parallel", len(search_tasks)) search_results = await asyncio.gather(*search_tasks, return_exceptions=True) search_texts = [self._extract_search_text(result) for result in search_results] @@ -1038,12 +1049,12 @@ class WebSearchInterceptionLogger(CustomLogger): @staticmethod def _extract_search_text(result: object) -> str: if isinstance(result, Exception): - verbose_logger.error(f"WebSearchInterception: Responses search failed with error: {result}") + verbose_logger.error("WebSearchInterception: Responses search failed with error: %s", result) return f"Search failed: {result}" if isinstance(result, tuple) and len(result) == 2: text_value, _ = result return text_value if isinstance(text_value, str) else str(text_value) - verbose_logger.debug(f"WebSearchInterception: Unexpected search result type {type(result)}") + verbose_logger.debug("WebSearchInterception: Unexpected search result type %s", type(result)) return str(result) @staticmethod @@ -1176,15 +1187,15 @@ class WebSearchInterceptionLogger(CustomLogger): for tool_call in tool_calls: query = tool_call["input"].get("query") if query: - verbose_logger.debug(f"WebSearchInterception: Queuing search for query='{query}'") + verbose_logger.debug("WebSearchInterception: Queuing search for query='%s'", query) search_tasks.append(self._execute_search(query, kwargs=kwargs)) else: - verbose_logger.debug(f"WebSearchInterception: Tool call {tool_call['id']} has no query") + verbose_logger.debug("WebSearchInterception: Tool call %s has no query", tool_call["id"]) # Add empty result for tools without query search_tasks.append(self._create_empty_search_result()) # Execute searches in parallel - verbose_logger.debug(f"WebSearchInterception: Executing {len(search_tasks)} search(es) in parallel") + verbose_logger.debug("WebSearchInterception: Executing %s search(es) in parallel", len(search_tasks)) search_results = await asyncio.gather(*search_tasks, return_exceptions=True) # Split the gathered (text, structured) tuples into two parallel lists. @@ -1194,7 +1205,7 @@ class WebSearchInterceptionLogger(CustomLogger): structured_results: list[SearchResponse | None] = [] for i, result in enumerate(search_results): if isinstance(result, Exception): - verbose_logger.error(f"WebSearchInterception: Search {i} failed with error: {result}") + verbose_logger.error("WebSearchInterception: Search %s failed with error: %s", i, result) final_search_results.append(f"Search failed: {result}") structured_results.append(None) elif isinstance(result, tuple) and len(result) == 2: @@ -1204,7 +1215,7 @@ class WebSearchInterceptionLogger(CustomLogger): else: # Defensive: legacy callers / unexpected shape — preserve text, # drop structure. - verbose_logger.debug(f"WebSearchInterception: Unexpected result type {type(result)} at index {i}") + verbose_logger.debug("WebSearchInterception: Unexpected result type %s at index %s", type(result), i) final_search_results.append(str(result)) structured_results.append(None) @@ -1224,7 +1235,7 @@ class WebSearchInterceptionLogger(CustomLogger): max_tokens = self._resolve_max_tokens(anthropic_messages_optional_request_params, kwargs) - verbose_logger.debug(f"WebSearchInterception: Using max_tokens={max_tokens} for follow-up request") + verbose_logger.debug("WebSearchInterception: Using max_tokens=%s for follow-up request", max_tokens) optional_params_without_max_tokens = { k: v for k, v in anthropic_messages_optional_request_params.items() if k != "max_tokens" @@ -1286,12 +1297,12 @@ class WebSearchInterceptionLogger(CustomLogger): if not search_provider: search_provider = "perplexity" verbose_logger.debug( - "WebSearchInterception: No search tools configured in router, " - f"using default provider '{search_provider}'" + "WebSearchInterception: No search tools configured in router, using default provider '%s'", + search_provider, ) verbose_logger.debug( - f"WebSearchInterception: Executing search for '{query}' using provider '{search_provider}'" + "WebSearchInterception: Executing search for '%s' using provider '%s'", query, search_provider ) search_kwargs = { key: value @@ -1304,11 +1315,11 @@ class WebSearchInterceptionLogger(CustomLogger): search_result_text = WebSearchTransformation.format_search_response(result) verbose_logger.debug( - f"WebSearchInterception: Search completed for '{query}', got {len(search_result_text)} chars" + "WebSearchInterception: Search completed for '%s', got %s chars", query, len(search_result_text) ) return search_result_text, result except Exception as e: - verbose_logger.error(f"WebSearchInterception: Search failed for '{query}': {e}") + verbose_logger.error("WebSearchInterception: Search failed for '%s': %s", query, e) raise async def _authorize_search_tool( @@ -1392,21 +1403,25 @@ class WebSearchInterceptionLogger(CustomLogger): if matching_tools: search_provider = (matching_tools[0].get("litellm_params", {}) or {}).get("search_provider") verbose_logger.debug( - f"WebSearchInterception: Found search tool '{self.search_tool_name}' " - f"from {source} with provider '{search_provider}'" + "WebSearchInterception: Found search tool '%s' from %s with provider '%s'", + self.search_tool_name, + source, + search_provider, ) return matching_tools[0] verbose_logger.debug( - f"WebSearchInterception: Search tool '{self.search_tool_name}' not found in {source}, " - "falling back to first available or perplexity" + "WebSearchInterception: Search tool '%s' not found in %s, falling back to first available or perplexity", + self.search_tool_name, + source, ) if search_tools: first_tool = search_tools[0] search_provider = (first_tool.get("litellm_params", {}) or {}).get("search_provider") verbose_logger.debug( - f"WebSearchInterception: Using first available search tool from {source} " - f"with provider '{search_provider}'" + "WebSearchInterception: Using first available search tool from %s with provider '%s'", + source, + search_provider, ) return first_tool @@ -1470,15 +1485,15 @@ class WebSearchInterceptionLogger(CustomLogger): query = args.get("query") if query: - verbose_logger.debug(f"WebSearchInterception: Queuing search for query='{query}'") + verbose_logger.debug("WebSearchInterception: Queuing search for query='%s'", query) search_tasks.append(self._execute_search(query, kwargs=kwargs)) else: - verbose_logger.debug(f"WebSearchInterception: Tool call {tool_call.get('id')} has no query") + verbose_logger.debug("WebSearchInterception: Tool call %s has no query", tool_call.get("id")) # Add empty result for tools without query search_tasks.append(self._create_empty_search_result()) # Execute searches in parallel - verbose_logger.debug(f"WebSearchInterception: Executing {len(search_tasks)} search(es) in parallel") + verbose_logger.debug("WebSearchInterception: Executing %s search(es) in parallel", len(search_tasks)) search_results = await asyncio.gather(*search_tasks, return_exceptions=True) # Chat-completion path only needs text — OpenAI tool_result format @@ -1486,13 +1501,13 @@ class WebSearchInterceptionLogger(CustomLogger): final_search_results: list[str] = [] for i, result in enumerate(search_results): if isinstance(result, Exception): - verbose_logger.error(f"WebSearchInterception: Search {i} failed with error: {result}") + verbose_logger.error("WebSearchInterception: Search %s failed with error: %s", i, result) final_search_results.append(f"Search failed: {result}") elif isinstance(result, tuple) and len(result) == 2: text_value, _ = result final_search_results.append(cast(str, text_value) if isinstance(text_value, str) else str(text_value)) else: - verbose_logger.debug(f"WebSearchInterception: Unexpected result type {type(result)} at index {i}") + verbose_logger.debug("WebSearchInterception: Unexpected result type %s at index %s", type(result), i) final_search_results.append(str(result)) # Build assistant and tool messages using transformation @@ -1517,7 +1532,7 @@ class WebSearchInterceptionLogger(CustomLogger): ] verbose_logger.debug("WebSearchInterception: Making follow-up chat completion request with search results") - verbose_logger.debug(f"WebSearchInterception: Follow-up messages count: {len(follow_up_messages)}") + verbose_logger.debug("WebSearchInterception: Follow-up messages count: %s", len(follow_up_messages)) # Remove internal parameters that shouldn't be passed to follow-up request internal_params = { diff --git a/litellm/integrations/websearch_interception/transformation.py b/litellm/integrations/websearch_interception/transformation.py index 9dd0c155142..3b9683366be 100644 --- a/litellm/integrations/websearch_interception/transformation.py +++ b/litellm/integrations/websearch_interception/transformation.py @@ -103,7 +103,7 @@ class WebSearchTransformation: parsed_input = json.loads(arguments) if arguments else {} except json.JSONDecodeError: verbose_logger.warning( - f"WebSearchInterception: Failed to parse function_call arguments: {arguments}" + "WebSearchInterception: Failed to parse function_call arguments: %s", arguments ) parsed_input = {} elif isinstance(arguments, dict): @@ -122,7 +122,7 @@ class WebSearchTransformation: "input": parsed_input, } ) - verbose_logger.debug(f"WebSearchInterception: Found {item_name} function_call with call_id={call_id}") + verbose_logger.debug("WebSearchInterception: Found %s function_call with call_id=%s", item_name, call_id) return len(tool_calls) > 0, tool_calls @@ -178,7 +178,7 @@ class WebSearchTransformation: "input": block_input, } tool_calls.append(tool_call) - verbose_logger.debug(f"WebSearchInterception: Found {block_name} tool_use with id={tool_call['id']}") + verbose_logger.debug("WebSearchInterception: Found %s tool_use with id=%s", block_name, tool_call["id"]) return len(tool_calls) > 0, tool_calls @@ -255,7 +255,7 @@ class WebSearchTransformation: arguments = json.loads(function_arguments) except json.JSONDecodeError: verbose_logger.warning( - f"WebSearchInterception: Failed to parse function arguments: {function_arguments}" + "WebSearchInterception: Failed to parse function arguments: %s", function_arguments ) arguments = {} else: @@ -273,7 +273,7 @@ class WebSearchTransformation: "input": arguments, # For compatibility with Anthropic format } tool_calls.append(tool_call_dict) - verbose_logger.debug(f"WebSearchInterception: Found {function_name} tool_call with id={tool_id}") + verbose_logger.debug("WebSearchInterception: Found %s tool_call with id=%s", function_name, tool_id) return len(tool_calls) > 0, tool_calls diff --git a/litellm/integrations/weights_biases.py b/litellm/integrations/weights_biases.py index 0fe2a70ab66..0c1d28c23ef 100644 --- a/litellm/integrations/weights_biases.py +++ b/litellm/integrations/weights_biases.py @@ -42,9 +42,9 @@ try: elif response["object"] == "chat.completion": return self._resolve_chat_completion(request, response, time_elapsed) else: - logger.debug(f"Unknown OpenAI response object: {response['object']}") + logger.debug("Unknown OpenAI response object: %s", response["object"]) except Exception as e: - logger.warning(f"Failed to resolve request/response: {e}") + logger.warning("Failed to resolve request/response: %s", e) return None @staticmethod diff --git a/litellm/interactions/streaming_iterator.py b/litellm/interactions/streaming_iterator.py index f8ac4f25ebc..0fa6a5a7f75 100644 --- a/litellm/interactions/streaming_iterator.py +++ b/litellm/interactions/streaming_iterator.py @@ -109,7 +109,7 @@ class BaseInteractionsAPIStreamingIterator: return None except json.JSONDecodeError: # If we can't parse the chunk, continue - verbose_logger.debug(f"Failed to parse streaming chunk: {stripped_chunk[:200]}...") + verbose_logger.debug("Failed to parse streaming chunk: %s...", stripped_chunk[:200]) return None def _handle_logging_completed_response(self): diff --git a/litellm/litellm_core_utils/exception_mapping_utils.py b/litellm/litellm_core_utils/exception_mapping_utils.py index 101cbae23f9..75e9524e3f1 100644 --- a/litellm/litellm_core_utils/exception_mapping_utils.py +++ b/litellm/litellm_core_utils/exception_mapping_utils.py @@ -536,7 +536,7 @@ def _map_anthropic_exception( llm_provider="anthropic", ) if hasattr(original_exception, "status_code"): - verbose_logger.debug(f"status_code: {original_exception.status_code}") + verbose_logger.debug("status_code: %s", original_exception.status_code) if original_exception.status_code == 401: raise AuthenticationError( message=f"AnthropicException - {error_str}", @@ -1752,7 +1752,7 @@ def _map_aleph_alpha_exception( response=getattr(original_exception, "response", None), ) elif hasattr(original_exception, "status_code"): - verbose_logger.debug(f"status code: {original_exception.status_code}") + verbose_logger.debug("status code: %s", original_exception.status_code) if original_exception.status_code == 401: raise AuthenticationError( message=f"AlephAlphaException - {original_exception.message}", @@ -2526,7 +2526,9 @@ def exception_logging( model_call_details["exception"] = exception model_call_details["additional_args"] = additional_args # User Logging -> if you pass in a custom logging function or want to use sentry breadcrumbs - verbose_logger.debug(f"Logging Details: logger_fn - {logger_fn} | callable(logger_fn) - {callable(logger_fn)}") + verbose_logger.debug( + "Logging Details: logger_fn - %s | callable(logger_fn) - %s", logger_fn, callable(logger_fn) + ) if logger_fn and callable(logger_fn): try: logger_fn( @@ -2534,11 +2536,11 @@ def exception_logging( ) # Expectation: any logger function passed in by the user should accept a dict object except Exception: verbose_logger.debug( - f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging {traceback.format_exc()}" + "LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging %s", traceback.format_exc() ) except Exception: verbose_logger.debug( - f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging {traceback.format_exc()}" + "LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging %s", traceback.format_exc() ) diff --git a/litellm/litellm_core_utils/fallback_utils.py b/litellm/litellm_core_utils/fallback_utils.py index 4e7ce828a58..a40970a1234 100644 --- a/litellm/litellm_core_utils/fallback_utils.py +++ b/litellm/litellm_core_utils/fallback_utils.py @@ -70,7 +70,7 @@ async def async_completion_with_fallbacks(**kwargs): ) except Exception as e: - verbose_logger.exception(f"Fallback attempt failed for model {model}: {e}") + verbose_logger.exception("Fallback attempt failed for model %s: %s", model, e) most_recent_exception_str = str(e) continue diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index 66d82bd18f1..9052899059a 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -202,7 +202,7 @@ try: EnterpriseStandardLoggingPayloadSetup ) except Exception as e: - verbose_logger.debug(f"[Non-Blocking] Unable to import GenericAPILogger - LiteLLM Enterprise Feature - {e}") + verbose_logger.debug("[Non-Blocking] Unable to import GenericAPILogger - LiteLLM Enterprise Feature - %s", e) GenericAPILogger = CustomLogger # type: ignore ResendEmailLogger = CustomLogger # type: ignore SendGridEmailLogger = CustomLogger # type: ignore @@ -546,7 +546,7 @@ class Logging(LiteLLMLoggingBaseClass): self.litellm_request_debug = litellm_params.get("litellm_request_debug", False) self.logger_fn = litellm_params.get("logger_fn", None) if _is_debugging_on() or self.litellm_request_debug: - verbose_logger.debug(f"self.optional_params: {self.optional_params}") + verbose_logger.debug("self.optional_params: %s", self.optional_params) self.model_call_details.update( { @@ -981,7 +981,7 @@ class Logging(LiteLLMLoggingBaseClass): ) # Expectation: any logger function passed in by the user should accept a dict object except Exception as e: verbose_logger.exception( - f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging {e}" + "LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging %s", e ) self.model_call_details["api_call_start_time"] = datetime.datetime.now() @@ -1001,7 +1001,7 @@ class Logging(LiteLLMLoggingBaseClass): verbose_logger.debug("reaches supabase for logging!") model = self.model_call_details["model"] messages = self.model_call_details["input"] - verbose_logger.debug(f"supabaseClient: {supabaseClient}") + verbose_logger.debug("supabaseClient: %s", supabaseClient) supabaseClient.input_log_event( model=model, messages=messages, @@ -1041,15 +1041,15 @@ class Logging(LiteLLMLoggingBaseClass): callback_func=callback, ) except Exception as e: - verbose_logger.exception(f"litellm.Logging.pre_call(): Exception occured - {e}") + verbose_logger.exception("litellm.Logging.pre_call(): Exception occured - %s", e) verbose_logger.debug( - f"LiteLLM.Logging: is sentry capture exception initialized {capture_exception}" + "LiteLLM.Logging: is sentry capture exception initialized %s", capture_exception ) if capture_exception: # log this error to sentry for debugging capture_exception(e) except Exception as e: - verbose_logger.exception(f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging {e}") - verbose_logger.error(f"LiteLLM.Logging: is sentry capture exception initialized {capture_exception}") + verbose_logger.exception("LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging %s", e) + verbose_logger.error("LiteLLM.Logging: is sentry capture exception initialized %s", capture_exception) if capture_exception: # log this error to sentry for debugging capture_exception(e) @@ -1091,10 +1091,10 @@ class Logging(LiteLLMLoggingBaseClass): ) if self.litellm_request_debug: verbose_logger.warning( - f"\033[92m{curl_command}\033[0m\n" + "\x1b[92m%s\x1b[0m\n", curl_command ) # .warning ensures this shows up in all environments else: - verbose_logger.debug(f"\033[92m{curl_command}\033[0m\n") + verbose_logger.debug("\x1b[92m%s\x1b[0m\n", curl_command) def _get_request_body(self, data: dict) -> str: return str(data) @@ -1164,7 +1164,7 @@ class Logging(LiteLLMLoggingBaseClass): ) # Expectation: any logger function passed in by the user should accept a dict object except Exception as e: verbose_logger.exception( - f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging {e}" + "LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging %s", e ) original_response = redact_message_input_output_from_logging( model_call_details=(self.model_call_details if hasattr(self, "model_call_details") else {}), @@ -1201,15 +1201,16 @@ class Logging(LiteLLMLoggingBaseClass): ) except Exception as e: verbose_logger.exception( - f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while post-call logging with integrations {e}" + "LiteLLM.LoggingError: [Non-Blocking] Exception occurred while post-call logging with integrations %s", + e, ) verbose_logger.debug( - f"LiteLLM.Logging: is sentry capture exception initialized {capture_exception}" + "LiteLLM.Logging: is sentry capture exception initialized %s", capture_exception ) if capture_exception: # log this error to sentry for debugging capture_exception(e) except Exception as e: - verbose_logger.exception(f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging {e}") + verbose_logger.exception("LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging %s", e) async def async_post_mcp_tool_call_hook( self, @@ -1249,7 +1250,7 @@ class Logging(LiteLLMLoggingBaseClass): if response is not None: response_obj = self._parse_post_mcp_call_hook_response(response=response) except Exception as e: - verbose_logger.exception(f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging {e}") + verbose_logger.exception("LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging %s", e) return response_obj def _parse_post_mcp_call_hook_response(self, response: MCPPostCallResponseObject | None) -> Any: @@ -1433,14 +1434,14 @@ class Logging(LiteLLMLoggingBaseClass): error_str=str(e), traceback_str=_get_traceback_str_for_error(str(e)), ) - verbose_logger.debug(f"response_cost_failure_debug_information: {debug_info}") + verbose_logger.debug("response_cost_failure_debug_information: %s", debug_info) self.model_call_details["response_cost_failure_debug_information"] = debug_info return None try: response_cost = litellm.response_cost_calculator(**response_cost_calculator_kwargs) - verbose_logger.debug(f"response_cost: {response_cost}") + verbose_logger.debug("response_cost: %s", response_cost) additional_response_cost: object = self.model_call_details.get("additional_response_cost") if isinstance(additional_response_cost, (int, float)) and additional_response_cost > 0: return (response_cost or 0.0) + additional_response_cost @@ -1456,7 +1457,7 @@ class Logging(LiteLLMLoggingBaseClass): call_type=response_cost_calculator_kwargs["call_type"], custom_pricing=response_cost_calculator_kwargs["custom_pricing"], ) - verbose_logger.debug(f"response_cost_failure_debug_information: {debug_info}") + verbose_logger.debug("response_cost_failure_debug_information: %s", debug_info) self.model_call_details["response_cost_failure_debug_information"] = debug_info return None @@ -1491,7 +1492,7 @@ class Logging(LiteLLMLoggingBaseClass): raw_response=httpx.Response(status_code=200, headers={}), ) except Exception as e: # noqa: BLE001 - cost normalization must never break the response path - verbose_logger.debug(f"generate_content response cost normalization failed: {e}") + verbose_logger.debug("generate_content response cost normalization failed: %s", e) return None async def _response_cost_calculator_async( @@ -1660,7 +1661,7 @@ class Logging(LiteLLMLoggingBaseClass): # proxy cost tracking cal backs should run if not (isinstance(callback, CustomLogger) and "_PROXY_" in callback.__class__.__name__): - verbose_logger.debug(f"no-log request, skipping logging for {event_hook} event") + verbose_logger.debug("no-log request, skipping logging for %s event", event_hook) return False # Check for dynamically disabled callbacks via headers @@ -1670,7 +1671,7 @@ class Logging(LiteLLMLoggingBaseClass): standard_callback_dynamic_params=self.standard_callback_dynamic_params, ): verbose_logger.debug( - f"Callback {callback} disabled via x-litellm-disable-callbacks header for {event_hook} event" + "Callback %s disabled via x-litellm-disable-callbacks header for %s event", callback, event_hook ) return False @@ -1983,7 +1984,7 @@ class Logging(LiteLLMLoggingBaseClass): await self.async_success_handler(result=complete_streaming_response) def success_handler(self, result=None, start_time=None, end_time=None, cache_hit=None, **kwargs): - verbose_logger.debug(f"Logging Details LiteLLM-Success Call: Cache_hit={cache_hit}") + verbose_logger.debug("Logging Details LiteLLM-Success Call: Cache_hit=%s", cache_hit) if not self.should_run_logging(event_type="sync_success"): # prevent double logging return start_time, end_time, result = self._success_handler_helper_fn( @@ -2204,7 +2205,8 @@ class Logging(LiteLLMLoggingBaseClass): # this only logs streaming once, complete_streaming_response exists i.e when stream ends if self.stream: verbose_logger.debug( - f"is complete_streaming_response in kwargs: {kwargs.get('complete_streaming_response', None)}" + "is complete_streaming_response in kwargs: %s", + kwargs.get("complete_streaming_response", None), ) if complete_streaming_response is None: continue @@ -2241,7 +2243,8 @@ class Logging(LiteLLMLoggingBaseClass): # this only logs streaming once, complete_streaming_response exists i.e when stream ends if self.stream: verbose_logger.debug( - f"is complete_streaming_response in kwargs: {kwargs.get('complete_streaming_response', None)}" + "is complete_streaming_response in kwargs: %s", + kwargs.get("complete_streaming_response", None), ) if complete_streaming_response is None: continue @@ -2383,7 +2386,8 @@ class Logging(LiteLLMLoggingBaseClass): pass except Exception as e: verbose_logger.exception( - f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while success logging {e}", + "LiteLLM.LoggingError: [Non-Blocking] Exception occurred while success logging %s", + e, ) async def async_success_handler(self, result=None, start_time=None, end_time=None, cache_hit=None, **kwargs): @@ -2477,10 +2481,10 @@ class Logging(LiteLLMLoggingBaseClass): result=complete_streaming_response ) - verbose_logger.debug(f"Model={self.model}; cost={self.model_call_details['response_cost']}") + verbose_logger.debug("Model=%s; cost=%s", self.model, self.model_call_details["response_cost"]) except litellm.NotFoundError: verbose_logger.warning( - f"Model={self.model} not found in completion cost map. Setting 'response_cost' to None" + "Model=%s not found in completion cost map. Setting 'response_cost' to None", self.model ) self.model_call_details["response_cost"] = None @@ -2675,7 +2679,8 @@ class Logging(LiteLLMLoggingBaseClass): ) except Exception: verbose_logger.error( - f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while success logging {traceback.format_exc()}" + "LiteLLM.LoggingError: [Non-Blocking] Exception occurred while success logging %s", + traceback.format_exc(), ) self._handle_callback_failure(callback=callback) @@ -2699,7 +2704,7 @@ class Logging(LiteLLMLoggingBaseClass): break # Only increment once except Exception as e: - verbose_logger.debug(f"Error in _handle_callback_failure: {e}") + verbose_logger.debug("Error in _handle_callback_failure: %s", e) def _failure_handler_helper_fn(self, exception, traceback_exception, start_time=None, end_time=None): if start_time is None: @@ -2778,7 +2783,7 @@ class Logging(LiteLLMLoggingBaseClass): ) # type: ignore def failure_handler(self, exception, traceback_exception, start_time=None, end_time=None): - verbose_logger.debug(f"Logging Details LiteLLM-Failure Call: {litellm.failure_callback}") + verbose_logger.debug("Logging Details LiteLLM-Failure Call: %s", litellm.failure_callback) if not self.should_run_logging(event_type="sync_failure"): # prevent double logging return litellm_params = self.model_call_details.get("litellm_params", {}) @@ -2943,7 +2948,7 @@ class Logging(LiteLLMLoggingBaseClass): capture_exception(e) except Exception as e: verbose_logger.exception( - f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while failure logging {e}" + "LiteLLM.LoggingError: [Non-Blocking] Exception occurred while failure logging %s", e ) async def async_failure_handler(self, exception, traceback_exception, start_time=None, end_time=None): @@ -2999,8 +3004,9 @@ class Logging(LiteLLMLoggingBaseClass): ) except Exception as e: verbose_logger.exception( - f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while failure \ - logging {e}\nCallback={callback}" + "LiteLLM.LoggingError: [Non-Blocking] Exception occurred while failure logging %s\nCallback=%s", + e, + callback, ) # Track callback logging failures in Prometheus self._handle_callback_failure(callback=callback) @@ -3128,7 +3134,7 @@ class Logging(LiteLLMLoggingBaseClass): """ filtered = [cb for cb in callbacks if not self._is_internal_litellm_proxy_callback(cb)] - verbose_logger.debug(f"Filtered callbacks: {filtered}") + verbose_logger.debug("Filtered callbacks: %s", filtered) return filtered def _get_callback_name(self, cb) -> str: @@ -4143,7 +4149,7 @@ def _init_custom_logger_compatible_class( return newrelic_logger # type: ignore return None except Exception as e: - verbose_logger.exception(f"[Non-Blocking Error] Error initializing custom logger: {e}") + verbose_logger.exception("[Non-Blocking Error] Error initializing custom logger: %s", e) return None return None @@ -4427,7 +4433,7 @@ def get_custom_logger_compatible_class( return None except Exception as e: - verbose_logger.exception(f"[Non-Blocking Error] Error getting custom logger: {e}") + verbose_logger.exception("[Non-Blocking Error] Error getting custom logger: %s", e) return None @@ -4777,7 +4783,8 @@ class StandardLoggingPayloadSetup: ) except Exception: verbose_logger.debug( # keep in debug otherwise it will trigger on every call - f"Model={model_cost_name} is not mapped in model cost map. Defaulting to None model_cost_information for standard_logging_payload" + "Model=%s is not mapped in model cost map. Defaulting to None model_cost_information for standard_logging_payload", + model_cost_name, ) model_cost_information = StandardLoggingModelInformation( model_map_key=model_cost_name, model_map_value=None @@ -5431,7 +5438,7 @@ def get_standard_logging_object_payload( return payload except Exception as e: - verbose_logger.exception(f"Error creating standard logging object - {e}") + verbose_logger.exception("Error creating standard logging object - %s", e) return None diff --git a/litellm/litellm_core_utils/llm_cost_calc/utils.py b/litellm/litellm_core_utils/llm_cost_calc/utils.py index face1d1b49f..d392bb49258 100644 --- a/litellm/litellm_core_utils/llm_cost_calc/utils.py +++ b/litellm/litellm_core_utils/llm_cost_calc/utils.py @@ -150,7 +150,8 @@ def _generic_cost_per_character( prompt_cost = prompt_characters * custom_prompt_cost except Exception as e: verbose_logger.exception( - f"litellm.litellm_core_utils.llm_cost_calc.utils.py::cost_per_character(): Exception occured - {e}\nDefaulting to None" + "litellm.litellm_core_utils.llm_cost_calc.utils.py::cost_per_character(): Exception occured - %s\nDefaulting to None", + e, ) prompt_cost = None @@ -165,7 +166,8 @@ def _generic_cost_per_character( completion_cost = completion_characters * custom_completion_cost except Exception as e: verbose_logger.exception( - f"litellm.litellm_core_utils.llm_cost_calc.utils.py::cost_per_character(): Exception occured - {e}\nDefaulting to None" + "litellm.litellm_core_utils.llm_cost_calc.utils.py::cost_per_character(): Exception occured - %s\nDefaulting to None", + e, ) completion_cost = None @@ -388,7 +390,8 @@ def _get_cost_per_unit(model_info: ModelInfo, cost_key: str, default_value: floa return float(cost_per_unit) except ValueError: verbose_logger.exception( - f"litellm.litellm_core_utils.llm_cost_calc.utils.py::calculate_cost_per_component(): Exception occured - {cost_per_unit}\nDefaulting to 0.0" + "litellm.litellm_core_utils.llm_cost_calc.utils.py::calculate_cost_per_component(): Exception occured - %s\nDefaulting to 0.0", + cost_per_unit, ) # If the service tier key doesn't exist or is None, try to fall back to the standard key @@ -408,7 +411,8 @@ def _get_cost_per_unit(model_info: ModelInfo, cost_key: str, default_value: floa return float(fallback_cost) except ValueError: verbose_logger.exception( - f"litellm.litellm_core_utils.llm_cost_calc.utils.py::_get_cost_per_unit(): Exception occured - {fallback_cost}\nDefaulting to 0.0" + "litellm.litellm_core_utils.llm_cost_calc.utils.py::_get_cost_per_unit(): Exception occured - %s\nDefaulting to 0.0", + fallback_cost, ) break # Only try the first matching suffix diff --git a/litellm/litellm_core_utils/llm_response_utils/get_api_base.py b/litellm/litellm_core_utils/llm_response_utils/get_api_base.py index 1982e40448d..8eb8815b584 100644 --- a/litellm/litellm_core_utils/llm_response_utils/get_api_base.py +++ b/litellm/litellm_core_utils/llm_response_utils/get_api_base.py @@ -53,7 +53,7 @@ def get_api_base(model: str, optional_params: dict | LiteLLM_Params) -> str | No api_key=_optional_params.api_key, ) except Exception as e: - verbose_logger.debug(f"Error occurred in getting api base - {e}") + verbose_logger.debug("Error occurred in getting api base - %s", e) custom_llm_provider = None dynamic_api_base = None diff --git a/litellm/litellm_core_utils/logging_callback_manager.py b/litellm/litellm_core_utils/logging_callback_manager.py index be732adfbe1..8bbe9ff4d25 100644 --- a/litellm/litellm_core_utils/logging_callback_manager.py +++ b/litellm/litellm_core_utils/logging_callback_manager.py @@ -146,7 +146,7 @@ class LoggingCallbackManager: if callback not in parent_list: parent_list.append(callback) else: - verbose_logger.debug(f"Callback {callback} already exists in {parent_list}, not adding again..") + verbose_logger.debug("Callback %s already exists in %s, not adding again..", callback, parent_list) def _check_callback_list_size(self, parent_list: list[CustomLogger | Callable | str]) -> bool: """ @@ -155,7 +155,9 @@ class LoggingCallbackManager: """ if len(parent_list) >= MAX_CALLBACKS: verbose_logger.warning( - f"Cannot add callback - would exceed MAX_CALLBACKS limit of {MAX_CALLBACKS}. Current callbacks: {len(parent_list)}" + "Cannot add callback - would exceed MAX_CALLBACKS limit of %s. Current callbacks: %s", + MAX_CALLBACKS, + len(parent_list), ) return False return True @@ -281,7 +283,7 @@ class LoggingCallbackManager: parent_list.append(callback) else: verbose_logger.debug( - f"Callback function {callback.__name__} already exists in {parent_list}, not adding again.." + "Callback function %s already exists in %s, not adding again..", callback.__name__, parent_list ) def _add_custom_logger_to_list( @@ -301,7 +303,10 @@ class LoggingCallbackManager: and self._get_custom_logger_key(existing_logger) == custom_logger_key ): verbose_logger.debug( - f"Custom logger of type {custom_logger_type_name}, key: {custom_logger_key} already exists in {parent_list}, not adding again.." + "Custom logger of type %s, key: %s already exists in %s, not adding again..", + custom_logger_type_name, + custom_logger_key, + parent_list, ) return parent_list.append(custom_logger) diff --git a/litellm/litellm_core_utils/logging_utils.py b/litellm/litellm_core_utils/logging_utils.py index 9340554b6d9..99a9ae4861a 100644 --- a/litellm/litellm_core_utils/logging_utils.py +++ b/litellm/litellm_core_utils/logging_utils.py @@ -178,7 +178,7 @@ def _get_parent_otel_span_from_logging_obj( return _get_parent_otel_span_from_kwargs(logging_obj.model_call_details) except Exception as e: - verbose_logger.exception(f"Error in _get_parent_otel_span_from_logging_obj: {e}") + verbose_logger.exception("Error in _get_parent_otel_span_from_logging_obj: %s", e) return None @@ -265,7 +265,7 @@ def _set_duration_in_model_call_details( else: verbose_logger.debug("`logging_obj` not found - unable to track `llm_api_duration_ms") except Exception as e: - verbose_logger.warning(f"Error setting `llm_api_duration_ms`: {e}") + verbose_logger.warning("Error setting `llm_api_duration_ms`: %s", e) def track_llm_api_timing(): @@ -321,7 +321,7 @@ def track_llm_api_timing(): ) ) except Exception as e: - verbose_logger.debug(f"Error in service logging: {e}") + verbose_logger.debug("Error in service logging: %s", e) @functools.wraps(func) def sync_wrapper(*args, **kwargs): @@ -366,7 +366,7 @@ def track_llm_api_timing(): parent_otel_span=parent_otel_span, ) except Exception as e: - verbose_logger.debug(f"Error in service logging: {e}") + verbose_logger.debug("Error in service logging: %s", e) # Check if the function is async or sync if inspect.iscoroutinefunction(func): diff --git a/litellm/litellm_core_utils/logging_worker.py b/litellm/litellm_core_utils/logging_worker.py index b0d1de32c3c..ff588243621 100644 --- a/litellm/litellm_core_utils/logging_worker.py +++ b/litellm/litellm_core_utils/logging_worker.py @@ -100,7 +100,7 @@ class LoggingWorker: timeout=self.timeout, ) except Exception as e: - verbose_logger.exception(f"LoggingWorker error: {e}") + verbose_logger.exception("LoggingWorker error: %s", e) finally: self._queue.task_done() finally: @@ -297,7 +297,7 @@ class LoggingWorker: if extracted_tasks: await self._process_extracted_tasks(extracted_tasks) except Exception as e: - verbose_logger.exception(f"LoggingWorker error during aggressive clear: {e}") + verbose_logger.exception("LoggingWorker error during aggressive clear: %s", e) finally: # Always reset the flag even if an error occurs self._aggressive_clear_in_progress = False @@ -383,7 +383,7 @@ class LoggingWorker: for _ in range(MAX_ITERATIONS_TO_CLEAR_QUEUE): # Check if we've exceeded the maximum time if asyncio.get_event_loop().time() - start_time >= MAX_TIME_TO_CLEAR_QUEUE: - verbose_logger.warning(f"clear_queue exceeded max_time of {MAX_TIME_TO_CLEAR_QUEUE}s, stopping early") + verbose_logger.warning("clear_queue exceeded max_time of %ss, stopping early", MAX_TIME_TO_CLEAR_QUEUE) break try: diff --git a/litellm/litellm_core_utils/prompt_templates/factory.py b/litellm/litellm_core_utils/prompt_templates/factory.py index 8aa4f60b7c5..838261dedc8 100644 --- a/litellm/litellm_core_utils/prompt_templates/factory.py +++ b/litellm/litellm_core_utils/prompt_templates/factory.py @@ -1413,7 +1413,7 @@ def convert_to_gemini_tool_call_result( inline_data_list.append(BlobType(data=mime_rest[1], mime_type=clean_mime)) content_str = "" except Exception as e: - verbose_logger.warning(f"Failed to parse data URL in tool response: {e}") + verbose_logger.warning("Failed to parse data URL in tool response: %s", e) elif isinstance(message["content"], list): content_list = message["content"] for content in content_list: @@ -1432,7 +1432,7 @@ def convert_to_gemini_tool_call_result( ) ) except Exception as e: - verbose_logger.warning(f"Failed to process Anthropic image block in tool response: {e}") + verbose_logger.warning("Failed to process Anthropic image block in tool response: %s", e) elif content_type in ("input_image", "image_url"): # Extract image for inline_data (for Computer Use screenshots and tool results) image_url_data = content.get("image_url", "") @@ -1449,7 +1449,7 @@ def convert_to_gemini_tool_call_result( ) ) except Exception as e: - verbose_logger.warning(f"Failed to process image in tool response: {e}") + verbose_logger.warning("Failed to process image in tool response: %s", e) elif content_type in ("file", "input_file"): # Extract file for inline_data (for tool results with PDF, audio, video, etc.) file_data = content.get("file_data", "") @@ -1474,7 +1474,7 @@ def convert_to_gemini_tool_call_result( ) ) except Exception as e: - verbose_logger.warning(f"Failed to process file in tool response: {e}") + verbose_logger.warning("Failed to process file in tool response: %s", e) name: str | None = message.get("name", "") # type: ignore # Recover name from last message with tool calls @@ -1997,7 +1997,7 @@ def _sanitize_empty_text_content( message = cast(AllMessageValues, dict(message)) # Make a copy message["content"] = _EMPTY_TEXT_PLACEHOLDER verbose_logger.debug( - f"_sanitize_empty_text_content: Replaced empty text content in {message.get('role')} message" + "_sanitize_empty_text_content: Replaced empty text content in %s message", message.get("role") ) return message @@ -2022,7 +2022,7 @@ def _sanitize_empty_text_content( message = cast(AllMessageValues, dict(message)) # Make a copy message["content"] = new_blocks # type: ignore verbose_logger.debug( - f"_sanitize_empty_text_content: Replaced empty text block(s) in {message.get('role')} message" + "_sanitize_empty_text_content: Replaced empty text block(s) in %s message", message.get("role") ) return message @@ -2086,7 +2086,8 @@ def _add_missing_tool_results( if missing_tool_call_ids: verbose_logger.debug( - f"_add_missing_tool_results: Found {len(missing_tool_call_ids)} orphaned tool calls. Adding dummy tool results." + "_add_missing_tool_results: Found %s orphaned tool calls. Adding dummy tool results.", + len(missing_tool_call_ids), ) result_messages.append(current_message) diff --git a/litellm/litellm_core_utils/realtime_streaming.py b/litellm/litellm_core_utils/realtime_streaming.py index c401741f9dc..fd109d7cf3c 100644 --- a/litellm/litellm_core_utils/realtime_streaming.py +++ b/litellm/litellm_core_utils/realtime_streaming.py @@ -178,7 +178,7 @@ class RealTimeStreaming: # Catch-all base object so unknown/new event names never raise. typed_obj = OpenAIRealtimeStreamResponseBaseObject(**message_obj) # type: ignore except Exception as e: - verbose_logger.debug(f"Error parsing message for logging: {e}") + verbose_logger.debug("Error parsing message for logging: %s", e) self.messages.append(message_obj) # type: ignore[arg-type] return self.messages.append(typed_obj) @@ -213,7 +213,7 @@ class RealTimeStreaming: if tools and isinstance(tools, list): self.session_tools = tools # GA: session.type is required; log it for traceability but no action needed - verbose_logger.debug(f"Realtime session.type: {session.get('type')}") + verbose_logger.debug("Realtime session.type: %s", session.get("type")) if session.get("type") == "transcription": self._is_transcription_session = True except (json.JSONDecodeError, AttributeError, TypeError): @@ -981,7 +981,7 @@ class RealTimeStreaming: try: await self._handle_provider_config_message(raw_response) except Exception as e: - verbose_logger.exception(f"Error processing backend message, skipping: {e}") + verbose_logger.exception("Error processing backend message, skipping: %s", e) continue else: event = self._parse_backend_event(raw_response) @@ -1008,9 +1008,9 @@ class RealTimeStreaming: await self.websocket.send_text(json.dumps(translated)) except websockets.exceptions.ConnectionClosed as e: # type: ignore - verbose_logger.exception(f"Connection closed in backend to client send messages - {e}") + verbose_logger.exception("Connection closed in backend to client send messages - %s", e) except Exception as e: - verbose_logger.exception(f"Error in backend to client send messages: {e}") + verbose_logger.exception("Error in backend to client send messages: %s", e) finally: await self.log_messages() @@ -1404,7 +1404,7 @@ class RealTimeStreaming: self._guardrail_turn_detection_update_sent = True except Exception as e: - verbose_logger.debug(f"Error in client ack messages: {e}") + verbose_logger.debug("Error in client ack messages: %s", e) async def bidirectional_forward(self): forward_task = asyncio.create_task(self.backend_to_client_send_messages()) diff --git a/litellm/litellm_core_utils/streaming_handler.py b/litellm/litellm_core_utils/streaming_handler.py index 25155068baa..5cdb5877915 100644 --- a/litellm/litellm_core_utils/streaming_handler.py +++ b/litellm/litellm_core_utils/streaming_handler.py @@ -618,7 +618,7 @@ class CustomStreamWrapper: else: return "" except Exception as e: - verbose_logger.exception(f"litellm.CustomStreamWrapper.handle_baseten_chunk(): Exception occured - {e}") + verbose_logger.exception("litellm.CustomStreamWrapper.handle_baseten_chunk(): Exception occured - %s", e) return "" def handle_triton_stream(self, chunk): @@ -1430,7 +1430,7 @@ class CustomStreamWrapper: model_response.choices[0].delta = Delta(**_json_delta) except Exception as e: verbose_logger.exception( - f"litellm.CustomStreamWrapper.chunk_creator(): Exception occured - {e}" + "litellm.CustomStreamWrapper.chunk_creator(): Exception occured - %s", e ) model_response.choices[0].delta = Delta() elif self._has_any_special_delta_attributes(delta): @@ -1538,7 +1538,7 @@ class CustomStreamWrapper: except Exception as e: from litellm._logging import verbose_logger - verbose_logger.exception(f"Error in post-call streaming deployment hook: {e}") + verbose_logger.exception("Error in post-call streaming deployment hook: %s", e) return chunk def _add_mcp_list_tools_to_first_chunk(self, chunk: ModelResponseStream) -> ModelResponseStream: @@ -1578,7 +1578,7 @@ class CustomStreamWrapper: except Exception as e: from litellm._logging import verbose_logger - verbose_logger.exception(f"Error adding MCP list tools to first chunk: {e}") + verbose_logger.exception("Error adding MCP list tools to first chunk: %s", e) return chunk @@ -1615,7 +1615,7 @@ class CustomStreamWrapper: except Exception as e: from litellm._logging import verbose_logger - verbose_logger.exception(f"Error adding MCP metadata to final chunk: {e}") + verbose_logger.exception("Error adding MCP metadata to final chunk: %s", e) return chunk diff --git a/litellm/litellm_core_utils/token_counter.py b/litellm/litellm_core_utils/token_counter.py index ff94965f628..d65f70d5a7a 100644 --- a/litellm/litellm_core_utils/token_counter.py +++ b/litellm/litellm_core_utils/token_counter.py @@ -80,17 +80,20 @@ def get_modified_max_tokens( ) # give at least a 10 token buffer. token counting can be imprecise. input_tokens += int(token_buffer) - verbose_logger.debug(f"max_output_tokens: {max_output_tokens}, user_max_tokens: {user_max_tokens}") + verbose_logger.debug("max_output_tokens: %s, user_max_tokens: %s", max_output_tokens, user_max_tokens) ## CASE 1: model input + output can't exceed X - happens when max input = max output, e.g. gpt-3.5-turbo if _model_info["max_input_tokens"] == max_output_tokens: - verbose_logger.debug(f"input_tokens: {input_tokens}, max_output_tokens: {max_output_tokens}") + verbose_logger.debug("input_tokens: %s, max_output_tokens: %s", input_tokens, max_output_tokens) if input_tokens > max_output_tokens: pass # allow call to fail normally - don't set max_tokens to negative. elif ( user_max_tokens + input_tokens > max_output_tokens ): # we can still modify to keep it positive but below the limit verbose_logger.debug( - f"MODIFYING MAX TOKENS - user_max_tokens={user_max_tokens}, input_tokens={input_tokens}, max_output_tokens={max_output_tokens}" + "MODIFYING MAX TOKENS - user_max_tokens=%s, input_tokens=%s, max_output_tokens=%s", + user_max_tokens, + input_tokens, + max_output_tokens, ) user_max_tokens = int(max_output_tokens - input_tokens) ## CASE 2: user_max_tokens> model max output tokens @@ -98,13 +101,17 @@ def get_modified_max_tokens( user_max_tokens = max_output_tokens verbose_logger.debug( - f"litellm.litellm_core_utils.token_counter.py::get_modified_max_tokens() - user_max_tokens: {user_max_tokens}" + "litellm.litellm_core_utils.token_counter.py::get_modified_max_tokens() - user_max_tokens: %s", + user_max_tokens, ) return user_max_tokens except Exception as e: verbose_logger.debug( - f"litellm.litellm_core_utils.token_counter.py::get_modified_max_tokens() - Error while checking max token limit: {e}\nmodel={model}, base_model={base_model}" + "litellm.litellm_core_utils.token_counter.py::get_modified_max_tokens() - Error while checking max token limit: %s\nmodel=%s, base_model=%s", + e, + model, + base_model, ) return user_max_tokens @@ -280,7 +287,7 @@ def calculate_img_tokens( int: The number of tokens for the image. """ if use_default_image_token_count: - verbose_logger.debug(f"Using default image token count: {DEFAULT_IMAGE_TOKEN_COUNT}") + verbose_logger.debug("Using default image token count: %s", DEFAULT_IMAGE_TOKEN_COUNT) return DEFAULT_IMAGE_TOKEN_COUNT if mode == "low" or mode == "auto": return base_tokens @@ -367,7 +374,7 @@ def token_counter( if litellm.disable_token_counter is True: return 0 - verbose_logger.debug(f"messages in token_counter: {messages}, text in token_counter: {text}") + verbose_logger.debug("messages in token_counter: %s, text in token_counter: %s", messages, text) if text is not None and messages is not None: raise ValueError("text and messages cannot both be set") if use_default_image_token_count is None: diff --git a/litellm/llms/__init__.py b/litellm/llms/__init__.py index 60715ac9bbf..a35fe5b2093 100644 --- a/litellm/llms/__init__.py +++ b/litellm/llms/__init__.py @@ -92,7 +92,7 @@ def discover_guardrail_translation_mappings() -> dict[CallTypes, type["BaseTrans try: # Import the module - verbose_logger.debug(f"Discovering guardrail translations in: {module_path}") + verbose_logger.debug("Discovering guardrail translations in: %s", module_path) module = importlib.import_module(module_path) @@ -102,14 +102,14 @@ def discover_guardrail_translation_mappings() -> dict[CallTypes, type["BaseTrans if isinstance(mappings, dict): discovered_mappings.update(mappings) verbose_logger.debug( - f"Found guardrail_translation_mappings in {module_path}: {list(mappings.keys())}" + "Found guardrail_translation_mappings in %s: %s", module_path, list(mappings.keys()) ) except ImportError as e: - verbose_logger.error(f"Could not import {module_path}: {e}") + verbose_logger.error("Could not import %s: %s", module_path, e) continue except Exception as e: - verbose_logger.error(f"Error processing {module_path}: {e}") + verbose_logger.error("Error processing %s: %s", module_path, e) continue try: @@ -126,11 +126,13 @@ def discover_guardrail_translation_mappings() -> dict[CallTypes, type["BaseTrans verbose_logger.debug("MCP guardrail translation mappings not available; skipping") verbose_logger.debug( - f"Discovered {len(discovered_mappings)} guardrail translation mappings: {list(discovered_mappings.keys())}" + "Discovered %s guardrail translation mappings: %s", + len(discovered_mappings), + list(discovered_mappings.keys()), ) except Exception as e: - verbose_logger.error(f"Error discovering guardrail translation mappings: {e}") + verbose_logger.error("Error discovering guardrail translation mappings: %s", e) return discovered_mappings diff --git a/litellm/llms/anthropic/chat/guardrail_translation/handler.py b/litellm/llms/anthropic/chat/guardrail_translation/handler.py index 0fb7d7802a0..c752d02f662 100644 --- a/litellm/llms/anthropic/chat/guardrail_translation/handler.py +++ b/litellm/llms/anthropic/chat/guardrail_translation/handler.py @@ -825,10 +825,10 @@ class AnthropicMessagesHandler(BaseTranslation): if delta.get("type") == "text_delta": text += delta.get("text", "") except json.JSONDecodeError: - verbose_proxy_logger.warning(f"Failed to parse JSON from SSE data: {data_line}") + verbose_proxy_logger.warning("Failed to parse JSON from SSE data: %s", data_line) except Exception as e: - verbose_proxy_logger.error(f"Error extracting text from SSE: {e}") + verbose_proxy_logger.error("Error extracting text from SSE: %s", e) return text @@ -889,10 +889,10 @@ class AnthropicMessagesHandler(BaseTranslation): if stop_reason is not None: return True except json.JSONDecodeError: - verbose_proxy_logger.warning(f"Failed to parse JSON from SSE data: {data_line}") + verbose_proxy_logger.warning("Failed to parse JSON from SSE data: %s", data_line) except Exception as e: - verbose_proxy_logger.error(f"Error checking streaming end in SSE: {e}") + verbose_proxy_logger.error("Error checking streaming end in SSE: %s", e) # Handle already-parsed dict format elif isinstance(response, dict): diff --git a/litellm/llms/anthropic/count_tokens/handler.py b/litellm/llms/anthropic/count_tokens/handler.py index 0c3d0e931a2..3762b2b2f2f 100644 --- a/litellm/llms/anthropic/count_tokens/handler.py +++ b/litellm/llms/anthropic/count_tokens/handler.py @@ -54,7 +54,7 @@ class AnthropicCountTokensHandler(AnthropicCountTokensConfig): # Validate the request self.validate_request(model, messages) - verbose_logger.debug(f"Processing Anthropic CountTokens request for model: {model}") + verbose_logger.debug("Processing Anthropic CountTokens request for model: %s", model) # Transform request to Anthropic format request_body = self.transform_request_to_count_tokens( @@ -64,12 +64,12 @@ class AnthropicCountTokensHandler(AnthropicCountTokensConfig): system=system, ) - verbose_logger.debug(f"Transformed request: {request_body}") + verbose_logger.debug("Transformed request: %s", request_body) # Get endpoint URL endpoint_url = api_base or self.get_anthropic_count_tokens_endpoint() - verbose_logger.debug(f"Making request to: {endpoint_url}") + verbose_logger.debug("Making request to: %s", endpoint_url) # Get required headers headers = self.get_required_headers(api_key) @@ -87,11 +87,11 @@ class AnthropicCountTokensHandler(AnthropicCountTokensConfig): timeout=request_timeout, ) - verbose_logger.debug(f"Response status: {response.status_code}") + verbose_logger.debug("Response status: %s", response.status_code) if response.status_code != 200: error_text = response.text - verbose_logger.error(f"Anthropic API error: {error_text}") + verbose_logger.error("Anthropic API error: %s", error_text) raise AnthropicError( status_code=response.status_code, message=error_text, @@ -99,7 +99,7 @@ class AnthropicCountTokensHandler(AnthropicCountTokensConfig): anthropic_response = response.json() - verbose_logger.debug(f"Anthropic response: {anthropic_response}") + verbose_logger.debug("Anthropic response: %s", anthropic_response) # Return Anthropic response directly - no transformation needed return anthropic_response @@ -109,13 +109,13 @@ class AnthropicCountTokensHandler(AnthropicCountTokensConfig): raise except httpx.HTTPStatusError as e: # HTTP errors - preserve the actual status code - verbose_logger.error(f"HTTP error in CountTokens handler: {e}") + verbose_logger.error("HTTP error in CountTokens handler: %s", e) raise AnthropicError( status_code=e.response.status_code, message=e.response.text, ) except Exception as e: - verbose_logger.error(f"Error in CountTokens handler: {e}") + verbose_logger.error("Error in CountTokens handler: %s", e) raise AnthropicError( status_code=500, message=f"CountTokens processing error: {e}", diff --git a/litellm/llms/anthropic/count_tokens/token_counter.py b/litellm/llms/anthropic/count_tokens/token_counter.py index 8cc9d2ec0a9..5a2b6044528 100644 --- a/litellm/llms/anthropic/count_tokens/token_counter.py +++ b/litellm/llms/anthropic/count_tokens/token_counter.py @@ -81,7 +81,7 @@ class AnthropicTokenCounter(BaseTokenCounter): original_response=result, ) except AnthropicError as e: - verbose_logger.warning(f"Anthropic CountTokens API error: status={e.status_code}, message={e.message}") + verbose_logger.warning("Anthropic CountTokens API error: status=%s, message=%s", e.status_code, e.message) return TokenCountResponse( total_tokens=0, request_model=request_model, @@ -92,7 +92,7 @@ class AnthropicTokenCounter(BaseTokenCounter): status_code=e.status_code, ) except Exception as e: - verbose_logger.warning(f"Error calling Anthropic CountTokens API: {e}") + verbose_logger.warning("Error calling Anthropic CountTokens API: %s", e) return TokenCountResponse( total_tokens=0, request_model=request_model, diff --git a/litellm/llms/anthropic/experimental_pass_through/adapters/streaming_iterator.py b/litellm/llms/anthropic/experimental_pass_through/adapters/streaming_iterator.py index bb61043742d..5de40cc34b5 100644 --- a/litellm/llms/anthropic/experimental_pass_through/adapters/streaming_iterator.py +++ b/litellm/llms/anthropic/experimental_pass_through/adapters/streaming_iterator.py @@ -669,7 +669,7 @@ class AnthropicStreamWrapper(AdapterCompletionStreamWrapper): return {"type": "message_stop"} raise StopIteration except Exception as e: - verbose_logger.error(f"Anthropic Adapter - {e}\n{traceback.format_exc()}") + verbose_logger.error("Anthropic Adapter - %s\n%s", e, traceback.format_exc()) raise StopIteration async def __anext__(self): diff --git a/litellm/llms/anthropic/experimental_pass_through/context_management/editors/clear_tool_uses.py b/litellm/llms/anthropic/experimental_pass_through/context_management/editors/clear_tool_uses.py index abfc45859ef..b432b122504 100644 --- a/litellm/llms/anthropic/experimental_pass_through/context_management/editors/clear_tool_uses.py +++ b/litellm/llms/anthropic/experimental_pass_through/context_management/editors/clear_tool_uses.py @@ -68,8 +68,8 @@ def _trigger_met( messages=messages, tools=cast(Any, tools), ) - verbose_logger.debug(f"context_management polyfill: current_tokens: {current_tokens}") - verbose_logger.debug(f"context_management polyfill: threshold: {threshold}") + verbose_logger.debug("context_management polyfill: current_tokens: %s", current_tokens) + verbose_logger.debug("context_management polyfill: threshold: %s", threshold) return current_tokens > threshold, current_tokens diff --git a/litellm/llms/anthropic/experimental_pass_through/messages/mcp_handler.py b/litellm/llms/anthropic/experimental_pass_through/messages/mcp_handler.py index 887240bb1cc..74ee291bf9f 100644 --- a/litellm/llms/anthropic/experimental_pass_through/messages/mcp_handler.py +++ b/litellm/llms/anthropic/experimental_pass_through/messages/mcp_handler.py @@ -164,8 +164,9 @@ async def anthropic_messages_with_mcp( response = await litellm.anthropic_messages(messages=list(working_messages), stream=False, **base_call_args) else: verbose_logger.warning( - f"MCP tool loop hit its {MAX_MCP_TOOL_USE_ITERATIONS} iteration cap for model {model}; " - "returning the last response" + "MCP tool loop hit its %s iteration cap for model %s; returning the last response", + MAX_MCP_TOOL_USE_ITERATIONS, + model, ) if stream: diff --git a/litellm/llms/anthropic/experimental_pass_through/responses_adapters/streaming_iterator.py b/litellm/llms/anthropic/experimental_pass_through/responses_adapters/streaming_iterator.py index f698c78604d..251c4e0f61a 100644 --- a/litellm/llms/anthropic/experimental_pass_through/responses_adapters/streaming_iterator.py +++ b/litellm/llms/anthropic/experimental_pass_through/responses_adapters/streaming_iterator.py @@ -300,7 +300,7 @@ class AnthropicResponsesStreamWrapper: except StopAsyncIteration: pass except Exception as e: - verbose_logger.error(f"AnthropicResponsesStreamWrapper error: {e}\n{traceback.format_exc()}") + verbose_logger.error("AnthropicResponsesStreamWrapper error: %s\n%s", e, traceback.format_exc()) # Drain any remaining queued chunks if self._chunk_queue: diff --git a/litellm/llms/anthropic/files/handler.py b/litellm/llms/anthropic/files/handler.py index b911347b2ff..c05392e0d7c 100644 --- a/litellm/llms/anthropic/files/handler.py +++ b/litellm/llms/anthropic/files/handler.py @@ -270,7 +270,7 @@ class AnthropicFilesHandler: transformed_content += "\n" # Add trailing newline for JSONL format return transformed_content.encode("utf-8") except Exception as e: - verbose_logger.error(f"Error transforming Anthropic batch results to OpenAI format: {e}") + verbose_logger.error("Error transforming Anthropic batch results to OpenAI format: %s", e) # Return original content if transformation fails return anthropic_content @@ -330,7 +330,7 @@ class AnthropicFilesHandler: return openai_body except Exception as e: - verbose_logger.error(f"Error transforming Anthropic message to OpenAI format: {e}") + verbose_logger.error("Error transforming Anthropic message to OpenAI format: %s", e) # Return a basic error response if transformation fails error_response: OpenAIChatCompletionResponse = { "id": anthropic_message.get("id", ""), diff --git a/litellm/llms/azure/chat/o_series_transformation.py b/litellm/llms/azure/chat/o_series_transformation.py index 2b8c2e88e51..86944c3b2c2 100644 --- a/litellm/llms/azure/chat/o_series_transformation.py +++ b/litellm/llms/azure/chat/o_series_transformation.py @@ -91,7 +91,7 @@ class AzureOpenAIO1Config(OpenAIOSeriesConfig): ): # allow user to override default with model_info={"supports_native_streaming": true} return False except Exception as e: - verbose_logger.debug(f"Error getting model info in AzureOpenAIO1Config: {e}") + verbose_logger.debug("Error getting model info in AzureOpenAIO1Config: %s", e) return True def is_o_series_model(self, model: str) -> bool: diff --git a/litellm/llms/azure/common_utils.py b/litellm/llms/azure/common_utils.py index 8db422e00ff..45f683d5962 100644 --- a/litellm/llms/azure/common_utils.py +++ b/litellm/llms/azure/common_utils.py @@ -333,7 +333,8 @@ def get_azure_ad_token( verbose_logger.debug("Azure AD Token Provider could not be used.") except Exception as e: verbose_logger.error( - f"Error calling Azure AD token provider: {e}. Follow docs - https://docs.litellm.ai/docs/providers/azure/#azure-ad-token-refresh---defaultazurecredential" + "Error calling Azure AD token provider: %s. Follow docs - https://docs.litellm.ai/docs/providers/azure/#azure-ad-token-refresh---defaultazurecredential", + e, ) raise e @@ -351,7 +352,7 @@ def get_azure_ad_token( try: token = azure_ad_token_provider() if not isinstance(token, str): - verbose_logger.error(f"Azure AD token provider returned non-string value: {type(token)}") + verbose_logger.error("Azure AD token provider returned non-string value: %s", type(token)) raise TypeError(f"Azure AD token must be a string, got {type(token)}") else: azure_ad_token = token @@ -359,7 +360,7 @@ def get_azure_ad_token( # Re-raise TypeError directly raise except Exception as e: - verbose_logger.error(f"Error calling Azure AD token provider: {e}") + verbose_logger.error("Error calling Azure AD token provider: %s", e) raise RuntimeError(f"Failed to get Azure AD token: {e}") from e return azure_ad_token @@ -393,7 +394,7 @@ class BaseAzureLLM(BaseOpenAILLM): verbose_logger.debug("Successfully obtained Azure AD token provider using DefaultAzureCredential") return azure_ad_token_provider except Exception as e: - verbose_logger.debug(f"DefaultAzureCredential failed: {e}") + verbose_logger.debug("DefaultAzureCredential failed: %s", e) return None def get_azure_openai_client( @@ -481,7 +482,7 @@ class BaseAzureLLM(BaseOpenAILLM): if "http_client" in azure_client_params: v1_params["http_client"] = azure_client_params["http_client"] - verbose_logger.debug(f"Using Azure v1 API with base_url: {v1_params['base_url']}") + verbose_logger.debug("Using Azure v1 API with base_url: %s", v1_params["base_url"]) if _is_async is True: openai_client = AsyncOpenAI(**v1_params) # type: ignore @@ -582,7 +583,7 @@ class BaseAzureLLM(BaseOpenAILLM): # only show first 5 chars of api_key _api_key = _api_key[:8] + "*" * 15 verbose_logger.debug( - f"Initializing Azure OpenAI Client for {model_name}, Api Base: {api_base}, Api Key:{_api_key}" + "Initializing Azure OpenAI Client for %s, Api Base: %s, Api Key:%s", model_name, api_base, _api_key ) azure_client_params = { "api_key": api_key, diff --git a/litellm/llms/azure/cost_calculation.py b/litellm/llms/azure/cost_calculation.py index 6fddb8523e7..ab4307f9172 100644 --- a/litellm/llms/azure/cost_calculation.py +++ b/litellm/llms/azure/cost_calculation.py @@ -35,7 +35,10 @@ def cost_per_token( and response_time_ms is not None ): verbose_logger.debug( - f"For model={model} - output_cost_per_second: {model_info.get('output_cost_per_second')}; response time: {response_time_ms}" + "For model=%s - output_cost_per_second: %s; response time: %s", + model, + model_info.get("output_cost_per_second"), + response_time_ms, ) ## COST PER SECOND ## prompt_cost = 0.0 diff --git a/litellm/llms/azure/image_generation/__init__.py b/litellm/llms/azure/image_generation/__init__.py index 64636bc689d..a2a905f2287 100644 --- a/litellm/llms/azure/image_generation/__init__.py +++ b/litellm/llms/azure/image_generation/__init__.py @@ -29,6 +29,6 @@ def get_azure_image_generation_config(model: str) -> BaseImageGenerationConfig: return AzureFoundryMAIImageGenerationConfig() else: verbose_logger.debug( - f"Using AzureGPTImageGenerationConfig for model: {model}. This follows the gpt-image model format." + "Using AzureGPTImageGenerationConfig for model: %s. This follows the gpt-image model format.", model ) return AzureGPTImageGenerationConfig() diff --git a/litellm/llms/azure/responses/o_series_transformation.py b/litellm/llms/azure/responses/o_series_transformation.py index 7a88c42cb14..121ceda7fa1 100644 --- a/litellm/llms/azure/responses/o_series_transformation.py +++ b/litellm/llms/azure/responses/o_series_transformation.py @@ -68,7 +68,7 @@ class AzureOpenAIOSeriesResponsesAPIConfig(AzureOpenAIResponsesAPIConfig): # If drop_params is enabled, remove temperature parameter for O-series models if drop_params and "temperature" in mapped_params: verbose_logger.debug( - f"Dropping unsupported parameter 'temperature' for Azure OpenAI O-series responses API model {model}" + "Dropping unsupported parameter 'temperature' for Azure OpenAI O-series responses API model %s", model ) mapped_params.pop("temperature", None) diff --git a/litellm/llms/azure/responses/transformation.py b/litellm/llms/azure/responses/transformation.py index 860b1b1dd5c..51b63b6299c 100644 --- a/litellm/llms/azure/responses/transformation.py +++ b/litellm/llms/azure/responses/transformation.py @@ -74,7 +74,7 @@ class AzureOpenAIResponsesAPIConfig(OpenAIResponsesAPIConfig): return dict_reasoning_item except Exception as e: - verbose_logger.debug(f"Failed to create ResponseReasoningItem, falling back to manual filtering: {e}") + verbose_logger.debug("Failed to create ResponseReasoningItem, falling back to manual filtering: %s", e) # Fallback: manually filter out known None fields filtered_item = { k: v @@ -252,7 +252,7 @@ class AzureOpenAIResponsesAPIConfig(OpenAIResponsesAPIConfig): delete_url = self._construct_url_for_response_id_in_path(api_base=api_base, response_id=response_id) data: dict = {} - verbose_logger.debug(f"delete response url={delete_url}") + verbose_logger.debug("delete response url=%s", delete_url) return delete_url, data ######################################################### @@ -273,7 +273,7 @@ class AzureOpenAIResponsesAPIConfig(OpenAIResponsesAPIConfig): """ get_url = self._construct_url_for_response_id_in_path(api_base=api_base, response_id=response_id) data: dict = {} - verbose_logger.debug(f"get response url={get_url}") + verbose_logger.debug("get response url=%s", get_url) return get_url, data def transform_list_input_items_request( @@ -302,7 +302,7 @@ class AzureOpenAIResponsesAPIConfig(OpenAIResponsesAPIConfig): params["limit"] = limit if order is not None: params["order"] = order - verbose_logger.debug(f"list input items url={url}") + verbose_logger.debug("list input items url=%s", url) return url, params ######################################################### @@ -329,7 +329,7 @@ class AzureOpenAIResponsesAPIConfig(OpenAIResponsesAPIConfig): ) data: dict = {} - verbose_logger.debug(f"cancel response url={cancel_url}") + verbose_logger.debug("cancel response url=%s", cancel_url) return cancel_url, data def transform_cancel_response_api_response( diff --git a/litellm/llms/azure_ai/agents/handler.py b/litellm/llms/azure_ai/agents/handler.py index 7023dbca0b8..81532aed208 100644 --- a/litellm/llms/azure_ai/agents/handler.py +++ b/litellm/llms/azure_ai/agents/handler.py @@ -193,7 +193,7 @@ class AzureAIAgentsHandler: ), ) except Exception as e: - verbose_logger.warning(f"Failed to calculate token usage: {e}") + verbose_logger.warning("Failed to calculate token usage: %s", e) return model_response @@ -226,7 +226,7 @@ class AzureAIAgentsHandler: thread_id = optional_params.get("thread_id") api_base = api_base.rstrip("/") - verbose_logger.debug(f"Azure AI Agents completion - api_base: {api_base}, agent_id: {agent_id}") + verbose_logger.debug("Azure AI Agents completion - api_base: %s, agent_id: %s", api_base, agent_id) return headers, api_version, agent_id, thread_id, api_base @@ -305,11 +305,11 @@ class AzureAIAgentsHandler: # Step 1: Create thread if not provided if not thread_id: - verbose_logger.debug(f"Creating thread at: {self._build_thread_url(api_base, api_version)}") + verbose_logger.debug("Creating thread at: %s", self._build_thread_url(api_base, api_version)) response = make_request("POST", self._build_thread_url(api_base, api_version), {}) self._check_response(response, [200, 201], "Failed to create thread") thread_id = response.json()["id"] - verbose_logger.debug(f"Created thread: {thread_id}") + verbose_logger.debug("Created thread: %s", thread_id) # At this point thread_id is guaranteed to be a string assert thread_id is not None @@ -329,7 +329,7 @@ class AzureAIAgentsHandler: response = make_request("POST", self._build_runs_url(api_base, thread_id, api_version), run_payload) self._check_response(response, [200, 201], "Failed to create run") run_id = response.json()["id"] - verbose_logger.debug(f"Created run: {run_id}") + verbose_logger.debug("Created run: %s", run_id) # Step 4: Poll for completion status_url = self._build_run_status_url(api_base, thread_id, run_id, api_version) @@ -338,7 +338,7 @@ class AzureAIAgentsHandler: self._check_response(response, [200], "Failed to get run status") status = response.json().get("status") - verbose_logger.debug(f"Run status: {status}") + verbose_logger.debug("Run status: %s", status) if status == "completed": break @@ -428,11 +428,11 @@ class AzureAIAgentsHandler: # Step 1: Create thread if not provided if not thread_id: - verbose_logger.debug(f"Creating thread at: {self._build_thread_url(api_base, api_version)}") + verbose_logger.debug("Creating thread at: %s", self._build_thread_url(api_base, api_version)) response = await make_request("POST", self._build_thread_url(api_base, api_version), {}) self._check_response(response, [200, 201], "Failed to create thread") thread_id = response.json()["id"] - verbose_logger.debug(f"Created thread: {thread_id}") + verbose_logger.debug("Created thread: %s", thread_id) # At this point thread_id is guaranteed to be a string assert thread_id is not None @@ -452,7 +452,7 @@ class AzureAIAgentsHandler: response = await make_request("POST", self._build_runs_url(api_base, thread_id, api_version), run_payload) self._check_response(response, [200, 201], "Failed to create run") run_id = response.json()["id"] - verbose_logger.debug(f"Created run: {run_id}") + verbose_logger.debug("Created run: %s", run_id) # Step 4: Poll for completion status_url = self._build_run_status_url(api_base, thread_id, run_id, api_version) @@ -461,7 +461,7 @@ class AzureAIAgentsHandler: self._check_response(response, [200], "Failed to get run status") status = response.json().get("status") - verbose_logger.debug(f"Run status: {status}") + verbose_logger.debug("Run status: %s", status) if status == "completed": break @@ -526,7 +526,7 @@ class AzureAIAgentsHandler: payload["instructions"] = optional_params["instructions"] url = self._build_create_thread_and_run_url(api_base, api_version) - verbose_logger.debug(f"Azure AI Agents streaming - URL: {url}") + verbose_logger.debug("Azure AI Agents streaming - URL: %s", url) # Use LiteLLM's async HTTP client for streaming client = get_async_httpx_client( @@ -607,7 +607,7 @@ class AzureAIAgentsHandler: # Extract thread_id from thread.created event if current_event == "thread.created" and "id" in data: thread_id = data["id"] - verbose_logger.debug(f"Stream created thread: {thread_id}") + verbose_logger.debug("Stream created thread: %s", thread_id) # Extract annotations from completed message if current_event == "thread.message.completed": diff --git a/litellm/llms/azure_ai/agents/transformation.py b/litellm/llms/azure_ai/agents/transformation.py index fb18b0cb651..7b6c8f0eefb 100644 --- a/litellm/llms/azure_ai/agents/transformation.py +++ b/litellm/llms/azure_ai/agents/transformation.py @@ -229,7 +229,7 @@ class AzureAIAgentsConfig(BaseConfig): if "instructions" in optional_params: payload["instructions"] = optional_params["instructions"] - verbose_logger.debug(f"Azure AI Agents request payload: {payload}") + verbose_logger.debug("Azure AI Agents request payload: %s", payload) return payload def validate_environment( diff --git a/litellm/llms/azure_ai/anthropic/count_tokens/handler.py b/litellm/llms/azure_ai/anthropic/count_tokens/handler.py index 65d8c0182ee..fca2244265b 100644 --- a/litellm/llms/azure_ai/anthropic/count_tokens/handler.py +++ b/litellm/llms/azure_ai/anthropic/count_tokens/handler.py @@ -56,7 +56,7 @@ class AzureAIAnthropicCountTokensHandler(AzureAIAnthropicCountTokensConfig): # Validate the request self.validate_request(model, messages) - verbose_logger.debug(f"Processing Azure AI Anthropic CountTokens request for model: {model}") + verbose_logger.debug("Processing Azure AI Anthropic CountTokens request for model: %s", model) # Transform request to Anthropic format request_body = self.transform_request_to_count_tokens( @@ -66,12 +66,12 @@ class AzureAIAnthropicCountTokensHandler(AzureAIAnthropicCountTokensConfig): system=system, ) - verbose_logger.debug(f"Transformed request: {request_body}") + verbose_logger.debug("Transformed request: %s", request_body) # Get endpoint URL endpoint_url = self.get_count_tokens_endpoint(api_base) - verbose_logger.debug(f"Making request to: {endpoint_url}") + verbose_logger.debug("Making request to: %s", endpoint_url) # Get required headers with Azure authentication headers = self.get_required_headers( @@ -92,11 +92,11 @@ class AzureAIAnthropicCountTokensHandler(AzureAIAnthropicCountTokensConfig): timeout=request_timeout, ) - verbose_logger.debug(f"Response status: {response.status_code}") + verbose_logger.debug("Response status: %s", response.status_code) if response.status_code != 200: error_text = response.text - verbose_logger.error(f"Azure AI Anthropic API error: {error_text}") + verbose_logger.error("Azure AI Anthropic API error: %s", error_text) raise AnthropicError( status_code=response.status_code, message=error_text, @@ -104,7 +104,7 @@ class AzureAIAnthropicCountTokensHandler(AzureAIAnthropicCountTokensConfig): azure_response = response.json() - verbose_logger.debug(f"Azure AI Anthropic response: {azure_response}") + verbose_logger.debug("Azure AI Anthropic response: %s", azure_response) # Return Anthropic-compatible response directly - no transformation needed return azure_response @@ -114,13 +114,13 @@ class AzureAIAnthropicCountTokensHandler(AzureAIAnthropicCountTokensConfig): raise except httpx.HTTPStatusError as e: # HTTP errors - preserve the actual status code - verbose_logger.error(f"HTTP error in CountTokens handler: {e}") + verbose_logger.error("HTTP error in CountTokens handler: %s", e) raise AnthropicError( status_code=e.response.status_code, message=e.response.text, ) except Exception as e: - verbose_logger.error(f"Error in CountTokens handler: {e}") + verbose_logger.error("Error in CountTokens handler: %s", e) raise AnthropicError( status_code=500, message=f"CountTokens processing error: {e}", diff --git a/litellm/llms/azure_ai/anthropic/count_tokens/token_counter.py b/litellm/llms/azure_ai/anthropic/count_tokens/token_counter.py index 129d7bb7aa9..277c07584ed 100644 --- a/litellm/llms/azure_ai/anthropic/count_tokens/token_counter.py +++ b/litellm/llms/azure_ai/anthropic/count_tokens/token_counter.py @@ -95,7 +95,7 @@ class AzureAIAnthropicTokenCounter(BaseTokenCounter): ) except AnthropicError as e: verbose_logger.warning( - f"Azure AI Anthropic CountTokens API error: status={e.status_code}, message={e.message}" + "Azure AI Anthropic CountTokens API error: status=%s, message=%s", e.status_code, e.message ) return TokenCountResponse( total_tokens=0, @@ -107,7 +107,7 @@ class AzureAIAnthropicTokenCounter(BaseTokenCounter): status_code=e.status_code, ) except Exception as e: - verbose_logger.warning(f"Error calling Azure AI Anthropic CountTokens API: {e}") + verbose_logger.warning("Error calling Azure AI Anthropic CountTokens API: %s", e) return TokenCountResponse( total_tokens=0, request_model=request_model, diff --git a/litellm/llms/azure_ai/chat/transformation.py b/litellm/llms/azure_ai/chat/transformation.py index 707ddc9e12b..083bed024f7 100644 --- a/litellm/llms/azure_ai/chat/transformation.py +++ b/litellm/llms/azure_ai/chat/transformation.py @@ -206,7 +206,7 @@ class AzureAIStudioConfig(OpenAIConfig): dynamic_api_key = api_key or get_secret_str("AZURE_AI_API_KEY") if self._is_azure_openai_model(model=model, api_base=api_base): - verbose_logger.debug(f"Model={model} is Azure OpenAI model. Setting custom_llm_provider='azure'.") + verbose_logger.debug("Model=%s is Azure OpenAI model. Setting custom_llm_provider='azure'.", model) custom_llm_provider = "azure" return api_base, dynamic_api_key, custom_llm_provider diff --git a/litellm/llms/azure_ai/cost_calculator.py b/litellm/llms/azure_ai/cost_calculator.py index 6cc0cb20e27..3642fb37e86 100644 --- a/litellm/llms/azure_ai/cost_calculator.py +++ b/litellm/llms/azure_ai/cost_calculator.py @@ -107,7 +107,7 @@ def cost_per_token( # Re-raise for non-router models - they should have pricing defined raise verbose_logger.debug( - f"Azure AI Model Router: model '{model}' not in cost map, calculating routing flat cost only. Error: {e}" + "Azure AI Model Router: model '%s' not in cost map, calculating routing flat cost only. Error: %s", model, e ) # Add flat cost for Azure Model Router diff --git a/litellm/llms/azure_ai/image_generation/__init__.py b/litellm/llms/azure_ai/image_generation/__init__.py index fd511654665..742922ad295 100644 --- a/litellm/llms/azure_ai/image_generation/__init__.py +++ b/litellm/llms/azure_ai/image_generation/__init__.py @@ -32,6 +32,6 @@ def get_azure_ai_image_generation_config(model: str) -> BaseImageGenerationConfi return AzureFoundryFluxImageGenerationConfig() else: verbose_logger.debug( - f"Using AzureGPTImageGenerationConfig for model: {model}. This follows the gpt-image-1 model format." + "Using AzureGPTImageGenerationConfig for model: %s. This follows the gpt-image-1 model format.", model ) return AzureFoundryGPTImageGenerationConfig() diff --git a/litellm/llms/azure_ai/ocr/common_utils.py b/litellm/llms/azure_ai/ocr/common_utils.py index 14b77338fd7..fbeb8b8f4bd 100644 --- a/litellm/llms/azure_ai/ocr/common_utils.py +++ b/litellm/llms/azure_ai/ocr/common_utils.py @@ -53,9 +53,9 @@ def get_azure_ai_ocr_config(model: str) -> Optional["BaseOCRConfig"]: # Check for Azure Document Intelligence models if is_azure_document_intelligence_model(model): - verbose_logger.debug(f"Routing {model} to Azure Document Intelligence OCR config") + verbose_logger.debug("Routing %s to Azure Document Intelligence OCR config", model) return AzureDocumentIntelligenceOCRConfig() # Default to Mistral-based OCR for other azure_ai models - verbose_logger.debug(f"Routing {model} to Azure AI (Mistral) OCR config") + verbose_logger.debug("Routing %s to Azure AI (Mistral) OCR config", model) return AzureAIOCRConfig() diff --git a/litellm/llms/azure_ai/ocr/document_intelligence/transformation.py b/litellm/llms/azure_ai/ocr/document_intelligence/transformation.py index 66ce84cea0f..503b58a44b7 100644 --- a/litellm/llms/azure_ai/ocr/document_intelligence/transformation.py +++ b/litellm/llms/azure_ai/ocr/document_intelligence/transformation.py @@ -353,7 +353,7 @@ class AzureDocumentIntelligenceOCRConfig(BaseOCRConfig): Returns: OCRRequestData with JSON data """ - verbose_logger.debug(f"Azure Document Intelligence transform_ocr_request - model: {model}") + verbose_logger.debug("Azure Document Intelligence transform_ocr_request - model: %s", model) if not isinstance(document, dict): raise ValueError(f"Expected document dict, got {type(document)}") @@ -455,7 +455,7 @@ class AzureDocumentIntelligenceOCRConfig(BaseOCRConfig): Retry-after duration in seconds (default: 2) """ retry_after = int(response.headers.get("retry-after", "2")) - verbose_logger.debug(f"Retry polling after: {retry_after} seconds") + verbose_logger.debug("Retry polling after: %s seconds", retry_after) return retry_after @staticmethod @@ -476,7 +476,7 @@ class AzureDocumentIntelligenceOCRConfig(BaseOCRConfig): result = response.json() status = result.get("status") - verbose_logger.debug(f"Azure DI operation status: {status}") + verbose_logger.debug("Azure DI operation status: %s", status) if status == "succeeded": return "succeeded" @@ -519,7 +519,7 @@ class AzureDocumentIntelligenceOCRConfig(BaseOCRConfig): client = _get_httpx_client() start_time = time.time() - verbose_logger.debug(f"Polling Azure DI operation: {operation_url}") + verbose_logger.debug("Polling Azure DI operation: %s", operation_url) while True: self._check_timeout(start_time=start_time, timeout_secs=timeout_secs) @@ -560,7 +560,7 @@ class AzureDocumentIntelligenceOCRConfig(BaseOCRConfig): client = get_async_httpx_client(llm_provider=litellm.LlmProviders.AZURE_AI) start_time = time.time() - verbose_logger.debug(f"Polling Azure DI operation (async): {operation_url}") + verbose_logger.debug("Polling Azure DI operation (async): %s", operation_url) while True: self._check_timeout(start_time=start_time, timeout_secs=timeout_secs) @@ -603,7 +603,7 @@ class AzureDocumentIntelligenceOCRConfig(BaseOCRConfig): """ operation = AzureDocumentIntelligenceOperation.model_validate(raw_response.json()) - verbose_logger.debug(f"Azure Document Intelligence response status: {operation.status}") + verbose_logger.debug("Azure Document Intelligence response status: %s", operation.status) if operation.status != "succeeded": raise ValueError(f"Azure Document Intelligence analysis failed with status: {operation.status}") diff --git a/litellm/llms/azure_ai/ocr/transformation.py b/litellm/llms/azure_ai/ocr/transformation.py index d757a7f1378..36f7159c0d4 100644 --- a/litellm/llms/azure_ai/ocr/transformation.py +++ b/litellm/llms/azure_ai/ocr/transformation.py @@ -117,13 +117,13 @@ class AzureAIOCRConfig(MistralOCRConfig): Returns: Base64 data URI string """ - verbose_logger.debug(f"Azure AI OCR: Converting URL to base64 data URI (sync): {url}") + verbose_logger.debug("Azure AI OCR: Converting URL to base64 data URI (sync): %s", url) # Fetch and convert to base64 data URI # convert_url_to_base64 already returns a full data URI like "data:image/jpeg;base64,..." data_uri = convert_url_to_base64(url=url) - verbose_logger.debug(f"Azure AI OCR: Converted URL to data URI (length: {len(data_uri)})") + verbose_logger.debug("Azure AI OCR: Converted URL to data URI (length: %s)", len(data_uri)) return data_uri @@ -140,13 +140,13 @@ class AzureAIOCRConfig(MistralOCRConfig): Returns: Base64 data URI string """ - verbose_logger.debug(f"Azure AI OCR: Converting URL to base64 data URI (async): {url}") + verbose_logger.debug("Azure AI OCR: Converting URL to base64 data URI (async): %s", url) # Fetch and convert to base64 data URI asynchronously # async_convert_url_to_base64 already returns a full data URI like "data:image/jpeg;base64,..." data_uri = await async_convert_url_to_base64(url=url) - verbose_logger.debug(f"Azure AI OCR: Converted URL to data URI (length: {len(data_uri)})") + verbose_logger.debug("Azure AI OCR: Converted URL to data URI (length: %s)", len(data_uri)) return data_uri @@ -174,7 +174,7 @@ class AzureAIOCRConfig(MistralOCRConfig): Returns: OCRRequestData with JSON data """ - verbose_logger.debug(f"Azure AI OCR transform_ocr_request (sync) - model: {model}") + verbose_logger.debug("Azure AI OCR transform_ocr_request (sync) - model: %s", model) if not isinstance(document, dict): raise ValueError(f"Expected document dict, got {type(document)}") @@ -231,7 +231,7 @@ class AzureAIOCRConfig(MistralOCRConfig): Returns: OCRRequestData with JSON data """ - verbose_logger.debug(f"Azure AI OCR async_transform_ocr_request - model: {model}") + verbose_logger.debug("Azure AI OCR async_transform_ocr_request - model: %s", model) if not isinstance(document, dict): raise ValueError(f"Expected document dict, got {type(document)}") diff --git a/litellm/llms/base_llm/files/azure_blob_storage_backend.py b/litellm/llms/base_llm/files/azure_blob_storage_backend.py index 33255657287..86229a16a63 100644 --- a/litellm/llms/base_llm/files/azure_blob_storage_backend.py +++ b/litellm/llms/base_llm/files/azure_blob_storage_backend.py @@ -129,11 +129,11 @@ class AzureBlobStorageBackend(BaseFileStorageBackend, AzureBlobStorageLogger): full_path=full_path, ) - verbose_logger.debug(f"Successfully uploaded file to Azure Blob Storage: {storage_url}") + verbose_logger.debug("Successfully uploaded file to Azure Blob Storage: %s", storage_url) return storage_url except Exception as e: - verbose_logger.exception(f"Error uploading file to Azure Blob Storage: {e}") + verbose_logger.exception("Error uploading file to Azure Blob Storage: %s", e) raise async def _upload_file_with_account_key(self, file_content: bytes, full_path: str) -> str: @@ -145,7 +145,7 @@ class AzureBlobStorageBackend(BaseFileStorageBackend, AzureBlobStorageLogger): # Create filesystem (container) if it doesn't exist if not await file_system_client.exists(): await file_system_client.create_file_system() - verbose_logger.debug(f"Created filesystem: {self.azure_storage_file_system}") + verbose_logger.debug("Created filesystem: %s", self.azure_storage_file_system) # Extract directory and filename (similar to logger's pattern) path_parts = full_path.split("/") @@ -157,7 +157,7 @@ class AzureBlobStorageBackend(BaseFileStorageBackend, AzureBlobStorageLogger): directory_client = file_system_client.get_directory_client(directory_path) if not await directory_client.exists(): await directory_client.create_directory() - verbose_logger.debug(f"Created directory: {directory_path}") + verbose_logger.debug("Created directory: %s", directory_path) # Get file client from directory (same pattern as logger) file_client = directory_client.get_file_client(file_name) @@ -247,7 +247,7 @@ class AzureBlobStorageBackend(BaseFileStorageBackend, AzureBlobStorageLogger): return await self._download_file_with_azure_ad(file_path) except Exception as e: - verbose_logger.exception(f"Error downloading file from Azure Blob Storage: {e}") + verbose_logger.exception("Error downloading file from Azure Blob Storage: %s", e) raise async def _download_file_with_account_key(self, file_path: str) -> bytes: diff --git a/litellm/llms/base_llm/files/storage_backend_factory.py b/litellm/llms/base_llm/files/storage_backend_factory.py index 8fd918af0dc..0cf8164bc4a 100644 --- a/litellm/llms/base_llm/files/storage_backend_factory.py +++ b/litellm/llms/base_llm/files/storage_backend_factory.py @@ -29,7 +29,7 @@ def get_storage_backend(backend_type: str) -> BaseFileStorageBackend: Raises: ValueError: If backend_type is not supported """ - verbose_logger.debug(f"Creating storage backend: type={backend_type}") + verbose_logger.debug("Creating storage backend: type=%s", backend_type) if backend_type == "azure_storage": return AzureBlobStorageBackend() diff --git a/litellm/llms/base_llm/managed_resources/base_managed_resource.py b/litellm/llms/base_llm/managed_resources/base_managed_resource.py index fd9eaf9801b..44ad555377b 100644 --- a/litellm/llms/base_llm/managed_resources/base_managed_resource.py +++ b/litellm/llms/base_llm/managed_resources/base_managed_resource.py @@ -156,7 +156,7 @@ class BaseManagedResource(ABC, Generic[ResourceObjectType]): user_api_key_dict: User API key authentication details additional_db_fields: Additional fields to store in database """ - verbose_logger.info(f"Storing LiteLLM Managed {self.resource_type} with id={unified_resource_id} in cache") + verbose_logger.info("Storing LiteLLM Managed %s with id=%s in cache", self.resource_type, unified_resource_id) # Prepare cache data cache_data = { @@ -215,7 +215,7 @@ class BaseManagedResource(ABC, Generic[ResourceObjectType]): result = await table.create(data=db_data) verbose_logger.debug( - f"LiteLLM Managed {self.resource_type} with id={unified_resource_id} stored in db: {result}" + "LiteLLM Managed %s with id=%s stored in db: %s", self.resource_type, unified_resource_id, result ) async def get_unified_resource_id( @@ -579,7 +579,7 @@ class BaseManagedResource(ABC, Generic[ResourceObjectType]): except Exception as e: verbose_logger.warning( - f"Failed to parse {self.resource_type} object {resource.unified_resource_id}: {e}" + "Failed to parse %s object %s: %s", self.resource_type, resource.unified_resource_id, e ) continue diff --git a/litellm/llms/bedrock/base_aws_llm.py b/litellm/llms/bedrock/base_aws_llm.py index d7b7806a4a8..bb5ee111f2e 100644 --- a/litellm/llms/bedrock/base_aws_llm.py +++ b/litellm/llms/bedrock/base_aws_llm.py @@ -816,7 +816,10 @@ class BaseAWSLLM: import boto3 verbose_logger.debug( - f"IN Web Identity Token: {aws_web_identity_token} | Role Name: {aws_role_name} | Session Name: {aws_session_name}" + "IN Web Identity Token: %s | Role Name: %s | Session Name: %s", + aws_web_identity_token, + aws_role_name, + aws_session_name, ) # get_secret() expands environment-variable references (an os.environ/ @@ -932,7 +935,8 @@ class BaseAWSLLM: if sts_response["PackedPolicySize"] > BEDROCK_MAX_POLICY_SIZE: verbose_logger.warning( - f"The policy size is greater than 75% of the allowed size, PackedPolicySize: {sts_response['PackedPolicySize']}" + "The policy size is greater than 75%% of the allowed size, PackedPolicySize: %s", + sts_response["PackedPolicySize"], ) with tracer.trace("boto3.Session(**iam_creds_dict)"): @@ -970,7 +974,7 @@ class BaseAWSLLM: sts_client = boto3.client("sts", **irsa_sts_kwargs) # Manually assume the IRSA role with the session name - verbose_logger.debug(f"Manually assuming IRSA role {irsa_role_arn} with session {aws_session_name}") + verbose_logger.debug("Manually assuming IRSA role %s with session %s", irsa_role_arn, aws_session_name) irsa_response = sts_client.assume_role_with_web_identity( RoleArn=irsa_role_arn, RoleSessionName=aws_session_name, @@ -994,13 +998,13 @@ class BaseAWSLLM: try: caller_identity = sts_client_with_creds.get_caller_identity() verbose_logger.debug( - f"Current identity after manual IRSA assumption: {caller_identity.get('Arn', 'unknown')}" + "Current identity after manual IRSA assumption: %s", caller_identity.get("Arn", "unknown") ) except Exception as e: - verbose_logger.debug(f"Failed to get caller identity: {e}") + verbose_logger.debug("Failed to get caller identity: %s", e) # Now assume the target role - verbose_logger.debug(f"Attempting to assume target role: {aws_role_name} with session: {aws_session_name}") + verbose_logger.debug("Attempting to assume target role: %s with session: %s", aws_role_name, aws_session_name) assume_role_params = { "RoleArn": aws_role_name, "RoleSessionName": aws_session_name, @@ -1035,12 +1039,12 @@ class BaseAWSLLM: # Get current caller identity for debugging try: caller_identity = sts_client.get_caller_identity() - verbose_logger.debug(f"Current IRSA identity: {caller_identity.get('Arn', 'unknown')}") + verbose_logger.debug("Current IRSA identity: %s", caller_identity.get("Arn", "unknown")) except Exception as e: - verbose_logger.debug(f"Failed to get caller identity: {e}") + verbose_logger.debug("Failed to get caller identity: %s", e) # Assume the role - verbose_logger.debug(f"Attempting to assume role: {aws_role_name} with session: {aws_session_name}") + verbose_logger.debug("Attempting to assume role: %s with session: %s", aws_role_name, aws_session_name) assume_role_params = { "RoleArn": aws_role_name, "RoleSessionName": aws_session_name, @@ -1142,7 +1146,7 @@ class BaseAWSLLM: if web_identity_token_file and irsa_role_arn and aws_access_key_id is None and aws_secret_access_key is None: # For cross-account role assumption with specific session names, # we need to manually assume the IRSA role first with the correct session name - verbose_logger.debug(f"IRSA detected: using web identity token from {web_identity_token_file}") + verbose_logger.debug("IRSA detected: using web identity token from %s", web_identity_token_file) try: # Check if we need to do cross-account role assumption @@ -1168,13 +1172,13 @@ class BaseAWSLLM: return self._extract_credentials_and_ttl(sts_response) except Exception as e: - verbose_logger.debug(f"Failed to assume role via IRSA: {e}") + verbose_logger.debug("Failed to assume role via IRSA: %s", e) if "AccessDenied" in str(e) and "is not authorized to perform: sts:AssumeRole" in str(e): # Provide a more helpful error message for trust policy issues verbose_logger.error( - f"Access denied when trying to assume role {aws_role_name}. " - f"Please ensure the trust policy of {aws_role_name} allows " - f"the current role to assume it. Current identity: check logs with verbose mode." + "Access denied when trying to assume role %s. Please ensure the trust policy of %s allows the current role to assume it. Current identity: check logs with verbose mode.", + aws_role_name, + aws_role_name, ) # Re-raise the exception instead of falling through raise diff --git a/litellm/llms/bedrock/chat/agentcore/transformation.py b/litellm/llms/bedrock/chat/agentcore/transformation.py index d6626562393..7efad7a906d 100644 --- a/litellm/llms/bedrock/chat/agentcore/transformation.py +++ b/litellm/llms/bedrock/chat/agentcore/transformation.py @@ -131,7 +131,7 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM): jwt_token = api_key or optional_params.get("api_key") if jwt_token: verbose_logger.debug( - f"AgentCore: Using Bearer token authentication (Cognito/JWT) - token: {jwt_token[:50]}..." + "AgentCore: Using Bearer token authentication (Cognito/JWT) - token: %s...", jwt_token[:50] ) headers["Content-Type"] = "application/json" headers["Authorization"] = f"Bearer {jwt_token}" @@ -182,12 +182,12 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM): """ session_id = optional_params.get("runtimeSessionId", None) if session_id: - verbose_logger.debug(f"Using provided runtimeSessionId: {session_id}") + verbose_logger.debug("Using provided runtimeSessionId: %s", session_id) return session_id # Generate a session ID with 33+ characters generated_id = f"litellm-session-{uuid.uuid4()}" - verbose_logger.debug(f"Generated new session ID: {generated_id}") + verbose_logger.debug("Generated new session ID: %s", generated_id) return generated_id def _get_runtime_user_id(self, optional_params: dict) -> str | None: @@ -196,7 +196,7 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM): """ user_id = optional_params.get("runtimeUserId", None) if user_id: - verbose_logger.debug(f"Using provided runtimeUserId: {user_id}") + verbose_logger.debug("Using provided runtimeUserId: %s", user_id) return user_id def transform_request( @@ -231,7 +231,7 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM): dict: Payload dict containing the prompt and (optionally) the OpenAI content list. """ - verbose_logger.debug(f"AgentCore transform_request - optional_params keys: {list(optional_params.keys())}") + verbose_logger.debug("AgentCore transform_request - optional_params keys: %s", list(optional_params.keys())) # Use the last message content as the prompt prompt = convert_content_list_to_str(messages[-1]) @@ -264,7 +264,7 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM): # The request data is the payload dict (will be JSON encoded by the HTTP handler) # Qualifier will be handled as a query parameter in get_complete_url - verbose_logger.debug(f"PAYLOAD: {payload}") + verbose_logger.debug("PAYLOAD: %s", payload) return payload @staticmethod @@ -302,7 +302,7 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM): # Skip non-dict data (some lines contain JSON strings) return data if isinstance(data, dict) else None except json.JSONDecodeError: - verbose_logger.debug(f"Skipping non-JSON line: {line[:100]}") + verbose_logger.debug("Skipping non-JSON line: %s", line[:100]) return None def _extract_usage_from_event(self, event_data: dict) -> AgentCoreUsage | None: @@ -361,7 +361,10 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM): total_tokens = prompt_tokens + completion_tokens verbose_logger.debug( - f"Calculated usage - prompt: {prompt_tokens}, completion: {completion_tokens}, total: {total_tokens}" + "Calculated usage - prompt: %s, completion: %s, total: %s", + prompt_tokens, + completion_tokens, + total_tokens, ) return Usage( @@ -370,7 +373,7 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM): total_tokens=total_tokens, ) except Exception as e: - verbose_logger.warning(f"Failed to calculate token usage: {e}") + verbose_logger.warning("Failed to calculate token usage: %s", e) return None def _parse_json_response(self, response_json: dict) -> AgentCoreParsedResponse: @@ -439,8 +442,8 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM): # Strategy 4: fallback - return raw JSON as content verbose_logger.warning( - f"AgentCore: Could not extract content from JSON response keys " - f"{list(response_json.keys())}. Returning raw JSON as content." + "AgentCore: Could not extract content from JSON response keys %s. Returning raw JSON as content.", + list(response_json.keys()), ) return AgentCoreParsedResponse( content=json.dumps(response_json), @@ -459,20 +462,20 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM): AgentCoreParsedResponse: Parsed response data """ content_type = raw_response.headers.get("content-type", "").lower() - verbose_logger.debug(f"AgentCore response Content-Type: {content_type}") + verbose_logger.debug("AgentCore response Content-Type: %s", content_type) # Parse response based on content type if "application/json" in content_type: # Direct JSON response verbose_logger.debug("Parsing JSON response") response_json = raw_response.json() - verbose_logger.debug(f"Response JSON: {response_json}") + verbose_logger.debug("Response JSON: %s", response_json) return self._parse_json_response(response_json) else: # SSE stream response (text/event-stream or default) verbose_logger.debug("Parsing SSE stream response") response_text = raw_response.text - verbose_logger.debug(f"AgentCore response (first 500 chars): {response_text[:500]}") + verbose_logger.debug("AgentCore response (first 500 chars): %s", response_text[:500]) return self._parse_sse_stream(response_text) def _parse_sse_stream(self, response_text: str) -> AgentCoreParsedResponse: @@ -496,7 +499,7 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM): if not data: continue - verbose_logger.debug(f"SSE event keys: {list(data.keys())}") + verbose_logger.debug("SSE event keys: %s", list(data.keys())) # Check for final complete message if "message" in data and isinstance(data["message"], dict): @@ -506,12 +509,12 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM): # Process event data if "event" in data and isinstance(data["event"], dict): event_payload = data["event"] - verbose_logger.debug(f"Event payload keys: {list(event_payload.keys())}") + verbose_logger.debug("Event payload keys: %s", list(event_payload.keys())) # Extract usage metadata if usage := self._extract_usage_from_event(data): usage_data = usage - verbose_logger.debug(f"Found usage data: {usage_data}") + verbose_logger.debug("Found usage data: %s", usage_data) # Collect content deltas if text := self._extract_content_delta(data): @@ -520,7 +523,7 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM): # Build final content content = self._extract_content_from_message(final_message) if final_message else "".join(content_blocks) - verbose_logger.debug(f"Final usage_data: {usage_data}") + verbose_logger.debug("Final usage_data: %s", usage_data) return AgentCoreParsedResponse(content=content, usage=usage_data, final_message=final_message) @@ -624,7 +627,7 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM): yield chunk except json.JSONDecodeError: - verbose_logger.debug(f"Skipping non-JSON SSE line: {line[:100]}") + verbose_logger.debug("Skipping non-JSON SSE line: %s", line[:100]) continue def get_sync_custom_stream_wrapper( @@ -651,7 +654,7 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM): if client is None or not isinstance(client, HTTPHandler): client = _get_httpx_client(params={}) - verbose_logger.debug(f"Making sync streaming request to: {api_base}") + verbose_logger.debug("Making sync streaming request to: %s", api_base) # Make streaming request response = client.post( @@ -837,7 +840,7 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM): yield chunk except json.JSONDecodeError: - verbose_logger.debug(f"Skipping non-JSON SSE line: {line[:100]}") + verbose_logger.debug("Skipping non-JSON SSE line: %s", line[:100]) continue async def get_async_custom_stream_wrapper( @@ -864,7 +867,7 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM): if client is None or not isinstance(client, AsyncHTTPHandler): client = get_async_httpx_client(llm_provider=cast(Any, "bedrock"), params={}) - verbose_logger.debug(f"Making async streaming request to: {api_base}") + verbose_logger.debug("Making async streaming request to: %s", api_base) # Make async streaming request response = await client.post( @@ -990,8 +993,8 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM): content = parsed_data["content"] usage_data = parsed_data["usage"] - verbose_logger.debug(f"Parsed content length: {len(content)}") - verbose_logger.debug(f"Usage data: {usage_data}") + verbose_logger.debug("Parsed content length: %s", len(content)) + verbose_logger.debug("Usage data: %s", usage_data) # Create the message message = Message(content=content, role="assistant") @@ -1023,7 +1026,7 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM): return model_response except Exception as e: - verbose_logger.error(f"Error processing Bedrock AgentCore response: {e}") + verbose_logger.error("Error processing Bedrock AgentCore response: %s", e) raise BedrockError( message=f"Error processing response: {e}", status_code=raw_response.status_code, diff --git a/litellm/llms/bedrock/chat/converse_transformation.py b/litellm/llms/bedrock/chat/converse_transformation.py index 2b34c9f2654..5096cc44b76 100644 --- a/litellm/llms/bedrock/chat/converse_transformation.py +++ b/litellm/llms/bedrock/chat/converse_transformation.py @@ -352,8 +352,8 @@ class AmazonConverseConfig(BaseConfig): # Model strings can be like: "amazon.nova-pro-v1:0", "us.amazon.nova-pro-v1:0", etc. if "nova" not in model.lower(): verbose_logger.debug( - f"web_search_options passed but model {model} is not a Nova model. " - "Nova grounding is only supported on Amazon Nova models." + "web_search_options passed but model %s is not a Nova model. Nova grounding is only supported on Amazon Nova models.", + model, ) return None @@ -950,8 +950,8 @@ class AmazonConverseConfig(BaseConfig): if isinstance(tool_choice_block, dict): if "any" in tool_choice_block or "tool" in tool_choice_block: verbose_logger.info( - f"{model} does not support forced tool use (tool_choice='required' or specific tool) " - f"when reasoning is enabled. Changing tool_choice to 'auto'." + "%s does not support forced tool use (tool_choice='required' or specific tool) when reasoning is enabled. Changing tool_choice to 'auto'.", + model, ) optional_params["tool_choice"] = ToolChoiceValuesBlock(auto={}) diff --git a/litellm/llms/bedrock/chat/invoke_agent/transformation.py b/litellm/llms/bedrock/chat/invoke_agent/transformation.py index da6224ec487..625ace20614 100644 --- a/litellm/llms/bedrock/chat/invoke_agent/transformation.py +++ b/litellm/llms/bedrock/chat/invoke_agent/transformation.py @@ -212,12 +212,12 @@ class AmazonInvokeAgentConfig(BaseConfig, BaseAWSLLM): } events.append(parsed_event) except json.JSONDecodeError as e: - verbose_logger.warning(f"Failed to parse trace event JSON: {e}") + verbose_logger.warning("Failed to parse trace event JSON: %s", e) else: - verbose_logger.debug(f"Unknown event type: {event_type}") + verbose_logger.debug("Unknown event type: %s", event_type) except Exception as e: - verbose_logger.error(f"Error processing event: {e}") + verbose_logger.error("Error processing event: %s", e) continue return events @@ -226,11 +226,11 @@ class AmazonInvokeAgentConfig(BaseConfig, BaseAWSLLM): """Extract message content from an AWS event, adapted from AWSEventStreamDecoder.""" try: response_dict = event.to_response_dict() - verbose_logger.debug(f"Response dict: {response_dict}") + verbose_logger.debug("Response dict: %s", response_dict) # Use the same response shape parsing as the existing decoder parsed_response = parser.parse(response_dict, self._get_response_stream_shape()) - verbose_logger.debug(f"Parsed response: {parsed_response}") + verbose_logger.debug("Parsed response: %s", parsed_response) if response_dict["status_code"] != 200: decoded_body = response_dict["body"].decode() @@ -259,7 +259,7 @@ class AmazonInvokeAgentConfig(BaseConfig, BaseAWSLLM): return chunk.decode() except Exception as e: - verbose_logger.debug(f"Error parsing message from event: {e}") + verbose_logger.debug("Error parsing message from event: %s", e) return None def _extract_headers_from_event(self, event) -> InvokeAgentEventHeaders: @@ -275,7 +275,7 @@ class AmazonInvokeAgentConfig(BaseConfig, BaseAWSLLM): message_type=headers.get(":message-type", ""), ) except Exception as e: - verbose_logger.debug(f"Error extracting headers: {e}") + verbose_logger.debug("Error extracting headers: %s", e) return InvokeAgentEventHeaders(event_type="", content_type="", message_type="") def _get_response_stream_shape(self): @@ -302,7 +302,7 @@ class AmazonInvokeAgentConfig(BaseConfig, BaseAWSLLM): decoded_content = base64.b64decode(encoded_bytes).decode("utf-8") response_parts.append(decoded_content) except Exception as e: - verbose_logger.warning(f"Failed to decode chunk content: {e}") + verbose_logger.warning("Failed to decode chunk content: %s", e) return "".join(response_parts) @@ -324,7 +324,7 @@ class AmazonInvokeAgentConfig(BaseConfig, BaseAWSLLM): if not trace_data: continue - verbose_logger.debug(f"Trace event: {trace_data}") + verbose_logger.debug("Trace event: %s", trace_data) # Extract usage from pre-processing trace self._extract_and_update_preprocessing_usage( @@ -443,11 +443,11 @@ class AmazonInvokeAgentConfig(BaseConfig, BaseAWSLLM): try: # Get the raw binary content raw_content = raw_response.content - verbose_logger.debug(f"Processing {len(raw_content)} bytes of AWS event stream data") + verbose_logger.debug("Processing %s bytes of AWS event stream data", len(raw_content)) # Parse the AWS event stream format events = self._parse_aws_event_stream(raw_content) - verbose_logger.debug(f"Parsed {len(events)} events from stream") + verbose_logger.debug("Parsed %s events from stream", len(events)) # Extract response content from chunk events content = self._extract_response_content(events) @@ -464,7 +464,7 @@ class AmazonInvokeAgentConfig(BaseConfig, BaseAWSLLM): ) except Exception as e: - verbose_logger.error(f"Error processing Bedrock Invoke Agent response: {e}") + verbose_logger.error("Error processing Bedrock Invoke Agent response: %s", e) raise BedrockError( message=f"Error processing response: {e}", status_code=raw_response.status_code, diff --git a/litellm/llms/bedrock/chat/invoke_handler.py b/litellm/llms/bedrock/chat/invoke_handler.py index 4a429b639d2..a5ffe6abff4 100644 --- a/litellm/llms/bedrock/chat/invoke_handler.py +++ b/litellm/llms/bedrock/chat/invoke_handler.py @@ -530,7 +530,7 @@ class AWSEventStreamDecoder: # and use it as the consistent ID for all subsequent chunks. self._initialize_converse_response_id(chunk_data) - verbose_logger.debug(f"\n\nRaw Chunk: {chunk_data}\n\n") + verbose_logger.debug("\n\nRaw Chunk: %s\n\n", chunk_data) text = "" tool_use: ChatCompletionToolCallChunk | None = None finish_reason = "" diff --git a/litellm/llms/bedrock/count_tokens/bedrock_token_counter.py b/litellm/llms/bedrock/count_tokens/bedrock_token_counter.py index 934d416d256..23998c62644 100644 --- a/litellm/llms/bedrock/count_tokens/bedrock_token_counter.py +++ b/litellm/llms/bedrock/count_tokens/bedrock_token_counter.py @@ -88,7 +88,7 @@ class BedrockTokenCounter(BaseTokenCounter): original_response=result, ) except BedrockError as e: - verbose_logger.warning(f"Bedrock CountTokens API error: status={e.status_code}, message={e.message}") + verbose_logger.warning("Bedrock CountTokens API error: status=%s, message=%s", e.status_code, e.message) return TokenCountResponse( total_tokens=0, request_model=request_model, @@ -99,7 +99,7 @@ class BedrockTokenCounter(BaseTokenCounter): status_code=e.status_code, ) except Exception as e: - verbose_logger.warning(f"Error calling Bedrock CountTokens API: {e}") + verbose_logger.warning("Error calling Bedrock CountTokens API: %s", e) return TokenCountResponse( total_tokens=0, request_model=request_model, diff --git a/litellm/llms/bedrock/count_tokens/handler.py b/litellm/llms/bedrock/count_tokens/handler.py index 44cc535385d..100f0753b51 100644 --- a/litellm/llms/bedrock/count_tokens/handler.py +++ b/litellm/llms/bedrock/count_tokens/handler.py @@ -43,7 +43,7 @@ class BedrockCountTokensHandler(BedrockCountTokensConfig): # Validate the request self.validate_count_tokens_request(request_data) - verbose_logger.debug(f"Processing CountTokens request for resolved model: {resolved_model}") + verbose_logger.debug("Processing CountTokens request for resolved model: %s", resolved_model) # Get AWS region using existing LiteLLM function aws_region_name = self._get_aws_region_name( @@ -52,12 +52,12 @@ class BedrockCountTokensHandler(BedrockCountTokensConfig): model_id=None, ) - verbose_logger.debug(f"Retrieved AWS region: {aws_region_name}") + verbose_logger.debug("Retrieved AWS region: %s", aws_region_name) # Transform request to Bedrock format (supports both Converse and InvokeModel) bedrock_request = self.transform_anthropic_to_bedrock_count_tokens(request_data=request_data) - verbose_logger.debug(f"Transformed request: {bedrock_request}") + verbose_logger.debug("Transformed request: %s", bedrock_request) # Get endpoint URL using simplified function api_base = litellm_params.get("api_base", None) @@ -69,7 +69,7 @@ class BedrockCountTokensHandler(BedrockCountTokensConfig): aws_bedrock_runtime_endpoint=aws_bedrock_runtime_endpoint, ) - verbose_logger.debug(f"Making request to: {endpoint_url}") + verbose_logger.debug("Making request to: %s", endpoint_url) # Use existing _sign_request method from BaseAWSLLM # Extract api_key for bearer token auth if provided @@ -94,11 +94,11 @@ class BedrockCountTokensHandler(BedrockCountTokensConfig): timeout=30.0, ) - verbose_logger.debug(f"Response status: {response.status_code}") + verbose_logger.debug("Response status: %s", response.status_code) if response.status_code != 200: error_text = response.text - verbose_logger.error(f"AWS Bedrock error: {error_text}") + verbose_logger.error("AWS Bedrock error: %s", error_text) raise BedrockError( status_code=response.status_code, message=error_text, @@ -106,12 +106,12 @@ class BedrockCountTokensHandler(BedrockCountTokensConfig): bedrock_response = response.json() - verbose_logger.debug(f"Bedrock response: {bedrock_response}") + verbose_logger.debug("Bedrock response: %s", bedrock_response) # Transform response back to expected format final_response = self.transform_bedrock_response_to_anthropic(bedrock_response) - verbose_logger.debug(f"Final response: {final_response}") + verbose_logger.debug("Final response: %s", final_response) return final_response @@ -120,13 +120,13 @@ class BedrockCountTokensHandler(BedrockCountTokensConfig): raise except httpx.HTTPStatusError as e: # HTTP errors - preserve the actual status code - verbose_logger.error(f"HTTP error in CountTokens handler: {e}") + verbose_logger.error("HTTP error in CountTokens handler: %s", e) raise BedrockError( status_code=e.response.status_code, message=e.response.text, ) except Exception as e: - verbose_logger.error(f"Error in CountTokens handler: {e}") + verbose_logger.error("Error in CountTokens handler: %s", e) raise BedrockError( status_code=500, message=f"CountTokens processing error: {e}", diff --git a/litellm/llms/bedrock/files/transformation.py b/litellm/llms/bedrock/files/transformation.py index d3e61829681..9f61c50b25f 100644 --- a/litellm/llms/bedrock/files/transformation.py +++ b/litellm/llms/bedrock/files/transformation.py @@ -652,7 +652,8 @@ class BedrockFilesConfig(BaseAWSLLM, BaseFilesConfig): ) except Exception as e: verbose_logger.exception( - f"litellm.llms.bedrock.files.transformation.py::_transform_openai_jsonl_content_to_bedrock_jsonl_content() - Error inferring custom_llm_provider - {e}" + "litellm.llms.bedrock.files.transformation.py::_transform_openai_jsonl_content_to_bedrock_jsonl_content() - Error inferring custom_llm_provider - %s", + e, ) # Determine provider from model name diff --git a/litellm/llms/bedrock/realtime/handler.py b/litellm/llms/bedrock/realtime/handler.py index a8969894dda..874052d2b29 100644 --- a/litellm/llms/bedrock/realtime/handler.py +++ b/litellm/llms/bedrock/realtime/handler.py @@ -83,7 +83,7 @@ class BedrockRealtime(BaseAWSLLM): else: endpoint_uri = f"https://bedrock-runtime.{aws_region_name}.amazonaws.com" - verbose_proxy_logger.debug(f"Bedrock Realtime: Connecting to {endpoint_uri} with model {model}") + verbose_proxy_logger.debug("Bedrock Realtime: Connecting to %s with model %s", endpoint_uri, model) credentials = self.get_credentials( aws_access_key_id=aws_access_key_id, @@ -173,7 +173,7 @@ class BedrockRealtime(BaseAWSLLM): ) except Exception as e: - verbose_proxy_logger.exception(f"Error in BedrockRealtime.async_realtime: {e}") + verbose_proxy_logger.exception("Error in BedrockRealtime.async_realtime: %s", e) try: await websocket.close(code=1011, reason=_redact_string(f"Internal error: {e}")) except Exception: @@ -200,13 +200,13 @@ class BedrockRealtime(BaseAWSLLM): value=BidirectionalInputPayloadPart(bytes_=bedrock_message.encode("utf-8")) ) await bedrock_stream.input_stream.send(event) - verbose_proxy_logger.debug(f"Bedrock Realtime: Sent to Bedrock: {bedrock_message[:200]}") + verbose_proxy_logger.debug("Bedrock Realtime: Sent to Bedrock: %s", bedrock_message[:200]) try: while True: # Receive message from client message = await client_ws.receive_text() - verbose_proxy_logger.debug(f"Bedrock Realtime: Received from client: {message[:200]}") + verbose_proxy_logger.debug("Bedrock Realtime: Received from client: %s", message[:200]) # Transform OpenAI format to Bedrock format transformed_messages = transformation_config.transform_realtime_request( @@ -237,7 +237,7 @@ class BedrockRealtime(BaseAWSLLM): ) except Exception as e: - verbose_proxy_logger.debug(f"Client to Bedrock forwarding ended: {e}", exc_info=True) + verbose_proxy_logger.debug("Client to Bedrock forwarding ended: %s", e, exc_info=True) for close_message in transformation_config.session_close_messages(): with contextlib.suppress(Exception): await send_to_bedrock(close_message) @@ -266,7 +266,7 @@ class BedrockRealtime(BaseAWSLLM): if result.value and result.value.bytes_: bedrock_response = result.value.bytes_.decode("utf-8") - verbose_proxy_logger.debug(f"Bedrock Realtime: Received from Bedrock: {bedrock_response[:200]}") + verbose_proxy_logger.debug("Bedrock Realtime: Received from Bedrock: %s", bedrock_response[:200]) # Transform Bedrock format to OpenAI format from litellm.types.realtime import RealtimeResponseTransformInput @@ -306,10 +306,10 @@ class BedrockRealtime(BaseAWSLLM): for openai_message in openai_messages: message_json = json.dumps(openai_message) await client_ws.send_text(message_json) - verbose_proxy_logger.debug(f"Bedrock Realtime: Sent to client: {message_json[:200]}") + verbose_proxy_logger.debug("Bedrock Realtime: Sent to client: %s", message_json[:200]) except Exception as e: - verbose_proxy_logger.debug(f"Bedrock to client forwarding ended: {e}", exc_info=True) + verbose_proxy_logger.debug("Bedrock to client forwarding ended: %s", e, exc_info=True) finally: # Close the client WebSocket try: diff --git a/litellm/llms/bedrock/realtime/transformation.py b/litellm/llms/bedrock/realtime/transformation.py index 39f5d25cf89..68782c8b412 100644 --- a/litellm/llms/bedrock/realtime/transformation.py +++ b/litellm/llms/bedrock/realtime/transformation.py @@ -601,7 +601,7 @@ class BedrockRealtimeConfig(BaseRealtimeConfig): try: json_message = json.loads(message) except json.JSONDecodeError: - verbose_logger.warning(f"Invalid JSON message: {message[:200]}") + verbose_logger.warning("Invalid JSON message: %s", message[:200]) return [] message_type = json_message.get("type") @@ -620,7 +620,7 @@ class BedrockRealtimeConfig(BaseRealtimeConfig): elif message_type == "response.cancel": return self.transform_response_cancel_event(json_message) else: - verbose_logger.warning(f"Unknown message type: {message_type}") + verbose_logger.warning("Unknown message type: %s", message_type) return [] def _session_object( @@ -866,7 +866,7 @@ class BedrockRealtimeConfig(BaseRealtimeConfig): Tuple of (events, reset_delta_chunks) """ content_end = event["contentEnd"] - verbose_logger.debug(f"Handling contentEnd: {content_end}") + verbose_logger.debug("Handling contentEnd: %s", content_end) if not current_output_item_id or not current_response_id: return [], current_delta_chunks @@ -1149,7 +1149,7 @@ class BedrockRealtimeConfig(BaseRealtimeConfig): message_preview = ( message[:200].decode("utf-8", errors="replace") if isinstance(message, bytes) else message[:200] ) - verbose_logger.warning(f"Invalid JSON message: {message_preview}") + verbose_logger.warning("Invalid JSON message: %s", message_preview) return { "response": [], "current_output_item_id": realtime_response_transform_input.get("current_output_item_id"), @@ -1230,7 +1230,7 @@ class BedrockRealtimeConfig(BaseRealtimeConfig): ) returned_messages.extend(events) # Store tool call info for potential use - verbose_logger.debug(f"Tool use event: {tool_name} (ID: {tool_call_id})") + verbose_logger.debug("Tool use event: %s (ID: %s)", tool_name, tool_call_id) elif "promptEnd" in event or "completionEnd" in event: ( diff --git a/litellm/llms/bedrock_mantle/chat/transformation.py b/litellm/llms/bedrock_mantle/chat/transformation.py index d85edbd0c86..bd1664ff95a 100644 --- a/litellm/llms/bedrock_mantle/chat/transformation.py +++ b/litellm/llms/bedrock_mantle/chat/transformation.py @@ -102,7 +102,7 @@ class BedrockMantleChatConfig(BedrockMantleAuthMixin, OpenAILikeChatConfig): if "reasoning_effort" not in base_params: base_params.append("reasoning_effort") except Exception as e: - verbose_logger.debug(f"BedrockMantleChatConfig: error checking reasoning support: {e}") + verbose_logger.debug("BedrockMantleChatConfig: error checking reasoning support: %s", e) return base_params def get_model_response_iterator( diff --git a/litellm/llms/black_forest_labs/image_edit/handler.py b/litellm/llms/black_forest_labs/image_edit/handler.py index cf0cc31283b..6a6c01e8b24 100644 --- a/litellm/llms/black_forest_labs/image_edit/handler.py +++ b/litellm/llms/black_forest_labs/image_edit/handler.py @@ -342,7 +342,7 @@ class BlackForestLabsImageEdit: polling_headers = {"x-key": headers.get("x-key", "")} start_time = time.time() - verbose_logger.debug(f"BFL starting sync polling at {polling_url}") + verbose_logger.debug("BFL starting sync polling at %s", polling_url) while time.time() - start_time < max_wait: response = sync_client.get( @@ -359,7 +359,7 @@ class BlackForestLabsImageEdit: data = response.json() status = data.get("status") - verbose_logger.debug(f"BFL poll status: {status}") + verbose_logger.debug("BFL poll status: %s", status) if status == "Ready": return response @@ -433,7 +433,7 @@ class BlackForestLabsImageEdit: polling_headers = {"x-key": headers.get("x-key", "")} start_time = time.time() - verbose_logger.debug(f"BFL starting async polling at {polling_url}") + verbose_logger.debug("BFL starting async polling at %s", polling_url) while time.time() - start_time < max_wait: response = await async_client.get( @@ -450,7 +450,7 @@ class BlackForestLabsImageEdit: data = response.json() status = data.get("status") - verbose_logger.debug(f"BFL poll status: {status}") + verbose_logger.debug("BFL poll status: %s", status) if status == "Ready": return response diff --git a/litellm/llms/black_forest_labs/image_generation/handler.py b/litellm/llms/black_forest_labs/image_generation/handler.py index 054d28003f1..4df3b49d7f1 100644 --- a/litellm/llms/black_forest_labs/image_generation/handler.py +++ b/litellm/llms/black_forest_labs/image_generation/handler.py @@ -336,7 +336,7 @@ class BlackForestLabsImageGeneration: polling_headers = {"x-key": headers.get("x-key", "")} start_time = time.time() - verbose_logger.debug(f"BFL starting sync polling at {polling_url}") + verbose_logger.debug("BFL starting sync polling at %s", polling_url) while time.time() - start_time < max_wait: response = sync_client.get( @@ -353,7 +353,7 @@ class BlackForestLabsImageGeneration: data = response.json() status = data.get("status") - verbose_logger.debug(f"BFL poll status: {status}") + verbose_logger.debug("BFL poll status: %s", status) if status == "Ready": return response @@ -427,7 +427,7 @@ class BlackForestLabsImageGeneration: polling_headers = {"x-key": headers.get("x-key", "")} start_time = time.time() - verbose_logger.debug(f"BFL starting async polling at {polling_url}") + verbose_logger.debug("BFL starting async polling at %s", polling_url) while time.time() - start_time < max_wait: response = await async_client.get( @@ -444,7 +444,7 @@ class BlackForestLabsImageGeneration: data = response.json() status = data.get("status") - verbose_logger.debug(f"BFL poll status: {status}") + verbose_logger.debug("BFL poll status: %s", status) if status == "Ready": return response diff --git a/litellm/llms/custom_httpx/aiohttp_transport.py b/litellm/llms/custom_httpx/aiohttp_transport.py index ac7a8908616..9ac67272b3e 100644 --- a/litellm/llms/custom_httpx/aiohttp_transport.py +++ b/litellm/llms/custom_httpx/aiohttp_transport.py @@ -289,7 +289,7 @@ class LiteLLMAiohttpTransport(AiohttpTransport): if self._owns_session: self._close_recycled_session(old_session) except Exception as e: - verbose_logger.debug(f"Error closing old session: {e}") + verbose_logger.debug("Error closing old session: %s", e) # Create a new session in the current event loop self.client = self._rebuild_session() @@ -302,9 +302,9 @@ class LiteLLMAiohttpTransport(AiohttpTransport): try: self._close_recycled_session(old_session) except (RuntimeError, AttributeError, OSError) as close_error: - verbose_logger.debug(f"Error closing old session: {close_error}") + verbose_logger.debug("Error closing old session: %s", close_error) self.client = self._rebuild_session() - verbose_logger.debug(f"Error checking session loop, created new session: {e}") + verbose_logger.debug("Error checking session loop, created new session: %s", e) return self.client @@ -397,7 +397,7 @@ class LiteLLMAiohttpTransport(AiohttpTransport): except RuntimeError as e: # Handle the case where session was closed between our check and actual use if "Session is closed" in str(e): - verbose_logger.debug(f"Session closed during request, retrying with new session: {e}") + verbose_logger.debug("Session closed during request, retrying with new session: %s", e) # Dispose of the session that actually faulted. Do NOT read # self.client here: a concurrent task may already have # replaced it with a healthy session that must stay open. @@ -436,7 +436,7 @@ class LiteLLMAiohttpTransport(AiohttpTransport): try: proxy = self._proxy_from_env(request.url) except Exception as e: # pragma: no cover - best effort - verbose_logger.debug(f"Error reading proxy env: {e}") + verbose_logger.debug("Error reading proxy env: %s", e) return proxy diff --git a/litellm/llms/custom_httpx/http_handler.py b/litellm/llms/custom_httpx/http_handler.py index 3e34b483002..861adf919c0 100644 --- a/litellm/llms/custom_httpx/http_handler.py +++ b/litellm/llms/custom_httpx/http_handler.py @@ -215,19 +215,20 @@ def _create_ssl_context( if ssl_ecdh_curve and isinstance(ssl_ecdh_curve, str): try: custom_ssl_context.set_ecdh_curve(ssl_ecdh_curve) - verbose_logger.debug(f"SSL ECDH curve set to: {ssl_ecdh_curve}") + verbose_logger.debug("SSL ECDH curve set to: %s", ssl_ecdh_curve) except AttributeError: verbose_logger.warning( - f"SSL ECDH curve configuration not supported. " - f"Python version: {sys.version.split()[0]}, OpenSSL version: {ssl.OPENSSL_VERSION}. " - f"Requested curve: {ssl_ecdh_curve}. Continuing with default curves." + "SSL ECDH curve configuration not supported. Python version: %s, OpenSSL version: %s. Requested curve: %s. Continuing with default curves.", + sys.version.split()[0], + ssl.OPENSSL_VERSION, + ssl_ecdh_curve, ) except ValueError as e: # Invalid curve name verbose_logger.warning( - f"Invalid SSL ECDH curve name: '{ssl_ecdh_curve}'. {e}. " - f"Common valid curves: X25519, prime256v1, secp384r1, secp521r1. " - f"Continuing with default curves (including PQC)." + "Invalid SSL ECDH curve name: '%s'. %s. Common valid curves: X25519, prime256v1, secp384r1, secp521r1. Continuing with default curves (including PQC).", + ssl_ecdh_curve, + e, ) return custom_ssl_context @@ -1033,7 +1034,7 @@ class AsyncHTTPHandler: # Use shared session if provided and valid if shared_session is not None and not shared_session.closed: - verbose_logger.debug(f"SHARED SESSION: Reusing existing ClientSession (ID: {id(shared_session)})") + verbose_logger.debug("SHARED SESSION: Reusing existing ClientSession (ID: %s)", id(shared_session)) return LiteLLMAiohttpTransport( client=shared_session, ssl_verify=ssl_for_transport, diff --git a/litellm/llms/custom_httpx/llm_http_handler.py b/litellm/llms/custom_httpx/llm_http_handler.py index f7bf174f9ac..fcb039c9b4f 100644 --- a/litellm/llms/custom_httpx/llm_http_handler.py +++ b/litellm/llms/custom_httpx/llm_http_handler.py @@ -370,7 +370,7 @@ class BaseLLMHTTPHandler: ): if client is None: verbose_logger.debug( - f"Creating HTTP client with shared_session: {id(shared_session) if shared_session else None}" + "Creating HTTP client with shared_session: %s", id(shared_session) if shared_session else None ) async_httpx_client = get_async_httpx_client( llm_provider=litellm.LlmProviders(custom_llm_provider), @@ -2676,7 +2676,8 @@ class BaseLLMHTTPHandler: """ if client is None or not isinstance(client, AsyncHTTPHandler): verbose_logger.debug( - f"Creating HTTP client for responses API with shared_session: {id(shared_session) if shared_session else None}" + "Creating HTTP client for responses API with shared_session: %s", + id(shared_session) if shared_session else None, ) async_httpx_client = get_async_httpx_client( llm_provider=litellm.LlmProviders(custom_llm_provider), @@ -2859,7 +2860,8 @@ class BaseLLMHTTPHandler: """ if client is None or not isinstance(client, AsyncHTTPHandler): verbose_logger.debug( - f"Creating HTTP client for delete_response with shared_session: {id(shared_session) if shared_session else None}" + "Creating HTTP client for delete_response with shared_session: %s", + id(shared_session) if shared_session else None, ) async_httpx_client = get_async_httpx_client( llm_provider=litellm.LlmProviders(custom_llm_provider), @@ -3112,7 +3114,8 @@ class BaseLLMHTTPHandler: """ if client is None or not isinstance(client, AsyncHTTPHandler): verbose_logger.debug( - f"Creating HTTP client for get_responses with shared_session: {id(shared_session) if shared_session else None}" + "Creating HTTP client for get_responses with shared_session: %s", + id(shared_session) if shared_session else None, ) async_httpx_client = get_async_httpx_client( llm_provider=litellm.LlmProviders(custom_llm_provider), @@ -3156,7 +3159,7 @@ class BaseLLMHTTPHandler: response = await async_httpx_client.get(url=url, headers=headers, params=data) response.raise_for_status() except Exception as e: - verbose_logger.debug(f"Error retrieving response: {e}") + verbose_logger.debug("Error retrieving response: %s", e) raise self._handle_error( e=e, provider_config=responses_api_provider_config, @@ -3275,7 +3278,8 @@ class BaseLLMHTTPHandler: ) -> dict: if client is None or not isinstance(client, AsyncHTTPHandler): verbose_logger.debug( - f"Creating HTTP client for list_input_items with shared_session: {id(shared_session) if shared_session else None}" + "Creating HTTP client for list_input_items with shared_session: %s", + id(shared_session) if shared_session else None, ) async_httpx_client = get_async_httpx_client( llm_provider=litellm.LlmProviders(custom_llm_provider), @@ -3495,7 +3499,7 @@ class BaseLLMHTTPHandler: timeout=timeout, ) except Exception as e: - verbose_logger.exception(f"Error creating file: {e}") + verbose_logger.exception("Error creating file: %s", e) raise self._handle_error(e=e, provider_config=provider_config) elif isinstance(transformed_request, str) or isinstance(transformed_request, bytes): # Handle traditional file uploads @@ -3626,7 +3630,7 @@ class BaseLLMHTTPHandler: if initial_response_data: litellm_params["initial_file_response"] = initial_response_data except Exception as e: - verbose_logger.exception(f"Error creating file: {e}") + verbose_logger.exception("Error creating file: %s", e) raise self._handle_error( e=e, provider_config=provider_config, @@ -3657,7 +3661,7 @@ class BaseLLMHTTPHandler: timeout=timeout, ) except Exception as e: - verbose_logger.exception(f"Error creating file: {e}") + verbose_logger.exception("Error creating file: %s", e) raise self._handle_error(e=e, provider_config=provider_config) elif isinstance(transformed_request, str) or isinstance(transformed_request, bytes): # Handle traditional file uploads @@ -3868,7 +3872,7 @@ class BaseLLMHTTPHandler: timeout=timeout, ) except Exception as e: - verbose_logger.exception(f"Error creating batch: {e}") + verbose_logger.exception("Error creating batch: %s", e) raise self._handle_error( e=e, provider_config=provider_config, @@ -3960,7 +3964,7 @@ class BaseLLMHTTPHandler: headers=headers, ) except Exception as e: - verbose_logger.exception(f"Error retrieving batch: {e}") + verbose_logger.exception("Error retrieving batch: %s", e) raise self._handle_error( e=e, provider_config=provider_config, @@ -4033,7 +4037,7 @@ class BaseLLMHTTPHandler: timeout=timeout, ) except Exception as e: - verbose_logger.exception(f"Error creating batch: {e}") + verbose_logger.exception("Error creating batch: %s", e) raise self._handle_error( e=e, provider_config=provider_config, @@ -4117,7 +4121,7 @@ class BaseLLMHTTPHandler: headers=headers, ) except Exception as e: - verbose_logger.exception(f"Error retrieving batch: {e}") + verbose_logger.exception("Error retrieving batch: %s", e) raise self._handle_error( e=e, provider_config=provider_config, @@ -4230,7 +4234,8 @@ class BaseLLMHTTPHandler: """ if client is None or not isinstance(client, AsyncHTTPHandler): verbose_logger.debug( - f"Creating HTTP client for cancel_response with shared_session: {id(shared_session) if shared_session else None}" + "Creating HTTP client for cancel_response with shared_session: %s", + id(shared_session) if shared_session else None, ) async_httpx_client = get_async_httpx_client( llm_provider=litellm.LlmProviders(custom_llm_provider), @@ -4404,7 +4409,8 @@ class BaseLLMHTTPHandler: """ if client is None or not isinstance(client, AsyncHTTPHandler): verbose_logger.debug( - f"Creating HTTP client for compact_response with shared_session: {id(shared_session) if shared_session else None}" + "Creating HTTP client for compact_response with shared_session: %s", + id(shared_session) if shared_session else None, ) async_httpx_client = get_async_httpx_client( llm_provider=litellm.LlmProviders(custom_llm_provider), @@ -5659,7 +5665,7 @@ class BaseLLMHTTPHandler: fingerprint=fingerprint, ) except Exception as e: - verbose_logger.exception(f"LiteLLM.AgenticHookError: Exception in chat completion agentic hooks: {e}") + verbose_logger.exception("LiteLLM.AgenticHookError: Exception in chat completion agentic hooks: %s", e) # Check if we need to convert response to fake stream for chat completions # This happens when: @@ -5901,10 +5907,10 @@ class BaseLLMHTTPHandler: await realtime_streaming.bidirectional_forward() except websockets.exceptions.InvalidStatusCode as e: # type: ignore - verbose_logger.exception(f"Error connecting to backend: {e}") + verbose_logger.exception("Error connecting to backend: %s", e) await websocket.close(code=e.status_code, reason=_redact_string(str(e))) except Exception as e: - verbose_logger.exception(f"Error connecting to backend: {e}") + verbose_logger.exception("Error connecting to backend: %s", e) try: await websocket.close(code=1011, reason=_redact_string(f"Internal server error: {e}")) except RuntimeError as close_error: @@ -6298,10 +6304,10 @@ class BaseLLMHTTPHandler: await streaming.bidirectional_forward() except websockets.exceptions.InvalidStatusCode as e: # type: ignore - verbose_logger.exception(f"Error connecting to responses WS backend: {e}") + verbose_logger.exception("Error connecting to responses WS backend: %s", e) await websocket.close(code=e.status_code, reason=_redact_string(str(e))) except Exception as e: - verbose_logger.exception(f"Error in responses WS: {e}") + verbose_logger.exception("Error in responses WS: %s", e) try: await websocket.close(code=1011, reason=_redact_string(f"Internal server error: {e}")) except RuntimeError as close_error: diff --git a/litellm/llms/databricks/common_utils.py b/litellm/llms/databricks/common_utils.py index 62e2245db99..d69b97b32a1 100644 --- a/litellm/llms/databricks/common_utils.py +++ b/litellm/llms/databricks/common_utils.py @@ -386,7 +386,7 @@ class DatabricksBase: headers["User-Agent"] = self._build_user_agent(custom_user_agent) # Debug logging with redaction (never log actual tokens) - verbose_logger.debug(f"Databricks request headers: {self.redact_headers_for_logging(headers)}") + verbose_logger.debug("Databricks request headers: %s", self.redact_headers_for_logging(headers)) if endpoint_type == "chat_completions" and custom_endpoint is not True: api_base = f"{api_base}/chat/completions" diff --git a/litellm/llms/databricks/streaming_utils.py b/litellm/llms/databricks/streaming_utils.py index 74216888111..635aa04b0be 100644 --- a/litellm/llms/databricks/streaming_utils.py +++ b/litellm/llms/databricks/streaming_utils.py @@ -126,7 +126,9 @@ class ModelResponseIterator: except StopIteration: raise StopIteration except ValueError as e: - verbose_logger.debug(f"Error parsing chunk: {e},\nReceived chunk: {chunk}. Defaulting to empty chunk here.") + verbose_logger.debug( + "Error parsing chunk: %s,\nReceived chunk: %s. Defaulting to empty chunk here.", e, chunk + ) return GenericStreamingChunk( text="", is_finished=False, @@ -171,7 +173,9 @@ class ModelResponseIterator: except StopAsyncIteration: raise StopAsyncIteration except ValueError as e: - verbose_logger.debug(f"Error parsing chunk: {e},\nReceived chunk: {chunk}. Defaulting to empty chunk here.") + verbose_logger.debug( + "Error parsing chunk: %s,\nReceived chunk: %s. Defaulting to empty chunk here.", e, chunk + ) return GenericStreamingChunk( text="", is_finished=False, diff --git a/litellm/llms/gemini/files/transformation.py b/litellm/llms/gemini/files/transformation.py index 89ac56979bb..274e5474101 100644 --- a/litellm/llms/gemini/files/transformation.py +++ b/litellm/llms/gemini/files/transformation.py @@ -190,7 +190,7 @@ class GoogleAIStudioFilesHandler(GeminiModelInfo, BaseFilesConfig): status_details=None, ) except Exception as e: - verbose_logger.exception(f"Error parsing file upload response: {e}") + verbose_logger.exception("Error parsing file upload response: %s", e) raise ValueError(f"Error parsing file upload response: {e}") def transform_retrieve_file_request( @@ -263,9 +263,9 @@ class GoogleAIStudioFilesHandler(GeminiModelInfo, BaseFilesConfig): Transform Gemini's file retrieval response into OpenAI-style FileObject """ try: - verbose_logger.debug(f"Retrieve file response: {raw_response.text}") + verbose_logger.debug("Retrieve file response: %s", raw_response.text) response_json = raw_response.json() - verbose_logger.debug(f"Response JSON: {response_json}") + verbose_logger.debug("Response JSON: %s", response_json) # Map Gemini state to OpenAI status gemini_state = response_json.get("state", "STATE_UNSPECIFIED") # Explicitly type status as the Literal union @@ -294,7 +294,7 @@ class GoogleAIStudioFilesHandler(GeminiModelInfo, BaseFilesConfig): status_details=(str(response_json.get("error", "")) if gemini_state == "FAILED" else None), ) except Exception as e: - verbose_logger.exception(f"Error parsing file retrieve response: {e}") + verbose_logger.exception("Error parsing file retrieve response: %s", e) raise ValueError(f"Error parsing file retrieve response: {e}") def transform_delete_file_request( @@ -362,7 +362,7 @@ class GoogleAIStudioFilesHandler(GeminiModelInfo, BaseFilesConfig): else: raise ValueError(f"Failed to delete file: {raw_response.text}") except Exception as e: - verbose_logger.exception(f"Error parsing file delete response: {e}") + verbose_logger.exception("Error parsing file delete response: %s", e) raise ValueError(f"Error parsing file delete response: {e}") def transform_list_files_request( diff --git a/litellm/llms/gemini/realtime/transformation.py b/litellm/llms/gemini/realtime/transformation.py index 6631c9d9ec7..0d56e3f92bc 100644 --- a/litellm/llms/gemini/realtime/transformation.py +++ b/litellm/llms/gemini/realtime/transformation.py @@ -154,7 +154,7 @@ class GeminiRealtimeConfig(BaseRealtimeConfig): if "parts" in model_turn: parts = model_turn["parts"] if len(parts) != 1: - verbose_logger.warning(f"Realtime: Expected 1 part, got {len(parts)} for Gemini model turn event.") + verbose_logger.warning("Realtime: Expected 1 part, got %s for Gemini model turn event.", len(parts)) part = parts[0] if "text" in part: return OpenAIRealtimeEventTypes.RESPONSE_TEXT_DELTA @@ -472,7 +472,7 @@ class GeminiRealtimeConfig(BaseRealtimeConfig): call_id = item.get("call_id", "") output = item.get("output", "{}") - verbose_logger.debug(f"Gemini Realtime: Transforming function_call_output for call_id={call_id}") + verbose_logger.debug("Gemini Realtime: Transforming function_call_output for call_id=%s", call_id) # Gemini functionResponses[].response must be a dict; wrap non-dicts. try: @@ -487,8 +487,8 @@ class GeminiRealtimeConfig(BaseRealtimeConfig): self._tool_call_id_to_name.move_to_end(call_id) else: verbose_logger.warning( - f"Gemini Realtime: Function name not found for call_id={call_id}. " - "This may cause Gemini to reject the response." + "Gemini Realtime: Function name not found for call_id=%s. This may cause Gemini to reject the response.", + call_id, ) function_response: dict[str, Any] = {"response": output_dict} @@ -868,7 +868,7 @@ class GeminiRealtimeConfig(BaseRealtimeConfig): resolved_response_id = response_id or f"resp_{uuid.uuid4()}" resolved_output_item_id = output_item_id or f"item_{uuid.uuid4()}" - verbose_logger.debug(f"Gemini Realtime: Transforming {len(function_calls)} tool call(s) to OpenAI format") + verbose_logger.debug("Gemini Realtime: Transforming %s tool call(s) to OpenAI format", len(function_calls)) events: list[OpenAIRealtimeFunctionCallArgumentsDone] = [] for idx, fc in enumerate(function_calls): diff --git a/litellm/llms/gigachat/authenticator.py b/litellm/llms/gigachat/authenticator.py index 356d438c6b2..9fc60ee058d 100644 --- a/litellm/llms/gigachat/authenticator.py +++ b/litellm/llms/gigachat/authenticator.py @@ -162,7 +162,7 @@ def _request_token_sync( } data = {"scope": scope} - verbose_logger.debug(f"Requesting GigaChat access token from {auth_url}") + verbose_logger.debug("Requesting GigaChat access token from %s", auth_url) try: client = _get_http_client() @@ -194,7 +194,7 @@ async def _request_token_async( } data = {"scope": scope} - verbose_logger.debug(f"Requesting GigaChat access token from {auth_url}") + verbose_logger.debug("Requesting GigaChat access token from %s", auth_url) try: client = get_async_httpx_client( diff --git a/litellm/llms/gigachat/chat/transformation.py b/litellm/llms/gigachat/chat/transformation.py index 4007588cfc5..d907ae2dcdf 100644 --- a/litellm/llms/gigachat/chat/transformation.py +++ b/litellm/llms/gigachat/chat/transformation.py @@ -268,7 +268,7 @@ class GigaChatConfig(BaseConfig): api_base=self._current_api_base, ) except Exception as e: - verbose_logger.error(f"Failed to upload image: {e}") + verbose_logger.error("Failed to upload image: %s", e) return None def transform_request( diff --git a/litellm/llms/gigachat/file_handler.py b/litellm/llms/gigachat/file_handler.py index ee16a6c5870..6c2e6d17915 100644 --- a/litellm/llms/gigachat/file_handler.py +++ b/litellm/llms/gigachat/file_handler.py @@ -97,7 +97,7 @@ def upload_file_sync( # Check cache if url_hash in _file_cache: - verbose_logger.debug(f"Image found in cache: {url_hash[:16]}...") + verbose_logger.debug("Image found in cache: %s...", url_hash[:16]) return _file_cache[url_hash] try: @@ -107,7 +107,7 @@ def upload_file_sync( content_bytes, content_type, ext = parsed verbose_logger.debug("Decoded base64 image") else: - verbose_logger.debug(f"Downloading image from URL: {image_url[:80]}...") + verbose_logger.debug("Downloading image from URL: %s...", image_url[:80]) content_bytes, content_type, ext = _download_image_sync(image_url) filename = f"{uuid.uuid4()}.{ext}" @@ -133,12 +133,12 @@ def upload_file_sync( file_id = result.get("id") if file_id: _file_cache[url_hash] = file_id - verbose_logger.debug(f"File uploaded successfully, file_id: {file_id}") + verbose_logger.debug("File uploaded successfully, file_id: %s", file_id) return file_id except Exception as e: - verbose_logger.error(f"Error uploading file to GigaChat: {e}") + verbose_logger.error("Error uploading file to GigaChat: %s", e) return None @@ -162,7 +162,7 @@ async def upload_file_async( # Check cache if url_hash in _file_cache: - verbose_logger.debug(f"Image found in cache: {url_hash[:16]}...") + verbose_logger.debug("Image found in cache: %s...", url_hash[:16]) return _file_cache[url_hash] try: @@ -172,7 +172,7 @@ async def upload_file_async( content_bytes, content_type, ext = parsed verbose_logger.debug("Decoded base64 image") else: - verbose_logger.debug(f"Downloading image from URL: {image_url[:80]}...") + verbose_logger.debug("Downloading image from URL: %s...", image_url[:80]) content_bytes, content_type, ext = await _download_image_async(image_url) filename = f"{uuid.uuid4()}.{ext}" @@ -201,10 +201,10 @@ async def upload_file_async( file_id = result.get("id") if file_id: _file_cache[url_hash] = file_id - verbose_logger.debug(f"File uploaded successfully, file_id: {file_id}") + verbose_logger.debug("File uploaded successfully, file_id: %s", file_id) return file_id except Exception as e: - verbose_logger.error(f"Error uploading file to GigaChat: {e}") + verbose_logger.error("Error uploading file to GigaChat: %s", e) return None diff --git a/litellm/llms/github_copilot/authenticator.py b/litellm/llms/github_copilot/authenticator.py index 180c2215212..b4bd9c4de3d 100644 --- a/litellm/llms/github_copilot/authenticator.py +++ b/litellm/llms/github_copilot/authenticator.py @@ -58,7 +58,7 @@ class Authenticator: verbose_logger.warning("No existing access token found or error reading file") for attempt in range(3): - verbose_logger.debug(f"Access token acquisition attempt {attempt + 1}/3") + verbose_logger.debug("Access token acquisition attempt %s/3", attempt + 1) try: access_token = self._login() try: @@ -68,7 +68,7 @@ class Authenticator: verbose_logger.error("Error saving access token to file") return access_token except (GetDeviceCodeError, GetAccessTokenError, RefreshAPIKeyError) as e: - verbose_logger.warning(f"Failed attempt {attempt + 1}: {e}") + verbose_logger.warning("Failed attempt %s: %s", attempt + 1, e) continue raise GetAccessTokenError( @@ -100,7 +100,7 @@ class Authenticator: except OSError: verbose_logger.warning("No API key file found or error opening file") except (json.JSONDecodeError, KeyError) as e: - verbose_logger.warning(f"Error reading API key from file: {e}") + verbose_logger.warning("Error reading API key from file: %s", e) except APIKeyExpiredError: pass # Already logged in the try block @@ -117,7 +117,7 @@ class Authenticator: status_code=401, ) except OSError as e: - verbose_logger.error(f"Error saving API key to file: {e}") + verbose_logger.error("Error saving API key to file: %s", e) raise GetAPIKeyError( message=f"Failed to save API key: {e}", status_code=500, @@ -142,7 +142,7 @@ class Authenticator: api_endpoint = endpoints.get("api") return api_endpoint except (OSError, json.JSONDecodeError, KeyError) as e: - verbose_logger.warning(f"Error reading API endpoint from file: {e}") + verbose_logger.warning("Error reading API endpoint from file: %s", e) return None def _refresh_api_key(self) -> dict[str, Any]: @@ -171,11 +171,11 @@ class Authenticator: if "token" in response_json: return response_json else: - verbose_logger.warning(f"API key response missing token: {response_json}") + verbose_logger.warning("API key response missing token: %s", response_json) except httpx.HTTPStatusError as e: - verbose_logger.error(f"HTTP error refreshing API key (attempt {attempt + 1}/{max_retries}): {e}") + verbose_logger.error("HTTP error refreshing API key (attempt %s/%s): %s", attempt + 1, max_retries, e) except Exception as e: - verbose_logger.error(f"Unexpected error refreshing API key: {e}") + verbose_logger.error("Unexpected error refreshing API key: %s", e) raise RefreshAPIKeyError( message="Failed to refresh API key after maximum retries", @@ -237,7 +237,7 @@ class Authenticator: required_fields = ["device_code", "user_code", "verification_uri"] if not all(field in resp_json for field in required_fields): - verbose_logger.error(f"Response missing required fields: {resp_json}") + verbose_logger.error("Response missing required fields: %s", resp_json) raise GetDeviceCodeError( message="Response missing required fields", status_code=400, @@ -245,19 +245,19 @@ class Authenticator: return resp_json except httpx.HTTPStatusError as e: - verbose_logger.error(f"HTTP error getting device code: {e}") + verbose_logger.error("HTTP error getting device code: %s", e) raise GetDeviceCodeError( message=f"Failed to get device code: {e}", status_code=400, ) except json.JSONDecodeError as e: - verbose_logger.error(f"Error decoding JSON response: {e}") + verbose_logger.error("Error decoding JSON response: %s", e) raise GetDeviceCodeError( message=f"Failed to decode device code response: {e}", status_code=400, ) except Exception as e: - verbose_logger.error(f"Unexpected error getting device code: {e}") + verbose_logger.error("Unexpected error getting device code: %s", e) raise GetDeviceCodeError( message=f"Failed to get device code: {e}", status_code=400, @@ -300,23 +300,23 @@ class Authenticator: verbose_logger.info("Authentication successful!") return resp_json["access_token"] elif "error" in resp_json and resp_json.get("error") == "authorization_pending": - verbose_logger.debug(f"Authorization pending (attempt {attempt + 1}/{max_attempts})") + verbose_logger.debug("Authorization pending (attempt %s/%s)", attempt + 1, max_attempts) else: - verbose_logger.warning(f"Unexpected response: {resp_json}") + verbose_logger.warning("Unexpected response: %s", resp_json) except httpx.HTTPStatusError as e: - verbose_logger.error(f"HTTP error polling for access token: {e}") + verbose_logger.error("HTTP error polling for access token: %s", e) raise GetAccessTokenError( message=f"Failed to get access token: {e}", status_code=400, ) except json.JSONDecodeError as e: - verbose_logger.error(f"Error decoding JSON response: {e}") + verbose_logger.error("Error decoding JSON response: %s", e) raise GetAccessTokenError( message=f"Failed to decode access token response: {e}", status_code=400, ) except Exception as e: - verbose_logger.error(f"Unexpected error polling for access token: {e}") + verbose_logger.error("Unexpected error polling for access token: %s", e) raise GetAccessTokenError( message=f"Failed to get access token: {e}", status_code=400, diff --git a/litellm/llms/github_copilot/embedding/transformation.py b/litellm/llms/github_copilot/embedding/transformation.py index 75c2d0e8c40..89e195e2d76 100644 --- a/litellm/llms/github_copilot/embedding/transformation.py +++ b/litellm/llms/github_copilot/embedding/transformation.py @@ -75,7 +75,7 @@ class GithubCopilotEmbeddingConfig(BaseEmbeddingConfig): # Merge with existing headers (user's extra_headers take priority) merged_headers = {**default_headers, **headers} - verbose_logger.debug(f"GitHub Copilot Embedding API: Successfully configured headers for model {model}") + verbose_logger.debug("GitHub Copilot Embedding API: Successfully configured headers for model %s", model) return merged_headers diff --git a/litellm/llms/github_copilot/responses/transformation.py b/litellm/llms/github_copilot/responses/transformation.py index 170ad938efb..079ad760aea 100644 --- a/litellm/llms/github_copilot/responses/transformation.py +++ b/litellm/llms/github_copilot/responses/transformation.py @@ -222,14 +222,14 @@ class GithubCopilotResponsesAPIConfig(OpenAIResponsesAPIConfig): if input_param is not None: initiator = self._get_initiator(input_param) merged_headers["X-Initiator"] = initiator - verbose_logger.debug(f"GitHub Copilot Responses API: Set X-Initiator={initiator}") + verbose_logger.debug("GitHub Copilot Responses API: Set X-Initiator=%s", initiator) # Add vision header if input contains images if self._has_vision_input(input_param): merged_headers["copilot-vision-request"] = "true" verbose_logger.debug("GitHub Copilot Responses API: Enabled vision request") - verbose_logger.debug(f"GitHub Copilot Responses API: Successfully configured headers for model {model}") + verbose_logger.debug("GitHub Copilot Responses API: Successfully configured headers for model %s", model) return merged_headers @@ -295,7 +295,8 @@ class GithubCopilotResponsesAPIConfig(OpenAIResponsesAPIConfig): filtered_item[k] = v verbose_logger.debug( - f"GitHub Copilot reasoning item processed, encrypted_content preserved: {encrypted_content is not None}" + "GitHub Copilot reasoning item processed, encrypted_content preserved: %s", + encrypted_content is not None, ) return filtered_item return item @@ -379,7 +380,7 @@ class GithubCopilotResponsesAPIConfig(OpenAIResponsesAPIConfig): """ if depth > max_depth: verbose_logger.warning( - f"[GitHub Copilot] Max recursion depth {max_depth} reached while checking for vision content" + "[GitHub Copilot] Max recursion depth %s reached while checking for vision content", max_depth ) return False diff --git a/litellm/llms/groq/chat/transformation.py b/litellm/llms/groq/chat/transformation.py index 64537e33d0e..35a4a14057f 100644 --- a/litellm/llms/groq/chat/transformation.py +++ b/litellm/llms/groq/chat/transformation.py @@ -99,7 +99,7 @@ class GroqChatConfig(OpenAILikeChatConfig): if litellm.supports_reasoning(model=model, custom_llm_provider=self.custom_llm_provider): base_params.append("reasoning_effort") except Exception as e: - verbose_logger.debug(f"Error checking if model supports reasoning: {e}") + verbose_logger.debug("Error checking if model supports reasoning: %s", e) return base_params diff --git a/litellm/llms/huggingface/chat/transformation.py b/litellm/llms/huggingface/chat/transformation.py index da1ebd7c23a..b02e5c174a8 100644 --- a/litellm/llms/huggingface/chat/transformation.py +++ b/litellm/llms/huggingface/chat/transformation.py @@ -148,7 +148,7 @@ class HuggingFaceChatConfig(OpenAIGPTConfig): provider_mapping = provider_mapping[provider] if provider_mapping["status"] == "staging": logger.warning( - f"Model {model_id} is in staging mode for provider {provider}. Meant for test purposes only." + "Model %s is in staging mode for provider %s. Meant for test purposes only.", model_id, provider ) mapped_model = provider_mapping["providerId"] diff --git a/litellm/llms/langflow/chat/transformation.py b/litellm/llms/langflow/chat/transformation.py index 69af32fc840..e84b7677ad2 100644 --- a/litellm/llms/langflow/chat/transformation.py +++ b/litellm/llms/langflow/chat/transformation.py @@ -168,7 +168,7 @@ class LangFlowConfig(BaseConfig): if session_id: payload["session_id"] = session_id - verbose_logger.debug(f"LangFlow request payload: {payload}") + verbose_logger.debug("LangFlow request payload: %s", payload) return payload def _extract_content_from_response(self, response_json: dict) -> str | None: @@ -235,7 +235,7 @@ class LangFlowConfig(BaseConfig): status_code=raw_response.status_code, ) - verbose_logger.debug(f"LangFlow response: {response_json}") + verbose_logger.debug("LangFlow response: %s", response_json) content = self._extract_content_from_response(response_json) if content is None: @@ -265,7 +265,7 @@ class LangFlowConfig(BaseConfig): ) setattr(model_response, "usage", usage) except Exception as e: - verbose_logger.warning(f"Failed to calculate token usage: {e}") + verbose_logger.warning("Failed to calculate token usage: %s", e) return model_response diff --git a/litellm/llms/langgraph/chat/sse_iterator.py b/litellm/llms/langgraph/chat/sse_iterator.py index bdaa34871cf..8815d5c93da 100644 --- a/litellm/llms/langgraph/chat/sse_iterator.py +++ b/litellm/llms/langgraph/chat/sse_iterator.py @@ -62,7 +62,7 @@ class LangGraphSSEStreamIterator: data = json.loads(json_str) return self._process_data(data) except json.JSONDecodeError: - verbose_logger.debug(f"Skipping non-JSON SSE line: {line[:100]}") + verbose_logger.debug("Skipping non-JSON SSE line: %s", line[:100]) return None return None @@ -196,7 +196,7 @@ class LangGraphSSEStreamIterator: except httpx.StreamClosed: raise StopIteration except Exception as e: - verbose_logger.error(f"Error in LangGraph SSE stream: {e}") + verbose_logger.error("Error in LangGraph SSE stream: %s", e) raise StopIteration async def __anext__(self) -> ModelResponseStream: @@ -224,5 +224,5 @@ class LangGraphSSEStreamIterator: except httpx.StreamClosed: raise StopAsyncIteration except Exception as e: - verbose_logger.error(f"Error in LangGraph SSE stream: {e}") + verbose_logger.error("Error in LangGraph SSE stream: %s", e) raise StopAsyncIteration diff --git a/litellm/llms/langgraph/chat/transformation.py b/litellm/llms/langgraph/chat/transformation.py index 2aa96ddb978..3f6b0c327d2 100644 --- a/litellm/llms/langgraph/chat/transformation.py +++ b/litellm/llms/langgraph/chat/transformation.py @@ -223,7 +223,7 @@ class LangGraphConfig(BaseConfig): if "thread_id" in optional_params: payload["thread_id"] = optional_params["thread_id"] - verbose_logger.debug(f"LangGraph request payload: {payload}") + verbose_logger.debug("LangGraph request payload: %s", payload) return payload def _extract_content_from_response(self, response_json: dict) -> str: @@ -297,7 +297,7 @@ class LangGraphConfig(BaseConfig): if client is None or not isinstance(client, HTTPHandler): client = _get_httpx_client(params={}) - verbose_logger.debug(f"Making sync streaming request to: {api_base}") + verbose_logger.debug("Making sync streaming request to: %s", api_base) # Make streaming request response = client.post( @@ -356,7 +356,7 @@ class LangGraphConfig(BaseConfig): if client is None or not isinstance(client, AsyncHTTPHandler): client = get_async_httpx_client(llm_provider=cast(Any, "langgraph"), params={}) - verbose_logger.debug(f"Making async streaming request to: {api_base}") + verbose_logger.debug("Making async streaming request to: %s", api_base) # Make async streaming request response = await client.post( @@ -422,7 +422,7 @@ class LangGraphConfig(BaseConfig): """ try: response_json = raw_response.json() - verbose_logger.debug(f"LangGraph response: {response_json}") + verbose_logger.debug("LangGraph response: %s", response_json) content = self._extract_content_from_response(response_json) @@ -451,12 +451,12 @@ class LangGraphConfig(BaseConfig): ) setattr(model_response, "usage", usage) except Exception as e: - verbose_logger.warning(f"Failed to calculate token usage: {e}") + verbose_logger.warning("Failed to calculate token usage: %s", e) return model_response except Exception as e: - verbose_logger.error(f"Error processing LangGraph response: {e}") + verbose_logger.error("Error processing LangGraph response: %s", e) raise LangGraphError( message=f"Error processing response: {e}", status_code=raw_response.status_code, diff --git a/litellm/llms/litellm_proxy/skills/code_execution.py b/litellm/llms/litellm_proxy/skills/code_execution.py index f1142a8e355..11fd80db377 100644 --- a/litellm/llms/litellm_proxy/skills/code_execution.py +++ b/litellm/llms/litellm_proxy/skills/code_execution.py @@ -141,7 +141,7 @@ class CodeExecutionHandler: response: Any = None # Initialize to avoid possibly unbound error for iteration in range(self.max_iterations): - verbose_logger.debug(f"CodeExecutionHandler: Iteration {iteration + 1}/{self.max_iterations}") + verbose_logger.debug("CodeExecutionHandler: Iteration %s/%s", iteration + 1, self.max_iterations) # Make LLM call response = await litellm.acompletion( @@ -175,7 +175,7 @@ class CodeExecutionHandler: # Check if we're done (no tool calls or not tool_calls finish reason) if stop_reason != "tool_calls" or not assistant_message.tool_calls: - verbose_logger.debug(f"CodeExecutionHandler: Completed after {iteration + 1} iterations") + verbose_logger.debug("CodeExecutionHandler: Completed after %s iterations", iteration + 1) return { "response": response, "files": generated_files, # Files returned directly with base64 content @@ -193,14 +193,14 @@ class CodeExecutionHandler: args = json.loads(tool_call.function.arguments) code = args.get("code", "") - verbose_logger.debug(f"CodeExecutionHandler: Executing code ({len(code)} chars)") + verbose_logger.debug("CodeExecutionHandler: Executing code (%s chars)", len(code)) exec_result = executor.execute( code=code, skill_files=skill_files, ) - verbose_logger.debug(f"CodeExecutionHandler: Execution result: {exec_result}") + verbose_logger.debug("CodeExecutionHandler: Execution result: %s", exec_result) execution_results.append( { @@ -232,7 +232,7 @@ class CodeExecutionHandler: tool_result += f"\n- {f['name']} ({len(file_content)} bytes)" verbose_logger.debug( - f"CodeExecutionHandler: Generated file {f['name']} ({len(file_content)} bytes)" + "CodeExecutionHandler: Generated file %s (%s bytes)", f["name"], len(file_content) ) if exec_result["error"]: @@ -268,7 +268,7 @@ class CodeExecutionHandler: ) # Max iterations reached - verbose_logger.warning(f"CodeExecutionHandler: Max iterations ({self.max_iterations}) reached") + verbose_logger.warning("CodeExecutionHandler: Max iterations (%s) reached", self.max_iterations) return { "response": response, "files": generated_files, diff --git a/litellm/llms/litellm_proxy/skills/handler.py b/litellm/llms/litellm_proxy/skills/handler.py index cc307917af4..efe5c27b7ba 100644 --- a/litellm/llms/litellm_proxy/skills/handler.py +++ b/litellm/llms/litellm_proxy/skills/handler.py @@ -100,7 +100,7 @@ class LiteLLMSkillsHandler: if data.file_type is not None: skill_data["file_type"] = data.file_type - verbose_logger.debug(f"LiteLLMSkillsHandler: Creating skill {skill_id} with title={data.display_title}") + verbose_logger.debug("LiteLLMSkillsHandler: Creating skill %s with title=%s", skill_id, data.display_title) new_skill = await SkillsRepository(prisma_client).table.create(data=skill_data) return _prisma_skill_to_litellm(new_skill) @@ -113,7 +113,7 @@ class LiteLLMSkillsHandler: ) -> list[LiteLLM_SkillsTable]: prisma_client = await LiteLLMSkillsHandler._get_prisma_client() - verbose_logger.debug(f"LiteLLMSkillsHandler: Listing skills with limit={limit}, offset={offset}") + verbose_logger.debug("LiteLLMSkillsHandler: Listing skills with limit=%s, offset=%s", limit, offset) find_many_kwargs: dict[str, Any] = { "take": limit, @@ -150,7 +150,7 @@ class LiteLLMSkillsHandler: skill_id: str, user_api_key_dict: UserAPIKeyAuth | None = None, ) -> LiteLLM_SkillsTable: - verbose_logger.debug(f"LiteLLMSkillsHandler: Getting skill {skill_id}") + verbose_logger.debug("LiteLLMSkillsHandler: Getting skill %s", skill_id) skill = await LiteLLMSkillsHandler._load_skill(skill_id) # Same "not found" message for both "missing" and "cross-tenant" @@ -166,7 +166,7 @@ class LiteLLMSkillsHandler: user_api_key_dict: UserAPIKeyAuth | None = None, ) -> dict[str, str]: prisma_client = await LiteLLMSkillsHandler._get_prisma_client() - verbose_logger.debug(f"LiteLLMSkillsHandler: Deleting skill {skill_id}") + verbose_logger.debug("LiteLLMSkillsHandler: Deleting skill %s", skill_id) skill = await LiteLLMSkillsHandler._load_skill(skill_id) if skill is None or not user_can_access_resource_owner(getattr(skill, "created_by", None), user_api_key_dict): @@ -189,5 +189,5 @@ class LiteLLMSkillsHandler: except ValueError: return None except Exception as e: - verbose_logger.warning(f"LiteLLMSkillsHandler: Error fetching skill {skill_id}: {e}") + verbose_logger.warning("LiteLLMSkillsHandler: Error fetching skill %s: %s", skill_id, e) return None diff --git a/litellm/llms/litellm_proxy/skills/prompt_injection.py b/litellm/llms/litellm_proxy/skills/prompt_injection.py index 244d4196404..f411da8f04c 100644 --- a/litellm/llms/litellm_proxy/skills/prompt_injection.py +++ b/litellm/llms/litellm_proxy/skills/prompt_injection.py @@ -66,7 +66,7 @@ class SkillPromptInjectionHandler: return f"## Skill: {skill.display_title or skill.skill_id}\n\n{content}" except Exception as e: verbose_logger.warning( - f"SkillPromptInjectionHandler: Error extracting content from skill {skill.skill_id}: {e}" + "SkillPromptInjectionHandler: Error extracting content from skill %s: %s", skill.skill_id, e ) return skill.instructions @@ -111,14 +111,16 @@ class SkillPromptInjectionHandler: normalized = posixpath.normpath(clean_path) if normalized.startswith("..") or posixpath.isabs(normalized): verbose_logger.warning( - f"SkillPromptInjectionHandler: Skipping entry with invalid path in skill {skill.skill_id}: {name}" + "SkillPromptInjectionHandler: Skipping entry with invalid path in skill %s: %s", + skill.skill_id, + name, ) continue files[normalized] = zf.read(name) except Exception as e: verbose_logger.warning( - f"SkillPromptInjectionHandler: Error extracting files from skill {skill.skill_id}: {e}" + "SkillPromptInjectionHandler: Error extracting files from skill %s: %s", skill.skill_id, e ) return files diff --git a/litellm/llms/litellm_proxy/skills/sandbox_executor.py b/litellm/llms/litellm_proxy/skills/sandbox_executor.py index e79b0c948c4..78939f3e03b 100644 --- a/litellm/llms/litellm_proxy/skills/sandbox_executor.py +++ b/litellm/llms/litellm_proxy/skills/sandbox_executor.py @@ -96,7 +96,7 @@ class SkillsSandboxExecutor: # Create the file in temp directory local_path = os.path.abspath(os.path.join(tmpdir, path)) if not local_path.startswith(tmpdir_abs + os.sep): - verbose_logger.warning(f"SkillsSandboxExecutor: Skipping file with invalid path: {path}") + verbose_logger.warning("SkillsSandboxExecutor: Skipping file with invalid path: %s", path) continue os.makedirs(os.path.dirname(local_path), exist_ok=True) with open(local_path, "wb") as f: @@ -106,7 +106,7 @@ class SkillsSandboxExecutor: sandbox_path = f"/sandbox/{path}" session.copy_to_runtime(local_path, sandbox_path) - verbose_logger.debug(f"SkillsSandboxExecutor: Copied {len(skill_files)} files to sandbox") + verbose_logger.debug("SkillsSandboxExecutor: Copied %s files to sandbox", len(skill_files)) # 2. Install requirements if present. Let pip parse the # requirements file inside the sandbox so standard syntax like @@ -171,10 +171,10 @@ sys.path.insert(0, '/sandbox') verbose_logger.debug("SkillsSandboxExecutor: Code execution succeeded") else: verbose_logger.debug( - f"SkillsSandboxExecutor: Code execution failed with exit code {result.exit_code}" + "SkillsSandboxExecutor: Code execution failed with exit code %s", result.exit_code ) - verbose_logger.debug(f"SkillsSandboxExecutor: stderr: {error[:500] if error else 'No stderr'}") - verbose_logger.debug(f"SkillsSandboxExecutor: stdout: {output[:500] if output else 'No stdout'}") + verbose_logger.debug("SkillsSandboxExecutor: stderr: %s", error[:500] if error else "No stderr") + verbose_logger.debug("SkillsSandboxExecutor: stdout: %s", output[:500] if output else "No stdout") # 4. Collect generated files generated_files = self._collect_generated_files(session, skill_files) @@ -187,7 +187,7 @@ sys.path.insert(0, '/sandbox') } except Exception as e: - verbose_logger.error(f"SkillsSandboxExecutor: Execution failed: {e}") + verbose_logger.error("SkillsSandboxExecutor: Execution failed: %s", e) return { "success": False, "output": "", @@ -270,15 +270,15 @@ print(json.dumps(files)) } ) - verbose_logger.debug(f"SkillsSandboxExecutor: Collected generated file: {rel_path}") + verbose_logger.debug("SkillsSandboxExecutor: Collected generated file: %s", rel_path) except Exception as e: - verbose_logger.warning(f"SkillsSandboxExecutor: Error copying file {filepath}: {e}") + verbose_logger.warning("SkillsSandboxExecutor: Error copying file %s: %s", filepath, e) finally: if os.path.exists(tmp_path): os.unlink(tmp_path) except Exception as e: - verbose_logger.warning(f"SkillsSandboxExecutor: Error collecting generated files: {e}") + verbose_logger.warning("SkillsSandboxExecutor: Error collecting generated files: %s", e) return generated_files diff --git a/litellm/llms/manus/files/transformation.py b/litellm/llms/manus/files/transformation.py index 325f6f36814..667910fab28 100644 --- a/litellm/llms/manus/files/transformation.py +++ b/litellm/llms/manus/files/transformation.py @@ -245,10 +245,10 @@ class ManusFilesConfig(BaseFilesConfig): response_json = initial_response_data else: # Log raw response for debugging - verbose_logger.debug(f"Manus raw response text: {raw_response.text}") + verbose_logger.debug("Manus raw response text: %s", raw_response.text) response_json = raw_response.json() - verbose_logger.debug(f"Manus file response: {response_json}") + verbose_logger.debug("Manus file response: %s", response_json) # Parse created_at timestamp created_at_str = response_json.get("created_at", "") @@ -279,7 +279,7 @@ class ManusFilesConfig(BaseFilesConfig): status_details=response_json.get("status_details"), ) except Exception as e: - verbose_logger.exception(f"Error parsing Manus file response: {e}") + verbose_logger.exception("Error parsing Manus file response: %s", e) raise ValueError(f"Error parsing Manus file response: {e}") def transform_retrieve_file_request( diff --git a/litellm/llms/manus/responses/transformation.py b/litellm/llms/manus/responses/transformation.py index 25d4d0b8db6..80ffb87c76f 100644 --- a/litellm/llms/manus/responses/transformation.py +++ b/litellm/llms/manus/responses/transformation.py @@ -157,7 +157,7 @@ class ManusResponsesAPIConfig(OpenAIResponsesAPIConfig): if extra_body: base_request.update(extra_body) - verbose_logger.debug(f"Manus: Using agent_profile={agent_profile}, task_mode=agent") + verbose_logger.debug("Manus: Using agent_profile=%s, task_mode=agent", agent_profile) return base_request @@ -219,7 +219,9 @@ class ManusResponsesAPIConfig(OpenAIResponsesAPIConfig): try: response = ResponsesAPIResponse.model_validate(raw_response_json) except Exception: - verbose_logger.debug(f"Error constructing ResponsesAPIResponse: {raw_response_json}, using model_construct") + verbose_logger.debug( + "Error constructing ResponsesAPIResponse: %s, using model_construct", raw_response_json + ) response = ResponsesAPIResponse.model_construct(**raw_response_json) # Store processed headers in additional_headers so they get returned to the client @@ -307,7 +309,9 @@ class ManusResponsesAPIConfig(OpenAIResponsesAPIConfig): try: response = ResponsesAPIResponse.model_validate(raw_response_json) except Exception: - verbose_logger.debug(f"Error constructing ResponsesAPIResponse: {raw_response_json}, using model_construct") + verbose_logger.debug( + "Error constructing ResponsesAPIResponse: %s, using model_construct", raw_response_json + ) response = ResponsesAPIResponse.model_construct(**raw_response_json) # Store processed headers in additional_headers so they get returned to the client diff --git a/litellm/llms/mistral/ocr/transformation.py b/litellm/llms/mistral/ocr/transformation.py index e9d8280cc85..dbcb3307980 100644 --- a/litellm/llms/mistral/ocr/transformation.py +++ b/litellm/llms/mistral/ocr/transformation.py @@ -175,7 +175,7 @@ class MistralOCRConfig(BaseOCRConfig): Returns: OCRRequestData with JSON data """ - verbose_logger.debug(f"Mistral OCR transform_ocr_request - model: {model}") + verbose_logger.debug("Mistral OCR transform_ocr_request - model: %s", model) # Document parameter is the Mistral-format dict from the user # Just pass it through as-is to the Mistral API @@ -226,7 +226,7 @@ class MistralOCRConfig(BaseOCRConfig): try: response_json = raw_response.json() - verbose_logger.debug(f"Mistral OCR response keys: {response_json.keys()}") + verbose_logger.debug("Mistral OCR response keys: %s", response_json.keys()) # Return native Mistral format - no transformation return OCRResponse( @@ -237,5 +237,5 @@ class MistralOCRConfig(BaseOCRConfig): object="ocr", ) except Exception as e: - verbose_logger.error(f"Error parsing Mistral OCR response: {e}") + verbose_logger.error("Error parsing Mistral OCR response: %s", e) raise e diff --git a/litellm/llms/ollama/common_utils.py b/litellm/llms/ollama/common_utils.py index 83c697d7cb5..ecc56e6f110 100644 --- a/litellm/llms/ollama/common_utils.py +++ b/litellm/llms/ollama/common_utils.py @@ -119,7 +119,7 @@ class OllamaModelInfo(BaseLLMModelInfo): if isinstance(nm, str): names.add(nm if nm.startswith("ollama/") else f"ollama/{nm}") except Exception as e: - verbose_logger.warning(f"Error retrieving ollama tag endpoint: {e}") + verbose_logger.warning("Error retrieving ollama tag endpoint: %s", e) # If tags endpoint fails, fall back to static list try: from litellm import models_by_provider @@ -127,7 +127,7 @@ class OllamaModelInfo(BaseLLMModelInfo): static = models_by_provider.get("ollama", []) or [] return [f"ollama/{m}" for m in static] except Exception as e1: - verbose_logger.warning(f"Error retrieving static ollama models as fallback: {e1}") + verbose_logger.warning("Error retrieving static ollama models as fallback: %s", e1) return [] # assemble full model names result = sorted(names) diff --git a/litellm/llms/ollama/completion/transformation.py b/litellm/llms/ollama/completion/transformation.py index 5823c2dad75..ccc9fe666f2 100644 --- a/litellm/llms/ollama/completion/transformation.py +++ b/litellm/llms/ollama/completion/transformation.py @@ -538,5 +538,5 @@ class OllamaTextCompletionResponseIterator(BaseModelResponseIterator): ) # raise Exception(f"Unable to parse ollama chunk - {chunk}") except Exception as e: - verbose_proxy_logger.error(f"Unable to parse ollama chunk - {chunk}") + verbose_proxy_logger.error("Unable to parse ollama chunk - %s", chunk) raise e diff --git a/litellm/llms/openai/chat/o_series_transformation.py b/litellm/llms/openai/chat/o_series_transformation.py index 0aaf0315f2a..e5c4de0b29f 100644 --- a/litellm/llms/openai/chat/o_series_transformation.py +++ b/litellm/llms/openai/chat/o_series_transformation.py @@ -66,7 +66,7 @@ class OpenAIOSeriesConfig(OpenAIGPTConfig): model, custom_llm_provider, api_base, api_key = get_llm_provider(model=model) except Exception: verbose_logger.debug( - f"Unable to infer model provider for model={model}, defaulting to openai for o1 supported param check" + "Unable to infer model provider for model=%s, defaulting to openai for o1 supported param check", model ) custom_llm_provider = "openai" diff --git a/litellm/llms/openai/cost_calculation.py b/litellm/llms/openai/cost_calculation.py index 87568a4d399..40cfd1dd621 100644 --- a/litellm/llms/openai/cost_calculation.py +++ b/litellm/llms/openai/cost_calculation.py @@ -111,13 +111,19 @@ def cost_per_second(model: str, custom_llm_provider: str | None, duration: float ## Speech / Audio cost calculation if "output_cost_per_second" in model_info and model_info["output_cost_per_second"] is not None: verbose_logger.debug( - f"For model={model} - output_cost_per_second: {model_info.get('output_cost_per_second')}; duration: {duration}" + "For model=%s - output_cost_per_second: %s; duration: %s", + model, + model_info.get("output_cost_per_second"), + duration, ) ## COST PER SECOND ## completion_cost = model_info["output_cost_per_second"] * duration elif "input_cost_per_second" in model_info and model_info["input_cost_per_second"] is not None: verbose_logger.debug( - f"For model={model} - input_cost_per_second: {model_info.get('input_cost_per_second')}; duration: {duration}" + "For model=%s - input_cost_per_second: %s; duration: %s", + model, + model_info.get("input_cost_per_second"), + duration, ) ## COST PER SECOND ## prompt_cost = model_info["input_cost_per_second"] * duration @@ -199,19 +205,23 @@ def video_generation_cost( video_cost_per_second = model_info.get("output_cost_per_video_per_second") if video_cost_per_second is not None: verbose_logger.debug( - f"For model={model} - output_cost_per_video_per_second: {video_cost_per_second}; duration: {duration_seconds}" + "For model=%s - output_cost_per_video_per_second: %s; duration: %s", + model, + video_cost_per_second, + duration_seconds, ) return video_cost_per_second * duration_seconds output_cost_per_second = _video_output_cost_per_second(model_info, video_resolution) if output_cost_per_second is not None: verbose_logger.debug( - f"For model={model} - output_cost_per_second: {output_cost_per_second}; duration: {duration_seconds}" + "For model=%s - output_cost_per_second: %s; duration: %s", model, output_cost_per_second, duration_seconds ) return output_cost_per_second * duration_seconds # If no cost information found, return 0 verbose_logger.warning( - f"No cost information found for video model {model}. Please add pricing to model_prices_and_context_window.json" + "No cost information found for video model %s. Please add pricing to model_prices_and_context_window.json", + model, ) return 0.0 diff --git a/litellm/llms/openai/image_generation/cost_calculator.py b/litellm/llms/openai/image_generation/cost_calculator.py index b134ecc9a24..33893fd6fa7 100644 --- a/litellm/llms/openai/image_generation/cost_calculator.py +++ b/litellm/llms/openai/image_generation/cost_calculator.py @@ -20,7 +20,7 @@ def cost_calculator( """Calculate cost for OpenAI gpt-image models (token-based pricing).""" usage = getattr(image_response, "usage", None) if usage is None: - verbose_logger.debug(f"No usage data available for {model}, cannot calculate token-based cost") + verbose_logger.debug("No usage data available for %s, cannot calculate token-based cost", model) return 0.0 provider = custom_llm_provider or "openai" diff --git a/litellm/llms/openai/openai.py b/litellm/llms/openai/openai.py index f01730a06a5..151241dfb50 100644 --- a/litellm/llms/openai/openai.py +++ b/litellm/llms/openai/openai.py @@ -557,7 +557,7 @@ class OpenAIChatCompletion(BaseLLM, BaseOpenAILLM): except Exception as e: verbose_logger.exception( - f"LiteLLM.AgenticHookError: Exception in agentic completion hooks for OpenAI: {e}" + "LiteLLM.AgenticHookError: Exception in agentic completion hooks for OpenAI: %s", e ) return None diff --git a/litellm/llms/openai/responses/count_tokens/handler.py b/litellm/llms/openai/responses/count_tokens/handler.py index e59a28c2d09..e1deb47f457 100644 --- a/litellm/llms/openai/responses/count_tokens/handler.py +++ b/litellm/llms/openai/responses/count_tokens/handler.py @@ -45,7 +45,7 @@ class OpenAICountTokensHandler(OpenAICountTokensConfig): try: self.validate_request(model, input) - verbose_logger.debug(f"Processing OpenAI CountTokens request for model: {model}") + verbose_logger.debug("Processing OpenAI CountTokens request for model: %s", model) request_body = self.transform_request_to_count_tokens( model=model, @@ -56,7 +56,7 @@ class OpenAICountTokensHandler(OpenAICountTokensConfig): endpoint_url = self.get_openai_count_tokens_endpoint(api_base) - verbose_logger.debug(f"Making request to: {endpoint_url}") + verbose_logger.debug("Making request to: %s", endpoint_url) headers = self.get_required_headers(api_key) @@ -71,30 +71,30 @@ class OpenAICountTokensHandler(OpenAICountTokensConfig): timeout=request_timeout, ) - verbose_logger.debug(f"Response status: {response.status_code}") + verbose_logger.debug("Response status: %s", response.status_code) if response.status_code != 200: error_text = response.text - verbose_logger.error(f"OpenAI API error: {error_text}") + verbose_logger.error("OpenAI API error: %s", error_text) raise OpenAIError( status_code=response.status_code, message=error_text, ) openai_response = response.json() - verbose_logger.debug(f"OpenAI response: {openai_response}") + verbose_logger.debug("OpenAI response: %s", openai_response) return openai_response except OpenAIError: raise except httpx.HTTPStatusError as e: - verbose_logger.error(f"HTTP error in CountTokens handler: {e}") + verbose_logger.error("HTTP error in CountTokens handler: %s", e) raise OpenAIError( status_code=e.response.status_code, message=e.response.text, ) except (httpx.RequestError, json.JSONDecodeError, ValueError) as e: - verbose_logger.error(f"Error in CountTokens handler: {e}") + verbose_logger.error("Error in CountTokens handler: %s", e) raise OpenAIError( status_code=500, message=f"CountTokens processing error: {e}", diff --git a/litellm/llms/openai/responses/count_tokens/token_counter.py b/litellm/llms/openai/responses/count_tokens/token_counter.py index d4494759f6c..af65cdbe91d 100644 --- a/litellm/llms/openai/responses/count_tokens/token_counter.py +++ b/litellm/llms/openai/responses/count_tokens/token_counter.py @@ -89,7 +89,7 @@ class OpenAITokenCounter(BaseTokenCounter): original_response=result, ) except OpenAIError as e: - verbose_logger.warning(f"OpenAI CountTokens API error: status={e.status_code}, message={e.message}") + verbose_logger.warning("OpenAI CountTokens API error: status=%s, message=%s", e.status_code, e.message) return TokenCountResponse( total_tokens=0, request_model=request_model, @@ -100,7 +100,7 @@ class OpenAITokenCounter(BaseTokenCounter): status_code=e.status_code, ) except Exception as e: - verbose_logger.warning(f"Error calling OpenAI CountTokens API: {e}") + verbose_logger.warning("Error calling OpenAI CountTokens API: %s", e) return TokenCountResponse( total_tokens=0, request_model=request_model, diff --git a/litellm/llms/openai/responses/transformation.py b/litellm/llms/openai/responses/transformation.py index 2d0ce47e595..d84a9d2cda7 100644 --- a/litellm/llms/openai/responses/transformation.py +++ b/litellm/llms/openai/responses/transformation.py @@ -209,7 +209,7 @@ class OpenAIResponsesAPIConfig(BaseResponsesAPIConfig): elif isinstance(item, dict): # Handle reasoning items specifically to filter out status=None if item.get("type") == "reasoning": - verbose_logger.debug(f"Handling reasoning item: {item}") + verbose_logger.debug("Handling reasoning item: %s", item) # Type assertion since we know it's a dict at this point dict_item = cast(dict[str, Any], item) filtered_item = self._handle_reasoning_item(dict_item) @@ -251,7 +251,7 @@ class OpenAIResponsesAPIConfig(BaseResponsesAPIConfig): return dict_reasoning_item except Exception as e: - verbose_logger.debug(f"Failed to create ResponseReasoningItem, falling back to manual filtering: {e}") + verbose_logger.debug("Failed to create ResponseReasoningItem, falling back to manual filtering: %s", e) # Fallback: manually filter out known None fields filtered_item = { k: v @@ -282,7 +282,9 @@ class OpenAIResponsesAPIConfig(BaseResponsesAPIConfig): try: response = ResponsesAPIResponse.model_validate(raw_response_json) except Exception: - verbose_logger.debug(f"Error constructing ResponsesAPIResponse: {raw_response_json}, using model_construct") + verbose_logger.debug( + "Error constructing ResponsesAPIResponse: %s, using model_construct", raw_response_json + ) response = ResponsesAPIResponse.model_construct(**raw_response_json) # Store processed headers in additional_headers so they get returned to the client @@ -429,7 +431,7 @@ class OpenAIResponsesAPIConfig(BaseResponsesAPIConfig): ): return True except Exception as e: - verbose_logger.debug(f"Error getting model info in OpenAIResponsesAPIConfig: {e}") + verbose_logger.debug("Error getting model info in OpenAIResponsesAPIConfig: %s", e) return False def supports_native_websocket(self) -> bool: @@ -649,7 +651,9 @@ class OpenAIResponsesAPIConfig(BaseResponsesAPIConfig): try: response = ResponsesAPIResponse.model_validate(raw_response_json) except Exception: - verbose_logger.debug(f"Error constructing ResponsesAPIResponse: {raw_response_json}, using model_construct") + verbose_logger.debug( + "Error constructing ResponsesAPIResponse: %s, using model_construct", raw_response_json + ) response = ResponsesAPIResponse.model_construct(**raw_response_json) response._hidden_params["additional_headers"] = processed_headers diff --git a/litellm/llms/openai_like/dynamic_config.py b/litellm/llms/openai_like/dynamic_config.py index 40c3e2a07a7..57af268fe6a 100644 --- a/litellm/llms/openai_like/dynamic_config.py +++ b/litellm/llms/openai_like/dynamic_config.py @@ -110,8 +110,9 @@ def create_config_class(provider: SimpleProviderConfig): if param in supported_params: supported_params.remove(param) verbose_logger.debug( - f"Model {model} on provider {provider.slug} does not support " - f"function calling — removed tool-related params from supported params." + "Model %s on provider %s does not support function calling — removed tool-related params from supported params.", + model, + provider.slug, ) _supports_reasoning = supports_reasoning(model=model, custom_llm_provider=provider.slug) diff --git a/litellm/llms/openai_like/json_loader.py b/litellm/llms/openai_like/json_loader.py index bc10b7bd62f..5c6e8f643ce 100644 --- a/litellm/llms/openai_like/json_loader.py +++ b/litellm/llms/openai_like/json_loader.py @@ -51,7 +51,7 @@ class JSONProviderRegistry: cls._loaded = True except Exception as e: - verbose_logger.warning(f"Warning: Failed to load JSON provider configs: {e}") + verbose_logger.warning("Warning: Failed to load JSON provider configs: %s", e) cls._loaded = True @classmethod diff --git a/litellm/llms/perplexity/chat/transformation.py b/litellm/llms/perplexity/chat/transformation.py index c6fb750ec1b..5a4e3440201 100644 --- a/litellm/llms/perplexity/chat/transformation.py +++ b/litellm/llms/perplexity/chat/transformation.py @@ -52,13 +52,13 @@ class PerplexityChatConfig(OpenAIGPTConfig): if litellm.supports_reasoning(model=model, custom_llm_provider=self.custom_llm_provider): base_openai_params.append("reasoning_effort") except Exception as e: - verbose_logger.debug(f"Error checking if model supports reasoning: {e}") + verbose_logger.debug("Error checking if model supports reasoning: %s", e) try: if litellm.supports_web_search(model=model, custom_llm_provider=self.custom_llm_provider): base_openai_params.append("web_search_options") except Exception as e: - verbose_logger.debug(f"Error checking if model supports web search: {e}") + verbose_logger.debug("Error checking if model supports web search: %s", e) return base_openai_params @@ -97,7 +97,7 @@ class PerplexityChatConfig(OpenAIGPTConfig): self._enhance_usage_with_perplexity_fields(model_response, raw_response_json) self._add_citations_as_annotations(model_response, raw_response_json) except Exception as e: - verbose_logger.debug(f"Error extracting Perplexity-specific usage fields: {e}") + verbose_logger.debug("Error extracting Perplexity-specific usage fields: %s", e) return model_response diff --git a/litellm/llms/runwayml/image_generation/transformation.py b/litellm/llms/runwayml/image_generation/transformation.py index ba51a7ba093..5833892c866 100644 --- a/litellm/llms/runwayml/image_generation/transformation.py +++ b/litellm/llms/runwayml/image_generation/transformation.py @@ -170,7 +170,7 @@ class RunwayMLImageGenerationConfig(BaseImageGenerationConfig): """ status = response_data.get("status", "").upper() - verbose_logger.debug(f"RunwayML task status: {status}") + verbose_logger.debug("RunwayML task status: %s", status) if status == "SUCCEEDED": return "succeeded" @@ -216,7 +216,7 @@ class RunwayMLImageGenerationConfig(BaseImageGenerationConfig): api_base = api_base.rstrip("/") task_url = f"{api_base}/v1/tasks/{task_id}" - verbose_logger.debug(f"Polling RunwayML task: {task_url}") + verbose_logger.debug("Polling RunwayML task: %s", task_url) while True: self._check_timeout(start_time=start_time, timeout_secs=timeout_secs) @@ -265,7 +265,7 @@ class RunwayMLImageGenerationConfig(BaseImageGenerationConfig): api_base = api_base.rstrip("/") task_url = f"{api_base}/v1/tasks/{task_id}" - verbose_logger.debug(f"Polling RunwayML task (async): {task_url}") + verbose_logger.debug("Polling RunwayML task (async): %s", task_url) while True: self._check_timeout(start_time=start_time, timeout_secs=timeout_secs) diff --git a/litellm/llms/runwayml/text_to_speech/transformation.py b/litellm/llms/runwayml/text_to_speech/transformation.py index 46a5f606853..21ac716df01 100644 --- a/litellm/llms/runwayml/text_to_speech/transformation.py +++ b/litellm/llms/runwayml/text_to_speech/transformation.py @@ -259,7 +259,7 @@ class RunwayMLTextToSpeechConfig(BaseTextToSpeechConfig): """ status = response_data.get("status", "").upper() - verbose_logger.debug(f"RunwayML TTS task status: {status}") + verbose_logger.debug("RunwayML TTS task status: %s", status) if status == "SUCCEEDED": return "succeeded" @@ -305,7 +305,7 @@ class RunwayMLTextToSpeechConfig(BaseTextToSpeechConfig): api_base = api_base.rstrip("/") task_url = f"{api_base}/v1/tasks/{task_id}" - verbose_logger.debug(f"Polling RunwayML TTS task: {task_url}") + verbose_logger.debug("Polling RunwayML TTS task: %s", task_url) while True: self._check_timeout(start_time=start_time, timeout_secs=timeout_secs) @@ -353,7 +353,7 @@ class RunwayMLTextToSpeechConfig(BaseTextToSpeechConfig): api_base = api_base.rstrip("/") task_url = f"{api_base}/v1/tasks/{task_id}" - verbose_logger.debug(f"Polling RunwayML TTS task (async): {task_url}") + verbose_logger.debug("Polling RunwayML TTS task (async): %s", task_url) while True: self._check_timeout(start_time=start_time, timeout_secs=timeout_secs) diff --git a/litellm/llms/sagemaker/common_utils.py b/litellm/llms/sagemaker/common_utils.py index 5f5c0250273..5916747bf28 100644 --- a/litellm/llms/sagemaker/common_utils.py +++ b/litellm/llms/sagemaker/common_utils.py @@ -130,7 +130,7 @@ class AWSEventStreamDecoder: yield self._chunk_parser(chunk_data=_data) except json.JSONDecodeError: # Handle or log any unparseable data at the end - verbose_logger.error(f"Warning: Unparseable JSON data remained: {accumulated_json}") + verbose_logger.error("Warning: Unparseable JSON data remained: %s", accumulated_json) yield None async def aiter_bytes( @@ -168,10 +168,10 @@ class AWSEventStreamDecoder: # If it's not valid JSON yet, continue to the next event continue except UnicodeDecodeError as e: - verbose_logger.warning(f"UnicodeDecodeError: {e}. Attempting to combine with next event.") + verbose_logger.warning("UnicodeDecodeError: %s. Attempting to combine with next event.", e) continue except Exception as e: - verbose_logger.error(f"Error parsing message: {e}. Attempting to combine with next event.") + verbose_logger.error("Error parsing message: %s. Attempting to combine with next event.", e) continue # Handle any remaining data after the iterator is exhausted @@ -184,10 +184,10 @@ class AWSEventStreamDecoder: yield self._chunk_parser(chunk_data=_data) except json.JSONDecodeError: # Handle or log any unparseable data at the end - verbose_logger.error(f"Warning: Unparseable JSON data remained: {accumulated_json}") + verbose_logger.error("Warning: Unparseable JSON data remained: %s", accumulated_json) yield None except Exception as e: - verbose_logger.error(f"Final error parsing accumulated JSON: {e}") + verbose_logger.error("Final error parsing accumulated JSON: %s", e) def _parse_message_from_event(self, event) -> str | None: response_stream_shape = get_sagemaker_response_stream_shape() diff --git a/litellm/llms/sap/credentials.py b/litellm/llms/sap/credentials.py index 5b2e02875b8..fe5df75fc72 100644 --- a/litellm/llms/sap/credentials.py +++ b/litellm/llms/sap/credentials.py @@ -45,7 +45,7 @@ def _get_nested(d: dict[str, Any] | str, path: Sequence[str]) -> Any: for k in path: if not isinstance(cur, dict): verbose_logger.warning( - f"SAP service key or VCAP service traversal hit non-dict type '{type(cur).__name__}' at key '{k}'." + "SAP service key or VCAP service traversal hit non-dict type '%s' at key '%s'.", type(cur).__name__, k ) return None if k not in cur: @@ -173,7 +173,7 @@ def resolve_credentials(sources: list[Source]) -> dict[str, str]: for source in sources: credentials = extract_credentials(source) if credentials: - verbose_logger.debug(f"Resolved SAP credentials from source {source.name}") + verbose_logger.debug("Resolved SAP credentials from source %s", source.name) return credentials raise ValueError("No credentials found in any source") @@ -184,7 +184,7 @@ def resolve_resource_group(sources: list[Source]) -> str | None: for source in sources: value = source.get(rg_cred) if value is not None: - verbose_logger.debug(f"Resolved GEN AI Hub resource_group from source {source.name}") + verbose_logger.debug("Resolved GEN AI Hub resource_group from source %s", source.name) return value return rg_cred.default @@ -208,7 +208,7 @@ def _parse_service_key_once( verbose_logger.warning("SAP service key is a string but not valid JSON. Skipping this source.") return None verbose_logger.warning( - f"SAP service key has unexpected type '{type(service_key).__name__}'. Expected str or dict. Ignoring." + "SAP service key has unexpected type '%s'. Expected str or dict. Ignoring.", type(service_key).__name__ ) return None diff --git a/litellm/llms/together_ai/chat.py b/litellm/llms/together_ai/chat.py index 5920f02a44e..0eefd1ff1d6 100644 --- a/litellm/llms/together_ai/chat.py +++ b/litellm/llms/together_ai/chat.py @@ -29,7 +29,7 @@ class TogetherAIConfig(OpenAIGPTConfig): try: supports_fc = supports_function_calling(model, custom_llm_provider="together_ai") except Exception as e: - verbose_logger.debug(f"Error getting supported openai params: {e}") + verbose_logger.debug("Error getting supported openai params: %s", e) optional_params = super().get_supported_openai_params(model) if supports_fc is not True: diff --git a/litellm/llms/vertex_ai/agent_engine/transformation.py b/litellm/llms/vertex_ai/agent_engine/transformation.py index 9f01a9ee506..b40e38916ed 100644 --- a/litellm/llms/vertex_ai/agent_engine/transformation.py +++ b/litellm/llms/vertex_ai/agent_engine/transformation.py @@ -137,7 +137,7 @@ class VertexAgentEngineConfig(BaseConfig, VertexBase): # (create_session, get_session, list_sessions, delete_session, etc.) endpoint = f"{base_url}/v1beta1/{resource_path}:streamQuery" - verbose_logger.debug(f"Vertex Agent Engine URL: {endpoint}") + verbose_logger.debug("Vertex Agent Engine URL: %s", endpoint) return endpoint def _get_auth_headers( @@ -155,7 +155,7 @@ class VertexAgentEngineConfig(BaseConfig, VertexBase): project_id=vertex_project, ) - verbose_logger.debug(f"Vertex Agent Engine: Authenticated for project {project_id}") + verbose_logger.debug("Vertex Agent Engine: Authenticated for project %s", project_id) return { "Authorization": f"Bearer {access_token}", @@ -219,7 +219,7 @@ class VertexAgentEngineConfig(BaseConfig, VertexBase): "input": input_data, } - verbose_logger.debug(f"Vertex Agent Engine payload: {payload}") + verbose_logger.debug("Vertex Agent Engine payload: %s", payload) return payload def validate_environment( @@ -270,7 +270,7 @@ class VertexAgentEngineConfig(BaseConfig, VertexBase): total_tokens=total_tokens, ) except Exception as e: - verbose_logger.warning(f"Failed to calculate token usage: {e}") + verbose_logger.warning("Failed to calculate token usage: %s", e) return None def transform_response( @@ -295,11 +295,11 @@ class VertexAgentEngineConfig(BaseConfig, VertexBase): """ try: content_type = raw_response.headers.get("content-type", "").lower() - verbose_logger.debug(f"Vertex Agent Engine response Content-Type: {content_type}") + verbose_logger.debug("Vertex Agent Engine response Content-Type: %s", content_type) # Parse the SSE response response_text = raw_response.text - verbose_logger.debug(f"Response (first 500 chars): {response_text[:500]}") + verbose_logger.debug("Response (first 500 chars): %s", response_text[:500]) # Extract content from SSE stream content = "" @@ -335,7 +335,7 @@ class VertexAgentEngineConfig(BaseConfig, VertexBase): return model_response except Exception as e: - verbose_logger.error(f"Error processing Vertex Agent Engine response: {e}") + verbose_logger.error("Error processing Vertex Agent Engine response: %s", e) raise VertexAgentEngineError( message=f"Error processing response: {e}", status_code=raw_response.status_code, diff --git a/litellm/llms/vertex_ai/common_utils.py b/litellm/llms/vertex_ai/common_utils.py index 81d084e7e03..8d63df1ea3d 100644 --- a/litellm/llms/vertex_ai/common_utils.py +++ b/litellm/llms/vertex_ai/common_utils.py @@ -221,7 +221,8 @@ def get_supports_system_message( supports_system_message = True except Exception as e: verbose_logger.warning( - f"Unable to identify if system message supported. Defaulting to 'False'. Received error message - {e}\nAdd it here - https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json" + "Unable to identify if system message supported. Defaulting to 'False'. Received error message - %s\nAdd it here - https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json", + e, ) supports_system_message = False diff --git a/litellm/llms/vertex_ai/cost_calculator.py b/litellm/llms/vertex_ai/cost_calculator.py index a53e54e5fc2..572a4ed14db 100644 --- a/litellm/llms/vertex_ai/cost_calculator.py +++ b/litellm/llms/vertex_ai/cost_calculator.py @@ -114,7 +114,8 @@ def cost_per_character( prompt_cost = prompt_characters * model_info["input_cost_per_character"] except Exception as e: verbose_logger.debug( - f"litellm.litellm_core_utils.llm_cost_calc.google.py::cost_per_character(): Exception occured - {e}\nDefaulting to None" + "litellm.litellm_core_utils.llm_cost_calc.google.py::cost_per_character(): Exception occured - %s\nDefaulting to None", + e, ) prompt_cost, _ = cost_per_token( model=model, @@ -152,7 +153,8 @@ def cost_per_character( completion_cost = completion_characters * model_info["output_cost_per_character"] except Exception as e: verbose_logger.debug( - f"litellm.litellm_core_utils.llm_cost_calc.google.py::cost_per_character(): Exception occured - {e}\nDefaulting to None" + "litellm.litellm_core_utils.llm_cost_calc.google.py::cost_per_character(): Exception occured - %s\nDefaulting to None", + e, ) _, completion_cost = cost_per_token( model=model, diff --git a/litellm/llms/vertex_ai/gemini/vertex_and_google_ai_studio_gemini.py b/litellm/llms/vertex_ai/gemini/vertex_and_google_ai_studio_gemini.py index cadc8760601..c3977b19c87 100644 --- a/litellm/llms/vertex_ai/gemini/vertex_and_google_ai_studio_gemini.py +++ b/litellm/llms/vertex_ai/gemini/vertex_and_google_ai_studio_gemini.py @@ -447,8 +447,8 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig): transformed_config["environment"] = env_value else: verbose_logger.info( - f"Invalid environment value for computer_use: {env_value}. " - f"Supported: 'browser', 'unspecified', 'ENVIRONMENT_BROWSER', 'ENVIRONMENT_UNSPECIFIED'" + "Invalid environment value for computer_use: %s. Supported: 'browser', 'unspecified', 'ENVIRONMENT_BROWSER', 'ENVIRONMENT_UNSPECIFIED'", + env_value, ) # Transform excluded_predefined_functions to camelCase @@ -626,7 +626,7 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig): "web_search", "web_search_preview", ): - verbose_logger.info(f"Gemini: Transforming OpenAI-style '{tool['type']}' tool to googleSearch") + verbose_logger.info("Gemini: Transforming OpenAI-style '%s' tool to googleSearch", tool["type"]) tool = {VertexToolName.GOOGLE_SEARCH.value: {}} # Handle tools with 'type' field (OpenAI spec compliance) Ignore this field -> https://github.com/BerriAI/litellm/issues/14644#issuecomment-3342061838 elif "type" in tool: @@ -1087,36 +1087,29 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig): if VertexGeminiConfig._is_gemini_3_or_newer(model): if value is not None and value < 1.0: verbose_logger.info( - f"Warning: Setting temperature < 1.0 for Gemini 3 models ({model}) " - "can cause infinite loops, degraded reasoning performance, and failure on complex tasks. " - "Strongly recommended to use temperature = 1.0 (default)." + "Warning: Setting temperature < 1.0 for Gemini 3 models (%s) can cause infinite loops, degraded reasoning performance, and failure on complex tasks. Strongly recommended to use temperature = 1.0 (default).", + model, ) if not gemini_sampling_params_warned: verbose_logger.warning( - "DeprecationWarning: `temperature`, `top_p`, and `top_k` continue to " - f"function for Gemini 3+ ({model}) but are planned for removal in a " - "future release. Move sampling guidance into the `system` " - "instructions instead." + "DeprecationWarning: `temperature`, `top_p`, and `top_k` continue to function for Gemini 3+ (%s) but are planned for removal in a future release. Move sampling guidance into the `system` instructions instead.", + model, ) gemini_sampling_params_warned = True optional_params["temperature"] = value elif param == "top_p": if VertexGeminiConfig._is_gemini_3_or_newer(model) and not gemini_sampling_params_warned: verbose_logger.warning( - "DeprecationWarning: `temperature`, `top_p`, and `top_k` continue to " - f"function for Gemini 3+ ({model}) but are planned for removal in a " - "future release. Move sampling guidance into the `system` " - "instructions instead." + "DeprecationWarning: `temperature`, `top_p`, and `top_k` continue to function for Gemini 3+ (%s) but are planned for removal in a future release. Move sampling guidance into the `system` instructions instead.", + model, ) gemini_sampling_params_warned = True optional_params["top_p"] = value elif param == "top_k": if VertexGeminiConfig._is_gemini_3_or_newer(model) and not gemini_sampling_params_warned: verbose_logger.warning( - "DeprecationWarning: `temperature`, `top_p`, and `top_k` continue to " - f"function for Gemini 3+ ({model}) but are planned for removal in a " - "future release. Move sampling guidance into the `system` " - "instructions instead." + "DeprecationWarning: `temperature`, `top_p`, and `top_k` continue to function for Gemini 3+ (%s) but are planned for removal in a future release. Move sampling guidance into the `system` instructions instead.", + model, ) gemini_sampling_params_warned = True optional_params["top_k"] = value @@ -1977,7 +1970,9 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig): prompt_feedback = processed_chunk.get("promptFeedback") if prompt_feedback and "blockReason" in prompt_feedback: verbose_logger.debug( - f"Prompt blocked due to: {prompt_feedback.get('blockReason')} - {prompt_feedback.get('blockReasonMessage')}" + "Prompt blocked due to: %s - %s", + prompt_feedback.get("blockReason"), + prompt_feedback.get("blockReasonMessage"), ) # Create a content_filter response (consistent with non-streaming _handle_blocked_response) @@ -3248,7 +3243,7 @@ class ModelResponseIterator: def chunk_parser(self, chunk: dict) -> Optional["ModelResponseStream"]: try: - verbose_logger.debug(f"RAW GEMINI CHUNK: {chunk}") + verbose_logger.debug("RAW GEMINI CHUNK: %s", chunk) # Detect mid-stream error chunks (e.g. 429 RESOURCE_EXHAUSTED). # Vertex AI can return errors as HTTP 200 but with an "error" field in the SSE body. diff --git a/litellm/llms/vertex_ai/ocr/deepseek_transformation.py b/litellm/llms/vertex_ai/ocr/deepseek_transformation.py index b66dead91b1..f148f8e8be8 100644 --- a/litellm/llms/vertex_ai/ocr/deepseek_transformation.py +++ b/litellm/llms/vertex_ai/ocr/deepseek_transformation.py @@ -259,7 +259,7 @@ class VertexAIDeepSeekOCRConfig(BaseOCRConfig): OCRResponse in standard format """ verbose_logger.debug("Vertex AI DeepSeek OCR transform_ocr_response called") - verbose_logger.debug(f"Raw response: {raw_response.text}") + verbose_logger.debug("Raw response: %s", raw_response.text) try: response_json = raw_response.json() @@ -345,7 +345,7 @@ class VertexAIDeepSeekOCRConfig(BaseOCRConfig): ) except Exception as e: - verbose_logger.error(f"Error parsing Vertex AI DeepSeek OCR response: {e}") + verbose_logger.error("Error parsing Vertex AI DeepSeek OCR response: %s", e) raise e async def async_transform_ocr_response( diff --git a/litellm/llms/vertex_ai/ocr/transformation.py b/litellm/llms/vertex_ai/ocr/transformation.py index 0fb9523f3eb..e1254c5f833 100644 --- a/litellm/llms/vertex_ai/ocr/transformation.py +++ b/litellm/llms/vertex_ai/ocr/transformation.py @@ -138,13 +138,13 @@ class VertexAIOCRConfig(MistralOCRConfig): Returns: Base64 data URI string """ - verbose_logger.debug(f"Vertex AI OCR: Converting URL to base64 data URI (sync): {url}") + verbose_logger.debug("Vertex AI OCR: Converting URL to base64 data URI (sync): %s", url) # Fetch and convert to base64 data URI # convert_url_to_base64 already returns a full data URI like "data:image/jpeg;base64,..." data_uri = convert_url_to_base64(url=url) - verbose_logger.debug(f"Vertex AI OCR: Converted URL to data URI (length: {len(data_uri)})") + verbose_logger.debug("Vertex AI OCR: Converted URL to data URI (length: %s)", len(data_uri)) return data_uri @@ -161,13 +161,13 @@ class VertexAIOCRConfig(MistralOCRConfig): Returns: Base64 data URI string """ - verbose_logger.debug(f"Vertex AI OCR: Converting URL to base64 data URI (async): {url}") + verbose_logger.debug("Vertex AI OCR: Converting URL to base64 data URI (async): %s", url) # Fetch and convert to base64 data URI asynchronously # async_convert_url_to_base64 already returns a full data URI like "data:image/jpeg;base64,..." data_uri = await async_convert_url_to_base64(url=url) - verbose_logger.debug(f"Vertex AI OCR: Converted URL to data URI (length: {len(data_uri)})") + verbose_logger.debug("Vertex AI OCR: Converted URL to data URI (length: %s)", len(data_uri)) return data_uri @@ -252,7 +252,7 @@ class VertexAIOCRConfig(MistralOCRConfig): Returns: OCRRequestData with JSON data """ - verbose_logger.debug(f"Vertex AI OCR async_transform_ocr_request - model: {model}") + verbose_logger.debug("Vertex AI OCR async_transform_ocr_request - model: %s", model) if not isinstance(document, dict): raise ValueError(f"Expected document dict, got {type(document)}") diff --git a/litellm/llms/vertex_ai/rag_engine/ingestion.py b/litellm/llms/vertex_ai/rag_engine/ingestion.py index edafa2f8f7a..cb30dc0ce0a 100644 --- a/litellm/llms/vertex_ai/rag_engine/ingestion.py +++ b/litellm/llms/vertex_ai/rag_engine/ingestion.py @@ -133,7 +133,7 @@ class VertexAIRAGIngestion(BaseRAGIngestion): file_tuple = (filename, file_content, content_type) verbose_logger.debug( - f"Uploading file to GCS via litellm.files.acreate_file: {filename} (bucket: {self.gcs_bucket})" + "Uploading file to GCS via litellm.files.acreate_file: %s (bucket: %s)", filename, self.gcs_bucket ) # Upload to GCS using LiteLLM's file upload @@ -148,7 +148,7 @@ class VertexAIRAGIngestion(BaseRAGIngestion): # The response.id should be the GCS URI gcs_uri = response.id - verbose_logger.info(f"Uploaded file to GCS: {gcs_uri}") + verbose_logger.info("Uploaded file to GCS: %s", gcs_uri) return gcs_uri finally: @@ -185,7 +185,7 @@ class VertexAIRAGIngestion(BaseRAGIngestion): transformation_config = self._build_transformation_config() corpus_name = self._get_corpus_name() - verbose_logger.debug(f"Importing {gcs_uri} into corpus {self.corpus_id}") + verbose_logger.debug("Importing %s into corpus %s", gcs_uri, self.corpus_id) if self.wait_for_import: # Synchronous import - wait for completion @@ -195,7 +195,7 @@ class VertexAIRAGIngestion(BaseRAGIngestion): transformation_config=transformation_config, timeout=self.import_timeout, ) - verbose_logger.info(f"Import complete: {response.imported_rag_files_count} files imported") + verbose_logger.info("Import complete: %s files imported", response.imported_rag_files_count) else: # Async import - don't wait _ = rag.import_files_async( @@ -293,7 +293,7 @@ class VertexAIRAGIngestion(BaseRAGIngestion): try: await self._import_file_to_corpus_via_sdk(gcs_uri=gcs_uri) except Exception as e: - verbose_logger.error(f"Failed to import file into RAG corpus: {e}") + verbose_logger.error("Failed to import file into RAG corpus: %s", e) raise RuntimeError(f"Failed to import file into RAG corpus: {e}") from e return str(self.corpus_id), gcs_uri diff --git a/litellm/llms/vertex_ai/vertex_llm_base.py b/litellm/llms/vertex_ai/vertex_llm_base.py index 2def1acb708..c0a6bd01167 100644 --- a/litellm/llms/vertex_ai/vertex_llm_base.py +++ b/litellm/llms/vertex_ai/vertex_llm_base.py @@ -766,7 +766,7 @@ class VertexBase: The original error if reauthentication fails """ verbose_logger.debug( - f"Handling reauthentication for project_id: {project_id}. Clearing cache and retrying once." + "Handling reauthentication for project_id: %s. Clearing cache and retrying once.", project_id ) # Clear the cached credentials @@ -782,8 +782,10 @@ class VertexBase: ) except Exception as retry_error: verbose_logger.error( - f"Reauthentication retry failed for project_id: {project_id}. " - f"Original error: {error}. Retry error: {retry_error}" + "Reauthentication retry failed for project_id: %s. Original error: %s. Retry error: %s", + project_id, + error, + retry_error, ) # Re-raise the original error for better context raise error @@ -799,7 +801,7 @@ class VertexBase: Async reauthentication retry that stays within the per-key async lock. """ verbose_logger.debug( - f"Handling async reauthentication for project_id: {project_id}. Clearing cache and retrying once." + "Handling async reauthentication for project_id: %s. Clearing cache and retrying once.", project_id ) self._credentials_project_mapping.pop(credential_cache_key, None) @@ -836,8 +838,10 @@ class VertexBase: return _credentials.token, project_id except Exception as retry_error: verbose_logger.error( - f"Async reauthentication retry failed for project_id: {project_id}. " - f"Original error: {error}. Retry error: {retry_error}" + "Async reauthentication retry failed for project_id: %s. Original error: %s. Retry error: %s", + project_id, + error, + retry_error, ) raise error @@ -870,10 +874,10 @@ class VertexBase: credential_cache_key = (cache_credentials, project_id) _credentials: GoogleCredentialsObject | None = None - verbose_logger.debug(f"Checking cached credentials for project_id: {project_id}") + verbose_logger.debug("Checking cached credentials for project_id: %s", project_id) if credential_cache_key in self._credentials_project_mapping: - verbose_logger.debug(f"Cached credentials found for project_id: {project_id}.") + verbose_logger.debug("Cached credentials found for project_id: %s.", project_id) # Retrieve both credentials and cached project_id cached_entry = self._credentials_project_mapping[credential_cache_key] verbose_logger.debug("cached_entry: %s", cached_entry) @@ -890,14 +894,15 @@ class VertexBase: else: verbose_logger.debug( - f"Credential cache key not found for project_id: {project_id}, loading new credentials" + "Credential cache key not found for project_id: %s, loading new credentials", project_id ) try: _credentials, credential_project_id = self.load_auth(credentials=credentials, project_id=project_id) except Exception as e: verbose_logger.exception( - f"Failed to load vertex credentials. Check to see if credentials containing partial/invalid information. Error: {e}" + "Failed to load vertex credentials. Check to see if credentials containing partial/invalid information. Error: %s", + e, ) raise e diff --git a/litellm/llms/watsonx/chat/transformation.py b/litellm/llms/watsonx/chat/transformation.py index adc7035d2f7..0990edc5c42 100644 --- a/litellm/llms/watsonx/chat/transformation.py +++ b/litellm/llms/watsonx/chat/transformation.py @@ -190,7 +190,7 @@ class IBMWatsonXChatConfig(IBMWatsonXMixin, OpenAIGPTConfig): # Log the exception for debugging but don't raise it # The caller will fall back to default prompt factory try: - verbose_logger.debug(f"Failed to apply HuggingFace template for model {hf_model}: {e}") + verbose_logger.debug("Failed to apply HuggingFace template for model %s: %s", hf_model, e) except Exception: # If logging fails, silently continue - don't break the flow pass diff --git a/litellm/llms/xai/chat/transformation.py b/litellm/llms/xai/chat/transformation.py index 98d8fe5fadd..fa2f957260e 100644 --- a/litellm/llms/xai/chat/transformation.py +++ b/litellm/llms/xai/chat/transformation.py @@ -144,7 +144,7 @@ class XAIChatConfig(OpenAIGPTConfig): if litellm.supports_reasoning(model=model, custom_llm_provider=self.custom_llm_provider): base_openai_params.append("reasoning_effort") except Exception as e: - verbose_logger.debug(f"Error checking if model supports reasoning: {e}") + verbose_logger.debug("Error checking if model supports reasoning: %s", e) return base_openai_params @@ -277,7 +277,7 @@ class XAIChatConfig(OpenAIGPTConfig): raw_response_json = raw_response.json() self._enhance_usage_with_xai_web_search_fields(response, raw_response_json) except Exception as e: - verbose_logger.debug(f"Error extracting X.AI web search usage: {e}") + verbose_logger.debug("Error extracting X.AI web search usage: %s", e) self._fold_reasoning_tokens_into_completion(response) self._normalize_openai_compatible_usage_totals(getattr(response, "usage", None)) @@ -369,7 +369,7 @@ class XAIChatConfig(OpenAIGPTConfig): usage.prompt_tokens_details.web_search_requests = int(num_sources_used) setattr(usage, "num_sources_used", int(num_sources_used)) - verbose_logger.debug(f"X.AI web search sources used: {num_sources_used}") + verbose_logger.debug("X.AI web search sources used: %s", num_sources_used) @staticmethod def _normalize_openai_compatible_usage_totals( diff --git a/litellm/main.py b/litellm/main.py index 731a545a267..8b2c3c72f76 100644 --- a/litellm/main.py +++ b/litellm/main.py @@ -550,7 +550,7 @@ async def acompletion( # Log shared session usage if shared_session is not None: - verbose_logger.debug(f"🔄 SHARED SESSION: acompletion called with shared_session (ID: {id(shared_session)})") + verbose_logger.debug("🔄 SHARED SESSION: acompletion called with shared_session (ID: %s)", id(shared_session)) else: verbose_logger.debug("🔄 NO SHARED SESSION: acompletion called without shared_session") @@ -1002,7 +1002,7 @@ def responses_api_bridge_check( model = model.replace("responses/", "") except Exception as e: - verbose_logger.debug(f"Error getting model info: {e}") + verbose_logger.debug("Error getting model info: %s", e) if model.startswith("responses/"): # handle azure models - `azure/responses/` model = model.replace("responses/", "") @@ -2817,7 +2817,7 @@ def _complete_cohere_chat(ctx: _CompletionDispatchContext) -> _CompletionDispatc ) cohere_route = CohereModelInfo.get_cohere_route(model) - verbose_logger.debug(f"Cohere route: {cohere_route}") + verbose_logger.debug("Cohere route: %s", cohere_route) # Set API base based on route if cohere_route == "v2": api_base = api_base or litellm.api_base or get_secret_str("COHERE_API_BASE") or "https://api.cohere.com/v2/chat" @@ -2834,8 +2834,8 @@ def _complete_cohere_chat(ctx: _CompletionDispatchContext) -> _CompletionDispatc if extra_headers is not None: headers.update(extra_headers) - verbose_logger.debug(f"Model: {model}, API Base: {api_base}") - verbose_logger.debug(f"Provider Config: {provider_config}") + verbose_logger.debug("Model: %s, API Base: %s", model, api_base) + verbose_logger.debug("Provider Config: %s", provider_config) return base_llm_http_handler.completion( model=model, stream=stream, @@ -4998,7 +4998,7 @@ def completion( # type: ignore proxy_headers = litellm.proxy_auth.get_auth_headers() headers.update(proxy_headers) except Exception as e: - verbose_logger.warning(f"Failed to get proxy auth headers: {e}") + verbose_logger.warning("Failed to get proxy auth headers: %s", e) num_retries = kwargs.get( "num_retries", None ) ## alt. param for 'max_retries'. Use this to pass retries w/ instructor. @@ -5965,7 +5965,7 @@ def embedding( proxy_headers = litellm.proxy_auth.get_auth_headers() headers.update(proxy_headers) except Exception as e: - verbose_logger.warning(f"Failed to get proxy auth headers: {e}") + verbose_logger.warning("Failed to get proxy auth headers: %s", e) ### CUSTOM MODEL COST ### input_cost_per_token = kwargs.get("input_cost_per_token", None) output_cost_per_token = kwargs.get("output_cost_per_token", None) @@ -8669,7 +8669,7 @@ def stream_chunk_builder( processor.apply_provider_assembled_streaming_metadata(response, chunks, logging_obj) return response except Exception as e: - verbose_logger.exception(f"litellm.main.py::stream_chunk_builder() - Exception occurred - {e}") + verbose_logger.exception("litellm.main.py::stream_chunk_builder() - Exception occurred - %s", e) raise litellm.APIError( status_code=500, message="Error building chunks for logging/streaming usage calculation", @@ -8759,7 +8759,7 @@ async def acount_tokens( if result is not None and not result.error: return result except Exception as e: - verbose_logger.debug(f"Provider token counting failed for model={model}, falling back to local: {e}") + verbose_logger.debug("Provider token counting failed for model=%s, falling back to local: %s", model, e) # Fallback to local tiktoken-based token counting fallback_messages = messages or [] diff --git a/litellm/ocr/main.py b/litellm/ocr/main.py index f53f32eecfa..171f3286a7d 100644 --- a/litellm/ocr/main.py +++ b/litellm/ocr/main.py @@ -119,7 +119,7 @@ def _prepare_ocr_request( if ocr_provider_config is None: raise ValueError(f"OCR is not supported for provider: {custom_llm_provider}") - verbose_logger.debug(f"OCR call - model: {model}, provider: {custom_llm_provider}") + verbose_logger.debug("OCR call - model: %s, provider: %s", model, custom_llm_provider) litellm_params = GenericLiteLLMParams.model_validate(kwargs) @@ -135,7 +135,7 @@ def _prepare_ocr_request( model=model, ) - verbose_logger.debug(f"OCR optional_params after mapping: {optional_params}") + verbose_logger.debug("OCR optional_params after mapping: %s", optional_params) effective_timeout = timeout or request_timeout @@ -553,14 +553,18 @@ def convert_file_document_to_url_document(document: dict[str, Any]) -> dict[str, if mime_type.startswith("image/"): verbose_logger.debug( - f"OCR file input: Converted file to image_url data URI " - f"(mime={mime_type}, size={len(file_bytes)} bytes, name={file_name})" + "OCR file input: Converted file to image_url data URI (mime=%s, size=%s bytes, name=%s)", + mime_type, + len(file_bytes), + file_name, ) return {"type": "image_url", "image_url": data_uri} verbose_logger.debug( - f"OCR file input: Converted file to document_url data URI " - f"(mime={mime_type}, size={len(file_bytes)} bytes, name={file_name})" + "OCR file input: Converted file to document_url data URI (mime=%s, size=%s bytes, name=%s)", + mime_type, + len(file_bytes), + file_name, ) return {"type": "document_url", "document_url": data_uri} diff --git a/litellm/proxy/_experimental/mcp_server/auth/user_api_key_auth_mcp.py b/litellm/proxy/_experimental/mcp_server/auth/user_api_key_auth_mcp.py index a256653f0f9..07a4eb164c3 100644 --- a/litellm/proxy/_experimental/mcp_server/auth/user_api_key_auth_mcp.py +++ b/litellm/proxy/_experimental/mcp_server/auth/user_api_key_auth_mcp.py @@ -384,14 +384,14 @@ class MCPRequestHandler: # Parse MCP servers from header mcp_servers_header = headers.get(MCPRequestHandler.LITELLM_MCP_SERVERS_HEADER_NAME) - verbose_logger.debug(f"Raw MCP servers header: {mcp_servers_header}") + verbose_logger.debug("Raw MCP servers header: %s", mcp_servers_header) mcp_servers = None if mcp_servers_header is not None: try: mcp_servers = [s.strip() for s in mcp_servers_header.split(",") if s.strip()] - verbose_logger.debug(f"Parsed MCP servers: {mcp_servers}") + verbose_logger.debug("Parsed MCP servers: %s", mcp_servers) except Exception as e: - verbose_logger.debug(f"Error parsing mcp_servers header: {e}") + verbose_logger.debug("Error parsing mcp_servers header: %s", e) mcp_servers = None if mcp_servers_header == "" or (mcp_servers is not None and len(mcp_servers) == 0): mcp_servers = [] @@ -1008,7 +1008,7 @@ class MCPRequestHandler: limits[source.team_id] = applicable return limits or None except Exception as e: # noqa: BLE001 # throttling metadata must never fail an allowed request - verbose_logger.warning(f"Failed to resolve per-team MCP rpm limits for admitted subject: {e}") + verbose_logger.warning("Failed to resolve per-team MCP rpm limits for admitted subject: %s", e) return None @staticmethod @@ -1091,7 +1091,7 @@ class MCPRequestHandler: user_id_upsert=False, ) except Exception as e: # noqa: BLE001 # mirror the builder's fail-open user lookup; DB errors are of any type - verbose_logger.debug(f"bridge admission: user lookup failed, skipping SCIM gate: {e}") + verbose_logger.debug("bridge admission: user lookup failed, skipping SCIM gate: %s", e) user_object = None if user_object is None or not isinstance(user_object.metadata, dict): return @@ -1194,8 +1194,8 @@ class MCPRequestHandler: auth_header = headers.get(mcp_client_side_auth_header_name) if auth_header: verbose_logger.warning( - f"The '{mcp_client_side_auth_header_name}' header is deprecated. " - f"Please use server-specific auth headers in the format 'x-mcp-{{server_alias}}-{{header_name}}' instead." + "The '%s' header is deprecated. Please use server-specific auth headers in the format 'x-mcp-{server_alias}-{header_name}' instead.", + mcp_client_side_auth_header_name, ) return auth_header @@ -1245,7 +1245,10 @@ class MCPRequestHandler: server_auth_headers[server_alias][auth_header_name] = header_value verbose_logger.debug( - f"Found server auth header: {server_alias} -> {auth_header_name}: {header_value[:10]}..." + "Found server auth header: %s -> %s: %s...", + server_alias, + auth_header_name, + header_value[:10], ) return server_auth_headers @@ -1331,7 +1334,7 @@ class MCPRequestHandler: headers_dict = {name.decode("latin-1"): value.decode("latin-1") for name, value in raw_headers} return Headers(headers_dict) except (UnicodeDecodeError, AttributeError, TypeError) as e: - verbose_logger.exception(f"Error getting headers from scope: {e}") + verbose_logger.exception("Error getting headers from scope: %s", e) # Return empty Headers object with empty dict return Headers({}) @@ -1455,7 +1458,9 @@ class MCPRequestHandler: if len(allowed_mcp_servers_for_end_user) > 0: has_lower_level_mcp_restrictions = True verbose_logger.debug( - f"End user {user_api_key_auth.end_user_id} has explicit MCP permissions: {allowed_mcp_servers_for_end_user}" + "End user %s has explicit MCP permissions: %s", + user_api_key_auth.end_user_id, + allowed_mcp_servers_for_end_user, ) # Always apply intersection: key/team AND end_user @@ -1466,12 +1471,13 @@ class MCPRequestHandler: filtered_servers.append(_mcp_server) allowed_mcp_servers = filtered_servers verbose_logger.debug( - f"Applied end_user intersection filter. Final allowed servers: {allowed_mcp_servers}" + "Applied end_user intersection filter. Final allowed servers: %s", allowed_mcp_servers ) # If flag is enabled but end_user has no permissions, block all access elif general_settings.get("require_end_user_mcp_access_defined", False): verbose_logger.debug( - f"require_end_user_mcp_access_defined=True and end_user {user_api_key_auth.end_user_id} has no MCP permissions - blocking MCP access" + "require_end_user_mcp_access_defined=True and end_user %s has no MCP permissions - blocking MCP access", + user_api_key_auth.end_user_id, ) return [] @@ -1487,7 +1493,7 @@ class MCPRequestHandler: # Intersect: agent can only use servers allowed by BOTH key/team AND agent config allowed_mcp_servers = [s for s in allowed_mcp_servers if s in allowed_mcp_servers_for_agent] verbose_logger.debug( - f"Applied agent intersection filter. Final allowed servers: {allowed_mcp_servers}" + "Applied agent intersection filter. Final allowed servers: %s", allowed_mcp_servers ) ######################################################### @@ -1514,9 +1520,9 @@ class MCPRequestHandler: if isinstance(e, UnloadableEntitlementError): # A ceiling we KNOW exists and cannot read. Denying is the only answer that does not # widen this caller past what an operator configured, for both caller shapes. - verbose_logger.warning(f"Denying MCP access, entitlement unreadable: {e}") + verbose_logger.warning("Denying MCP access, entitlement unreadable: %s", e) else: - verbose_logger.warning(f"Failed to get allowed MCP servers: {e}") + verbose_logger.warning("Failed to get allowed MCP servers: %s", e) return [] @staticmethod @@ -1543,8 +1549,9 @@ class MCPRequestHandler: allowed_mcp_servers_for_org = await MCPRequestHandler._get_allowed_mcp_servers_for_org(user_api_key_auth) if allowed_mcp_servers_for_org is None: verbose_logger.warning( - f"MCP org ceiling unresolved for org_id={user_api_key_auth.org_id!r}; " - f"{'denying (keyless admitted subject)' if keyless_source else 'leaving uncapped (key auth)'}" + "MCP org ceiling unresolved for org_id=%r; %s", + user_api_key_auth.org_id, + "denying (keyless admitted subject)" if keyless_source else "leaving uncapped (key auth)", ) return [] if keyless_source else allowed_mcp_servers if len(allowed_mcp_servers_for_org) == 0: @@ -1556,7 +1563,7 @@ class MCPRequestHandler: else: # No lower-level restrictions → org list becomes the ceiling. capped = allowed_mcp_servers_for_org - verbose_logger.debug(f"Applied org ceiling filter. Final allowed servers: {capped}") + verbose_logger.debug("Applied org ceiling filter. Final allowed servers: %s", capped) return capped @staticmethod @@ -1649,7 +1656,7 @@ class MCPRequestHandler: # Fault isolation is per SOURCE: an unresolvable team contributes nothing (fail closed for # it alone, access only narrows) while every other source stands. Raising would collapse the # whole union to deny-all over one momentarily-unreadable row. - verbose_logger.warning(f"MCP admitted-subject source team {team_id!r} unresolvable, skipping: {e}") + verbose_logger.warning("MCP admitted-subject source team %r unresolvable, skipping: %s", team_id, e) return None if team_obj is None: return None @@ -1682,10 +1689,10 @@ class MCPRequestHandler: proxy_logging_obj=proxy_logging_obj, ) except BudgetExceededError as e: - verbose_logger.info(f"MCP admitted-subject source team {team_id!r} over budget, not a grantor: {e}") + verbose_logger.info("MCP admitted-subject source team %r over budget, not a grantor: %s", team_id, e) return None except Exception as e: # noqa: BLE001 # per-source isolation: a budget-check fault narrows, never raises - verbose_logger.warning(f"MCP budget check failed for source team {team_id!r}, skipping source: {e}") + verbose_logger.warning("MCP budget check failed for source team %r, skipping source: %s", team_id, e) return None return team_obj @@ -1738,7 +1745,7 @@ class MCPRequestHandler: billed.org_id = source.org_id return billed except Exception as e: # noqa: BLE001 # attribution must never fail an authorized call - verbose_logger.warning(f"MCP billing attribution failed for {tool_name!r}, billing the user: {e}") + verbose_logger.warning("MCP billing attribution failed for %r, billing the user: %s", tool_name, e) return auth @staticmethod @@ -1828,7 +1835,7 @@ class MCPRequestHandler: ) verbose_logger.debug( - f"MCP team permission lookup: team_id={user_api_key_auth.team_id if user_api_key_auth else None}" + "MCP team permission lookup: team_id=%s", user_api_key_auth.team_id if user_api_key_auth else None ) if not user_api_key_auth or not user_api_key_auth.team_id or not prisma_client: return None @@ -1946,9 +1953,9 @@ class MCPRequestHandler: # than the None (allow-all) key auth gets for an indeterminate fault. unreadable_entitlement = isinstance(e, UnloadableEntitlementError) if unreadable_entitlement: - verbose_logger.warning(f"Denying MCP tools, entitlement unreadable: {e}") + verbose_logger.warning("Denying MCP tools, entitlement unreadable: %s", e) else: - verbose_logger.warning(f"Failed to get allowed tools for server: {e}") + verbose_logger.warning("Failed to get allowed tools for server: %s", e) # Fail CLOSED for a keyless admitted subject: ANY error must deny the server's tools ([]), # not collapse to allow-all (None); key/JWT auth keeps its prior allow-all-on-error. Both # keyless_source AND the marker are needed: each source resolves through an UNMARKED auth, so @@ -1998,8 +2005,9 @@ class MCPRequestHandler: if keyless_source or isinstance(e, UnloadableEntitlementError): raise verbose_logger.warning( - f"MCP org tool ceiling unresolvable for org_id={user_api_key_auth.org_id!r}; " - f"skipping org intersect, key/team/agent restrictions stand: {e}" + "MCP org tool ceiling unresolvable for org_id=%r; skipping org intersect, key/team/agent restrictions stand: %s", + user_api_key_auth.org_id, + e, ) return allowed_tools org_tools = ( @@ -2102,7 +2110,7 @@ class MCPRequestHandler: # Permission entries may be server_ids OR names/aliases — expand to ids. return global_mcp_server_manager.expand_permission_list(raw_server_ids) except Exception as e: - verbose_logger.warning(f"Failed to get key access group MCP server grants: {e}") + verbose_logger.warning("Failed to get key access group MCP server grants: %s", e) return [] @staticmethod @@ -2180,7 +2188,7 @@ class MCPRequestHandler: all_servers = direct_mcp_servers + access_group_servers + tool_perm_servers + toolset_servers return list(set(all_servers)) except Exception as e: - verbose_logger.warning(f"Failed to get allowed MCP servers for key: {e}") + verbose_logger.warning("Failed to get allowed MCP servers for key: %s", e) return [] @staticmethod @@ -2238,7 +2246,7 @@ class MCPRequestHandler: proxy_logging_obj=proxy_logging_obj, ) except Exception as e: # noqa: BLE001 # a team-resolution blip narrows access, never raises - verbose_logger.warning(f"Failed to resolve user teams for MCP grant: {e}") + verbose_logger.warning("Failed to resolve user teams for MCP grant: %s", e) return [] if user_object is None or not user_object.teams: return [] @@ -2323,7 +2331,7 @@ class MCPRequestHandler: servers = await MCPRequestHandler._team_granted_servers(team_obj, team_access_group_servers) return list(servers) except Exception as e: - verbose_logger.warning(f"Failed to get allowed MCP servers for team: {e}") + verbose_logger.warning("Failed to get allowed MCP servers for team: %s", e) return [] @staticmethod @@ -2403,7 +2411,7 @@ class MCPRequestHandler: # CONFIRMED absent: places no ceiling. Every OTHER exception propagates as an unresolvable # ceiling (denies for a keyless source, fail-open for a key); catching bare Exception here # would treat a DB outage as "no org" and silently drop a real ceiling for its duration. - verbose_logger.debug(f"MCP org ceiling: org {user_api_key_auth.org_id!r} does not exist: {e}") + verbose_logger.debug("MCP org ceiling: org %r does not exist: %s", user_api_key_auth.org_id, e) return None if org_obj is None or not org_obj.object_permission_id: @@ -2462,7 +2470,7 @@ class MCPRequestHandler: # A NAMED-but-unreadable ceiling is a stronger fact than "unresolved" and denies everywhere. if isinstance(e, UnloadableEntitlementError): raise - verbose_logger.warning(f"Failed to get allowed MCP servers for org: {e}") + verbose_logger.warning("Failed to get allowed MCP servers for org: %s", e) return None @staticmethod @@ -2490,7 +2498,7 @@ class MCPRequestHandler: route="/mcp", ) except Exception as e: # noqa: BLE001 # entitlement unknown, not known-absent: no ceiling, as before this level - verbose_logger.warning(f"Failed to resolve end_user for MCP permissions: {e}") + verbose_logger.warning("Failed to resolve end_user for MCP permissions: %s", e) return None if end_user_obj is None: @@ -2554,7 +2562,7 @@ class MCPRequestHandler: all_servers = direct_mcp_servers + access_group_servers + tool_perm_servers return list(set(all_servers)) except Exception as e: - verbose_logger.warning(f"Failed to get allowed MCP servers for end_user: {e}") + verbose_logger.warning("Failed to get allowed MCP servers for end_user: %s", e) return [] @staticmethod @@ -2637,7 +2645,7 @@ class MCPRequestHandler: ) return object_permission_id except Exception as e: # noqa: BLE001 # unknown whether entitled at all: no ceiling, as before - verbose_logger.warning(f"MCP user entitlement: link for {user_id!r} unresolved, no ceiling: {e}") + verbose_logger.warning("MCP user entitlement: link for %r unresolved, no ceiling: %s", user_id, e) return None @staticmethod @@ -2669,7 +2677,7 @@ class MCPRequestHandler: ) return list(set(direct_mcp_servers + access_group_servers + tool_perm_servers)) except Exception as e: # noqa: BLE001 # any resolution fault is an unresolved ceiling, never "no ceiling" - verbose_logger.warning(f"Failed to get allowed MCP servers for user: {e}") + verbose_logger.warning("Failed to get allowed MCP servers for user: %s", e) return None @staticmethod @@ -2700,7 +2708,7 @@ class MCPRequestHandler: if not entitled: return tuple(allowed_mcp_servers), False capped = tuple(server for server in allowed_mcp_servers if server in set(entitled)) - verbose_logger.debug(f"Applied user ceiling filter. Final allowed servers: {capped}") + verbose_logger.debug("Applied user ceiling filter. Final allowed servers: %s", capped) return capped, True @staticmethod @@ -2739,7 +2747,7 @@ class MCPRequestHandler: try: object_permissions = await MCPRequestHandler._get_user_object_permission(user_api_key_auth) except Exception as e: # noqa: BLE001 # an unresolved human entitlement must deny, not widen - verbose_logger.warning(f"MCP user tool ceiling unresolvable, denying tools on {server_id!r}: {e}") + verbose_logger.warning("MCP user tool ceiling unresolvable, denying tools on %r: %s", server_id, e) return [] if object_permissions is None or not object_permissions.mcp_tool_permissions: @@ -2785,7 +2793,7 @@ class MCPRequestHandler: ) return object_permission_id except Exception as e: # noqa: BLE001 # entitlement unknown, not known-absent: no ceiling, as before this level - verbose_logger.warning(f"Failed to resolve object_permission_id for agent {agent_id!r}: {e}") + verbose_logger.warning("Failed to resolve object_permission_id for agent %r: %s", agent_id, e) return None @staticmethod @@ -2869,7 +2877,7 @@ class MCPRequestHandler: all_servers = expanded_direct_servers + access_group_servers return list(set(all_servers)) except Exception as e: - verbose_logger.warning(f"Failed to get allowed MCP servers for agent: {e}") + verbose_logger.warning("Failed to get allowed MCP servers for agent: %s", e) return [] @staticmethod @@ -2911,7 +2919,7 @@ class MCPRequestHandler: tools = global_mcp_server_manager.expand_tool_permissions(mcp_tool_permissions).get(server_id) return list(tools) if tools else None except Exception as e: - verbose_logger.warning(f"Failed to get agent tool permissions for server: {e}") + verbose_logger.warning("Failed to get agent tool permissions for server: %s", e) return None @staticmethod @@ -2940,7 +2948,7 @@ class MCPRequestHandler: for server in mcp_servers: server_ids.add(server.server_id) except Exception as e: - verbose_logger.debug(f"Error getting MCP servers from access groups: {e}") + verbose_logger.debug("Error getting MCP servers from access groups: %s", e) return server_ids @staticmethod @@ -2969,7 +2977,7 @@ class MCPRequestHandler: return list(server_ids) except Exception as e: - verbose_logger.warning(f"Failed to get MCP servers from access groups: {e}") + verbose_logger.warning("Failed to get MCP servers from access groups: %s", e) return [] @staticmethod @@ -3029,7 +3037,7 @@ class MCPRequestHandler: return key_object_permission.mcp_access_groups or [] except Exception as e: - verbose_logger.warning(f"Failed to get MCP access groups for key: {e}") + verbose_logger.warning("Failed to get MCP access groups for key: %s", e) return [] @staticmethod @@ -3077,7 +3085,7 @@ class MCPRequestHandler: return object_permissions.mcp_access_groups or [] except Exception as e: - verbose_logger.warning(f"Failed to get MCP access groups for team: {e}") + verbose_logger.warning("Failed to get MCP access groups for team: %s", e) return [] @staticmethod diff --git a/litellm/proxy/_experimental/mcp_server/db.py b/litellm/proxy/_experimental/mcp_server/db.py index 672396afd05..c5469785778 100644 --- a/litellm/proxy/_experimental/mcp_server/db.py +++ b/litellm/proxy/_experimental/mcp_server/db.py @@ -570,7 +570,7 @@ async def get_all_mcp_servers( decrypt_global_env_var_values(table.env_vars) return tables except Exception as e: - verbose_proxy_logger.debug(f"litellm.proxy._experimental.mcp_server.db.py::get_all_mcp_servers - {e}") + verbose_proxy_logger.debug("litellm.proxy._experimental.mcp_server.db.py::get_all_mcp_servers - %s", e) return [] diff --git a/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py b/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py index e16fb0d0e00..40844ec1937 100644 --- a/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py +++ b/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py @@ -2159,8 +2159,9 @@ async def _build_oauth_protected_resource_response( upstream_metadata = await fetch_upstream_oauth_protected_resource(mcp_server) except Exception as exc: verbose_logger.warning( - "Failed to fetch upstream oauth-protected-resource metadata " - f"for pass-through MCP server {mcp_server.name!r}: {exc}" + "Failed to fetch upstream oauth-protected-resource metadata for pass-through MCP server %r: %s", + mcp_server.name, + exc, ) raise HTTPException( status_code=502, @@ -2179,7 +2180,7 @@ async def _build_oauth_protected_resource_response( # so we must not fall through to the default gateway metadata — # that would point clients at the wrong IdP. verbose_logger.warning( - f"Upstream oauth-protected-resource metadata unavailable for pass-through MCP server {mcp_server.name!r}" + "Upstream oauth-protected-resource metadata unavailable for pass-through MCP server %r", mcp_server.name ) raise HTTPException( status_code=502, diff --git a/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py b/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py index 0a6a0374d13..66a55f30b74 100644 --- a/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py +++ b/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py @@ -1566,7 +1566,7 @@ class MCPServerManager: if target_server_name == server_name and alias_name not in used_aliases: alias = alias_name used_aliases.add(alias_name) - verbose_logger.debug(f"Mapped alias '{alias_name}' to server '{server_name}'") + verbose_logger.debug("Mapped alias '%s' to server '%s'", alias_name, server_name) break # Create a temporary server object to use with get_server_prefix utility @@ -1785,7 +1785,7 @@ class MCPServerManager: # Check if this is an OpenAPI-based server spec_path = server_config.get("spec_path", None) if spec_path: - verbose_logger.info(f"Loading OpenAPI spec from {spec_path} for server {server_name}") + verbose_logger.info("Loading OpenAPI spec from %s for server %s", spec_path, server_name) await self._register_openapi_tools( spec_path=spec_path, server=new_server, @@ -1793,7 +1793,7 @@ class MCPServerManager: ) verbose_logger.debug( - f"Loaded MCP Servers: {json.dumps(_redacted_registry_dump(self.config_mcp_servers), indent=4)}" + "Loaded MCP Servers: %s", json.dumps(_redacted_registry_dump(self.config_mcp_servers), indent=4) ) await self._hydrate_config_servers_dcr_clients() @@ -1856,7 +1856,7 @@ class MCPServerManager: # Use base_url from config if provided, otherwise extract from spec if not base_url: base_url = get_openapi_base_url(spec, spec_path) - verbose_logger.info(f"Registering OpenAPI tools for server {server.name} with base URL: {base_url}") + verbose_logger.info("Registering OpenAPI tools for server %s with base URL: %s", server.name, base_url) # Get server prefix for tool naming server_prefix = get_server_prefix(server) @@ -1892,7 +1892,7 @@ class MCPServerManager: ) verbose_logger.debug( - f"Using headers for OpenAPI tools (excluding sensitive values): {list(headers.keys())}" + "Using headers for OpenAPI tools (excluding sensitive values): %s", list(headers.keys()) ) # Extract and register tools from OpenAPI paths @@ -1900,7 +1900,7 @@ class MCPServerManager: components = spec.get("components", {}) registered_count = 0 - verbose_logger.debug(f"Processing {len(paths)} paths from OpenAPI spec") + verbose_logger.debug("Processing %s paths from OpenAPI spec", len(paths)) for path, path_item in paths.items(): for method in ["get", "post", "put", "delete", "patch"]: @@ -1946,12 +1946,12 @@ class MCPServerManager: self.tool_name_to_mcp_server_name_mapping[prefixed_tool_name] = server_prefix registered_count += 1 - verbose_logger.debug(f"Registered OpenAPI tool: {prefixed_tool_name} for server {server.name}") + verbose_logger.debug("Registered OpenAPI tool: %s for server %s", prefixed_tool_name, server.name) - verbose_logger.info(f"Successfully registered {registered_count} OpenAPI tools for server {server.name}") + verbose_logger.info("Successfully registered %s OpenAPI tools for server %s", registered_count, server.name) except Exception as e: - verbose_logger.error(f"Failed to register OpenAPI tools for server {server.name}: {e}") + verbose_logger.error("Failed to register OpenAPI tools for server %s: %s", server.name, e) raise e def _cleanup_server_tool_routing_artifacts(self, server: MCPServer) -> None: @@ -2000,7 +2000,7 @@ class MCPServerManager: verbose_logger.debug("Removed MCP Server: %s", mcp_server.server_id or mcp_server.server_name) self._cleanup_server_tool_routing_artifacts(evicted) else: - verbose_logger.warning(f"Server ID {mcp_server.server_id} not found in registry") + verbose_logger.warning("Server ID %s not found in registry", mcp_server.server_id) def _resolve_env_vars_list( self, @@ -2295,7 +2295,7 @@ class MCPServerManager: async def _maybe_register_openapi_tools(self, server: MCPServer, *, initialize_mapping: bool = True): """Register OpenAPI tools if the server has a spec_path configured.""" if server.spec_path: - verbose_logger.info(f"Loading OpenAPI spec from {server.spec_path} for server {server.name}") + verbose_logger.info("Loading OpenAPI spec from %s for server %s", server.spec_path, server.name) await self._register_openapi_tools( spec_path=server.spec_path, server=server, @@ -2323,10 +2323,10 @@ class MCPServerManager: self._assign_unique_short_prefix(new_server) self.registry[mcp_server.server_id] = new_server await self._maybe_register_openapi_tools(new_server) - verbose_logger.debug(f"Added MCP Server: {new_server.name}") + verbose_logger.debug("Added MCP Server: %s", new_server.name) except Exception as e: - verbose_logger.debug(f"Failed to add MCP server: {e}") + verbose_logger.debug("Failed to add MCP server: %s", e) raise e async def update_server(self, mcp_server: LiteLLM_MCPServerTable): @@ -2357,10 +2357,10 @@ class MCPServerManager: self._assign_unique_short_prefix(new_server) self.registry[mcp_server.server_id] = new_server await self._maybe_register_openapi_tools(new_server) - verbose_logger.debug(f"Updated MCP Server: {new_server.name}") + verbose_logger.debug("Updated MCP Server: %s", new_server.name) except Exception as e: - verbose_logger.debug(f"Failed to udpate MCP server: {e}") + verbose_logger.debug("Failed to udpate MCP server: %s", e) raise e def get_all_mcp_server_ids(self) -> set[str]: @@ -2386,7 +2386,7 @@ class MCPServerManager: await user_api_key_cache.async_delete_cache(key=self.get_byom_submitted_servers_cache_key(user_id)) except Exception as e: # noqa: BLE001 - verbose_logger.warning(f"Failed to invalidate BYOM submitted MCP server cache: {e}") + verbose_logger.warning("Failed to invalidate BYOM submitted MCP server cache: %s", e) async def _get_active_submitted_mcp_server_ids_for_user( self, user_api_key_auth: UserAPIKeyAuth | None @@ -2401,7 +2401,7 @@ class MCPServerManager: ) from litellm.proxy.proxy_server import prisma_client, user_api_key_cache except Exception as e: # noqa: BLE001 - verbose_logger.warning(f"Failed to load BYOM submitted MCP server cache dependencies: {e}") + verbose_logger.warning("Failed to load BYOM submitted MCP server cache dependencies: %s", e) return [] byom_cache_key = self.get_byom_submitted_servers_cache_key(submitter_user_id) @@ -2411,7 +2411,7 @@ class MCPServerManager: if cached_submitted_server_ids is not None: submitted_server_ids = cast(list[str], cached_submitted_server_ids) except Exception as e: # noqa: BLE001 - verbose_logger.warning(f"Failed to read BYOM submitted MCP server cache: {e}") + verbose_logger.warning("Failed to read BYOM submitted MCP server cache: %s", e) if submitted_server_ids is None: if prisma_client is None: @@ -2422,7 +2422,7 @@ class MCPServerManager: prisma_client, submitter_user_id ) except Exception as e: # noqa: BLE001 - verbose_logger.warning(f"Failed to read BYOM submitted MCP servers from database: {e}") + verbose_logger.warning("Failed to read BYOM submitted MCP servers from database: %s", e) submitted_server_ids = [] try: await user_api_key_cache.async_set_cache( @@ -2431,7 +2431,7 @@ class MCPServerManager: ttl=60, ) except Exception as e: # noqa: BLE001 - verbose_logger.warning(f"Failed to write BYOM submitted MCP server cache: {e}") + verbose_logger.warning("Failed to write BYOM submitted MCP server cache: %s", e) return [server_id for server_id in submitted_server_ids if self.get_mcp_server_by_id(server_id) is not None] @@ -2522,7 +2522,7 @@ class MCPServerManager: key_object_permission.mcp_servers is not None ) if has_explicit_object_permission: - verbose_logger.debug(f"Object permission mcp_servers explicitly set: {key_object_permission.mcp_servers}") + verbose_logger.debug("Object permission mcp_servers explicitly set: %s", key_object_permission.mcp_servers) # BYOM creator visibility never widens a key that was explicitly scoped: # only keys without their own mcp_servers list get submitted servers unioned in. @@ -2551,7 +2551,7 @@ class MCPServerManager: # Get allowed servers from object permissions (respects object_permission even for admins) allowed_mcp_servers = await MCPRequestHandler.get_allowed_mcp_servers(user_api_key_auth) - verbose_logger.debug(f"Allowed MCP Servers for user api key auth: {allowed_mcp_servers}") + verbose_logger.debug("Allowed MCP Servers for user api key auth: %s", allowed_mcp_servers) combined_servers = set(allowed_mcp_servers) combined_servers.update( await self.operator_open_server_ids( @@ -2647,7 +2647,7 @@ class MCPServerManager: ) return tool_permissions except Exception as e: - verbose_logger.warning(f"Failed to resolve toolset permissions: {e}") + verbose_logger.warning("Failed to resolve toolset permissions: %s", e) return {} def invalidate_toolset_cache(self, toolset_id: str | None = None) -> None: @@ -2682,7 +2682,7 @@ class MCPServerManager: for k in keys_to_remove: cache_dict.pop(k, None) except Exception as e: - verbose_logger.warning(f"invalidate_toolset_cache: failed to evict in-memory entries: {e}") + verbose_logger.warning("invalidate_toolset_cache: failed to evict in-memory entries: %s", e) async def get_toolset_by_name_cached( self, @@ -2760,11 +2760,11 @@ class MCPServerManager: try: server = self.get_mcp_server_by_id(server_id) if server is None: - verbose_logger.warning(f"MCP Server {server_id} not found") + verbose_logger.warning("MCP Server %s not found", server_id) return [] return await self._get_tools_from_server(server) except Exception as e: - verbose_logger.warning(f"Failed to get tools from server {server_id}: {e}") + verbose_logger.warning("Failed to get tools from server %s: %s", server_id, e) return [] async def list_tools( @@ -2793,7 +2793,7 @@ class MCPServerManager: """Fetch tools from a single server with error handling.""" server = self.get_mcp_server_by_id(server_id) if server is None: - verbose_logger.warning(f"MCP Server {server_id} not found") + verbose_logger.warning("MCP Server %s not found", server_id) return [] # Get server-specific auth header if available @@ -2822,7 +2822,7 @@ class MCPServerManager: return tools except Exception as e: verbose_logger.warning( - f"Failed to list tools from server {server.name}: {e}. Continuing with other servers." + "Failed to list tools from server %s: %s. Continuing with other servers.", server.name, e ) return [] @@ -2833,7 +2833,7 @@ class MCPServerManager: # Flatten results into single list list_tools_result: list[MCPTool] = [tool for tools in results for tool in tools] - verbose_logger.info(f"Successfully fetched {len(list_tools_result)} tools total from all servers") + verbose_logger.info("Successfully fetched %s tools total from all servers", len(list_tools_result)) return list_tools_result ######################################################### @@ -3345,8 +3345,8 @@ class MCPServerManager: global_mcp_tool_registry, ) - verbose_logger.debug(f"Connecting to url: {server.url}") - verbose_logger.info(f"_get_tools_from_server for {server.name}...") + verbose_logger.debug("Connecting to url: %s", server.url) + verbose_logger.info("_get_tools_from_server for %s...", server.name) client = None @@ -3476,12 +3476,12 @@ class MCPServerManager: www_authenticate=None if server.is_dcr_bridge else challenge_header, server_name=server.name, ) from e - verbose_logger.warning(f"Failed to get tools from server {server.name}: {e}") + verbose_logger.warning("Failed to get tools from server %s: %s", server.name, e) raise MCPServerListError(ServerListFault(tag="internal", status_code=e.status_code), server.name) from e except MCPServerListError: raise except Exception as e: - verbose_logger.warning(f"Failed to get tools from server {server.name}: {e}") + verbose_logger.warning("Failed to get tools from server %s: %s", server.name, e) raise_classified_list_failure(e, server.name, suppress_challenge=server.is_dcr_bridge) async def get_prompts_from_server( @@ -3503,8 +3503,8 @@ class MCPServerManager: List[Prompt]: List of prompts available on the server with prefixed names """ - verbose_logger.debug(f"Connecting to url: {server.url}") - verbose_logger.info(f"get_prompts_from_server for {server.name}...") + verbose_logger.debug("Connecting to url: %s", server.url) + verbose_logger.info("get_prompts_from_server for %s...", server.name) client = None @@ -3532,7 +3532,7 @@ class MCPServerManager: return prefixed_or_original_prompts except Exception as e: - verbose_logger.warning(f"Failed to get prompts from server {server.name}: {e}") + verbose_logger.warning("Failed to get prompts from server %s: %s", server.name, e) return [] async def get_resources_from_server( @@ -3545,8 +3545,8 @@ class MCPServerManager: ) -> list[Resource]: """Fetch available resources from a single MCP server.""" - verbose_logger.debug(f"Connecting to url: {server.url}") - verbose_logger.info(f"get_resources_from_server for {server.name}...") + verbose_logger.debug("Connecting to url: %s", server.url) + verbose_logger.info("get_resources_from_server for %s...", server.name) client = None @@ -3574,7 +3574,7 @@ class MCPServerManager: return prefixed_resources except Exception as e: - verbose_logger.warning(f"Failed to get resources from server {server.name}: {e}") + verbose_logger.warning("Failed to get resources from server %s: %s", server.name, e) return [] async def get_resource_templates_from_server( @@ -3587,8 +3587,8 @@ class MCPServerManager: ) -> list[ResourceTemplate]: """Fetch available resource templates from a single MCP server.""" - verbose_logger.debug(f"Connecting to url: {server.url}") - verbose_logger.info(f"get_resource_templates_from_server for {server.name}...") + verbose_logger.debug("Connecting to url: %s", server.url) + verbose_logger.info("get_resource_templates_from_server for %s...", server.name) client = None @@ -3618,7 +3618,7 @@ class MCPServerManager: return prefixed_templates except Exception as e: - verbose_logger.warning(f"Failed to get resource templates from server {server.name}: {e}") + verbose_logger.warning("Failed to get resource templates from server %s: %s", server.name, e) return [] async def read_resource_from_server( @@ -3631,8 +3631,8 @@ class MCPServerManager: ) -> ReadResourceResult: """Read resource contents from a specific MCP server.""" - verbose_logger.debug(f"Connecting to url: {server.url}") - verbose_logger.info(f"read_resource_from_server for {server.name}...") + verbose_logger.debug("Connecting to url: %s", server.url) + verbose_logger.info("read_resource_from_server for %s...", server.name) if server.static_headers: if extra_headers is None: @@ -3663,8 +3663,8 @@ class MCPServerManager: ) -> GetPromptResult: """Fetch a specific prompt definition from a single MCP server.""" - verbose_logger.debug(f"Connecting to url: {server.url}") - verbose_logger.info(f"get_prompt_from_server for {server.name}...") + verbose_logger.debug("Connecting to url: %s", server.url) + verbose_logger.info("get_prompt_from_server for %s...", server.name) if server.static_headers: if extra_headers is None: @@ -4206,19 +4206,19 @@ class MCPServerManager: try: with anyio.fail_after(MCP_TOOL_LISTING_TIMEOUT): tools = await client.list_tools(raise_on_error=True) - verbose_logger.debug(f"Tools from {server_name}: {tools}") + verbose_logger.debug("Tools from %s: %s", server_name, tools) return tools except TimeoutError as e: - verbose_logger.warning(f"Timeout while listing tools from {server_name}") + verbose_logger.warning("Timeout while listing tools from %s", server_name) raise MCPServerListError(ServerListFault(tag="timeout"), server_name) from e except asyncio.CancelledError as e: - verbose_logger.warning(f"Task cancelled while listing tools from {server_name}") + verbose_logger.warning("Task cancelled while listing tools from %s", server_name) raise MCPServerListError(ServerListFault(tag="internal"), server_name) from e except ConnectionError as e: - verbose_logger.warning(f"Connection error while listing tools from {server_name}: {e}") + verbose_logger.warning("Connection error while listing tools from %s: %s", server_name, e) raise MCPServerListError(ServerListFault(tag="unreachable"), server_name) from e except Exception as e: - verbose_logger.warning(f"Error listing tools from {server_name}: {e}") + verbose_logger.warning("Error listing tools from %s: %s", server_name, e) raise_classified_list_failure(e, server_name) _SHORT_PREFIX_MAX_REHASH_ATTEMPTS = 1024 @@ -4315,7 +4315,7 @@ class MCPServerManager: for spelling in iter_known_tool_name_spellings(original_name, server): self.tool_name_to_mcp_server_name_mapping[spelling] = prefix - verbose_logger.info(f"Successfully fetched {len(prefixed_tools)} tools from server {server.name}") + verbose_logger.info("Successfully fetched %s tools from server %s", len(prefixed_tools), server.name) return prefixed_tools def _create_prefixed_prompts( @@ -4342,7 +4342,7 @@ class MCPServerManager: prompt.name = name_to_use prefixed_prompts.append(prompt) - verbose_logger.info(f"Successfully fetched {len(prefixed_prompts)} prompts from server {server.name}") + verbose_logger.info("Successfully fetched %s prompts from server %s", len(prefixed_prompts), server.name) return prefixed_prompts def _create_prefixed_resources( @@ -4358,7 +4358,7 @@ class MCPServerManager: resource.name = name_to_use prefixed_resources.append(resource) - verbose_logger.info(f"Successfully fetched {len(prefixed_resources)} resources from server {server.name}") + verbose_logger.info("Successfully fetched %s resources from server %s", len(prefixed_resources), server.name) return prefixed_resources def _create_prefixed_resource_templates( @@ -4380,7 +4380,7 @@ class MCPServerManager: prefixed_templates.append(resource_template) verbose_logger.info( - f"Successfully fetched {len(prefixed_templates)} resource templates from server {server.name}" + "Successfully fetched %s resource templates from server %s", len(prefixed_templates), server.name ) return prefixed_templates @@ -4639,7 +4639,7 @@ class MCPServerManager: HTTPException, ) as e: # Re-raise guardrail exceptions to properly fail the MCP call - verbose_logger.error(f"Guardrail blocked MCP tool call pre call: {e}") + verbose_logger.error("Guardrail blocked MCP tool call pre call: %s", e) raise e return hook_result @@ -4995,7 +4995,7 @@ class MCPServerManager: GuardrailRaisedException, HTTPException, ) as e: - verbose_logger.error(f"Guardrail blocked MCP tool call during result check: {e}") + verbose_logger.error("Guardrail blocked MCP tool call during result check: %s", e) raise e # If proxy_logging_obj is None, the tool call result is at index 0 @@ -5194,7 +5194,7 @@ class MCPServerManager: GuardrailRaisedException, HTTPException, ) as e: - verbose_logger.error(f"Guardrail blocked MCP tool call during result check: {e}") + verbose_logger.error("Guardrail blocked MCP tool call during result check: %s", e) raise e async def call_tool( @@ -5345,7 +5345,7 @@ class MCPServerManager: asyncio.create_task(self._initialize_tool_name_to_mcp_server_name_mapping()) except RuntimeError as e: # no running event loop verbose_logger.exception( - f"No running event loop - skipping tool name to MCP server name mapping initialization: {e}" + "No running event loop - skipping tool name to MCP server name mapping initialization: %s", e ) async def _initialize_tool_name_to_mcp_server_name_mapping(self): @@ -5364,12 +5364,12 @@ class MCPServerManager: # at startup we have none, so an upstream 401 is normal. # Swallow it so we keep mapping the remaining servers. verbose_logger.debug( - f"Skipping tool name mapping for server {server.name} due to upstream auth error: {e}" + "Skipping tool name mapping for server %s due to upstream auth error: %s", server.name, e ) continue except Exception as e: verbose_logger.warning( - f"Failed to get tools from server {server.name} during tool name mapping initialization: {e}" + "Failed to get tools from server %s during tool name mapping initialization: %s", server.name, e ) continue for tool in tools: @@ -5449,7 +5449,7 @@ class MCPServerManager: } ) db_mcp_servers = [LiteLLM_MCPServerTable.model_validate(r.model_dump()) for r in raw_rows] - verbose_logger.info(f"Found {len(db_mcp_servers)} MCP servers in database") + verbose_logger.info("Found %s MCP servers in database", len(db_mcp_servers)) previous_registry = self.registry new_registry: dict[str, MCPServer] = {} @@ -5481,7 +5481,7 @@ class MCPServerManager: alias=getattr(server, "alias", None), server_name=getattr(server, "server_name", None), ) - verbose_logger.debug(f"Building server from DB: {server.server_id} ({server.server_name})") + verbose_logger.debug("Building server from DB: %s (%s)", server.server_id, server.server_name) # raw_rows come straight from the DB, so their global env var # values (like credentials) are still encrypted here, unlike the # already-decrypted records add_server/update_server are handed. @@ -5776,7 +5776,7 @@ class MCPServerManager: server = self.get_mcp_server_by_id(server_id) if not server: - verbose_logger.warning(f"MCP Server {server_id} not found") + verbose_logger.warning("MCP Server %s not found", server_id) return LiteLLM_MCPServerTable( server_id=server_id, server_name=None, @@ -5929,7 +5929,7 @@ class MCPServerManager: for server_id in allowed_server_ids: server = self.get_mcp_server_by_id(server_id) if not server: - verbose_logger.warning(f"MCP Server {server_id} not found in registry") + verbose_logger.warning("MCP Server %s not found in registry", server_id) continue mcp_server_table = self._build_mcp_server_table(server) diff --git a/litellm/proxy/_experimental/mcp_server/openapi_to_mcp_generator.py b/litellm/proxy/_experimental/mcp_server/openapi_to_mcp_generator.py index db2851c60aa..5b30b58c0e3 100644 --- a/litellm/proxy/_experimental/mcp_server/openapi_to_mcp_generator.py +++ b/litellm/proxy/_experimental/mcp_server/openapi_to_mcp_generator.py @@ -138,8 +138,9 @@ def get_base_url(spec: dict[str, Any], spec_path: str | None = None) -> str: base_domain = f"{parsed.scheme}://{parsed.netloc}" full_base_url = base_domain + server_url verbose_logger.info( - f"OpenAPI spec has relative server URL '{server_url}'. " - f"Deriving base from spec_path: {full_base_url}" + "OpenAPI spec has relative server URL '%s'. Deriving base from spec_path: %s", + server_url, + full_base_url, ) return full_base_url @@ -160,12 +161,12 @@ def get_base_url(spec: dict[str, Any], spec_path: str | None = None) -> str: ]: if spec_path.endswith(suffix): base_url = spec_path[: -len(suffix)] - verbose_logger.info(f"No server info in OpenAPI spec. Using derived base URL: {base_url}") + verbose_logger.info("No server info in OpenAPI spec. Using derived base URL: %s", base_url) return base_url if spec_path.split("/")[-1].endswith((".json", ".yaml", ".yml")): base_url = "/".join(spec_path.split("/")[:-1]) - verbose_logger.info(f"No server info in OpenAPI spec. Using derived base URL: {base_url}") + verbose_logger.info("No server info in OpenAPI spec. Using derived base URL: %s", base_url) return base_url return "" @@ -497,4 +498,4 @@ def register_tools_from_openapi(spec: dict[str, Any], base_url: str): input_schema=input_schema, handler=tool_func, ) - verbose_logger.debug(f"Registered tool: {tool_name}") + verbose_logger.debug("Registered tool: %s", tool_name) diff --git a/litellm/proxy/_experimental/mcp_server/rest_endpoints.py b/litellm/proxy/_experimental/mcp_server/rest_endpoints.py index d0458db51c6..57dfe6823b9 100644 --- a/litellm/proxy/_experimental/mcp_server/rest_endpoints.py +++ b/litellm/proxy/_experimental/mcp_server/rest_endpoints.py @@ -50,7 +50,7 @@ MCP_AVAILABLE: bool = True try: importlib.import_module("mcp") except ImportError as e: - verbose_logger.debug(f"MCP module not found: {e}") + verbose_logger.debug("MCP module not found: %s", e) MCP_AVAILABLE = False @@ -328,8 +328,10 @@ if MCP_AVAILABLE: return {"Authorization": f"Bearer {cred['access_token']}"} except Exception as e: verbose_logger.warning( - f"_get_user_oauth_extra_headers: failed to retrieve credential for " - f"user={user_id} server={server_id}: {e}" + "_get_user_oauth_extra_headers: failed to retrieve credential for user=%s server=%s: %s", + user_id, + server_id, + e, ) return None @@ -356,7 +358,7 @@ if MCP_AVAILABLE: creds = await list_user_oauth_credentials(prisma_client, user_id) return {c["server_id"]: c for c in creds if "server_id" in c} except Exception as e: - verbose_logger.warning(f"_prefetch_user_oauth_creds: failed to prefetch for user={user_id}: {e}") + verbose_logger.warning("_prefetch_user_oauth_creds: failed to prefetch for user=%s: %s", user_id, e) return {} def _create_tool_response_objects(tools, server: MCPServer): @@ -641,7 +643,7 @@ if MCP_AVAILABLE: raise except MCPServerListError as e: fault = classify_list_exception(e) - verbose_logger.info(f"Listing tools from {server.name} failed with a {fault.tag} fault") + verbose_logger.info("Listing tools from %s failed with a %s fault", server.name, fault.tag) raise HTTPException( status_code=list_fault_http_status(fault), detail={ @@ -650,7 +652,7 @@ if MCP_AVAILABLE: }, ) from e except Exception as e: - verbose_logger.exception(f"Error getting tools from {server.name}: {e}") + verbose_logger.exception("Error getting tools from %s: %s", server.name, e) return { "tools": [], "error": "server_error", @@ -862,7 +864,7 @@ if MCP_AVAILABLE: ) list_tools_result.extend(tools_result) except Exception as e: - verbose_logger.exception(f"Error getting tools from {server.name}: {e}") + verbose_logger.exception("Error getting tools from %s: %s", server.name, e) errors.append( f"{get_server_prefix(server)}: {classify_list_exception(e).tag}" if isinstance(e, (MCPServerListError, MCPUpstreamAuthError)) @@ -1052,7 +1054,7 @@ if MCP_AVAILABLE: }, ) except BlockedPiiEntityError as e: - verbose_logger.error(f"BlockedPiiEntityError in MCP tool call: {e}") + verbose_logger.error("BlockedPiiEntityError in MCP tool call: %s", e) raise HTTPException( status_code=400, detail={ @@ -1063,7 +1065,7 @@ if MCP_AVAILABLE: }, ) except GuardrailRaisedException as e: - verbose_logger.error(f"GuardrailRaisedException in MCP tool call: {e}") + verbose_logger.error("GuardrailRaisedException in MCP tool call: %s", e) raise HTTPException( status_code=400, detail={ @@ -1076,16 +1078,16 @@ if MCP_AVAILABLE: # A client-forwarded pass-through upstream 401 from either the direct or the virtual call # branch. Relay it as a 401 + WWW-Authenticate so the MCP client can re-run upstream OAuth, # and log at info: an expected caller-must-reauth signal, not an operator-actionable error. - verbose_logger.info(f"MCP tool call relaying upstream HTTP {e.status_code}") + verbose_logger.info("MCP tool call relaying upstream HTTP %s", e.status_code) raise _relay_upstream_auth_http_exception(e, request) except HTTPException as e: # Locally generated denials (tool/server permission, IP filtering, BYOK) stay at error level # so restriction probing keeps full monitoring visibility; the relayed upstream 401 above is # the only status demoted to info. - verbose_logger.error(f"HTTPException in MCP tool call: {e}") + verbose_logger.error("HTTPException in MCP tool call: %s", e) raise e except Exception as e: - verbose_logger.exception(f"Unexpected error in MCP tool call: {e}") + verbose_logger.exception("Unexpected error in MCP tool call: %s", e) raise HTTPException( status_code=500, detail={ diff --git a/litellm/proxy/_experimental/mcp_server/semantic_tool_filter.py b/litellm/proxy/_experimental/mcp_server/semantic_tool_filter.py index a7cc9fe3ed0..e2c60a488a4 100644 --- a/litellm/proxy/_experimental/mcp_server/semantic_tool_filter.py +++ b/litellm/proxy/_experimental/mcp_server/semantic_tool_filter.py @@ -98,7 +98,7 @@ class SemanticMCPToolFilter: tools = await global_mcp_server_manager.get_tools_for_server(server_id) all_tools.extend(tools) except Exception as e: - verbose_logger.warning(f"Failed to fetch tools from server {server_id}: {e}") + verbose_logger.warning("Failed to fetch tools from server %s: %s", server_id, e) continue if not all_tools: @@ -106,11 +106,11 @@ class SemanticMCPToolFilter: self.tool_router = None return - verbose_logger.info(f"Fetched {len(all_tools)} tools from {len(registry)} MCP servers") + verbose_logger.info("Fetched %s tools from %s MCP servers", len(all_tools), len(registry)) self._build_router(all_tools) except Exception as e: - verbose_logger.error(f"Failed to build router from MCP registry: {e}") + verbose_logger.error("Failed to build router from MCP registry: %s", e) self.tool_router = None raise @@ -172,10 +172,10 @@ class SemanticMCPToolFilter: auto_sync="local", ) - verbose_logger.info(f"Built semantic router with {len(routes)} tools") + verbose_logger.info("Built semantic router with %s tools", len(routes)) except Exception as e: - verbose_logger.error(f"Failed to build semantic router: {e}") + verbose_logger.error("Failed to build semantic router: %s", e) self.tool_router = None if _is_context_window_error(e): self.context_window_error = str(e) @@ -254,7 +254,7 @@ class SemanticMCPToolFilter: self._tool_map.update(missing) verbose_logger.info( - f"Semantic tool filter indexed {len(routes)} request-time tools missing from the startup index" + "Semantic tool filter indexed %s request-time tools missing from the startup index", len(routes) ) async def filter_tools( @@ -321,7 +321,8 @@ class SemanticMCPToolFilter: except Exception as e: if _is_context_window_error(e): verbose_logger.error( - f"Semantic tool filter embedding exceeded its context window: {e}", + "Semantic tool filter embedding exceeded its context window: %s", + e, exc_info=True, ) raise SemanticToolFilterContextWindowError( @@ -329,7 +330,7 @@ class SemanticMCPToolFilter: stage="the user query or the MCP tool descriptions being indexed", original_error=str(e), ) from e - verbose_logger.error(f"Semantic tool filter failed: {e}", exc_info=True) + verbose_logger.error("Semantic tool filter failed: %s", e, exc_info=True) return available_tools def _extract_tool_names_from_matches(self, matches) -> list[str]: diff --git a/litellm/proxy/_experimental/mcp_server/server.py b/litellm/proxy/_experimental/mcp_server/server.py index a894413019e..6e7af04e747 100644 --- a/litellm/proxy/_experimental/mcp_server/server.py +++ b/litellm/proxy/_experimental/mcp_server/server.py @@ -153,7 +153,7 @@ try: "active_mcp_session", default=None ) except ImportError as e: - verbose_logger.debug(f"MCP module not found: {e}") + verbose_logger.debug("MCP module not found: %s", e) MCP_AVAILABLE = False # When MCP is not available, we set these to None at module level # All code using these types is inside `if MCP_AVAILABLE:` blocks @@ -657,7 +657,7 @@ if MCP_AVAILABLE: try: await _purge_expired_stateful_session_auth_contexts() except Exception as e: - verbose_logger.exception(f"Error cleaning up expired MCP stateful sessions: {e}") + verbose_logger.exception("Error cleaning up expired MCP stateful sessions: %s", e) async def initialize_session_managers(): """Initialize the session managers. Can be called from main app lifespan.""" @@ -713,7 +713,7 @@ if MCP_AVAILABLE: if _sse_session_manager_cm: await _sse_session_manager_cm.__aexit__(None, None, None) except Exception as e: - verbose_logger.exception(f"Error during session manager shutdown: {e}") + verbose_logger.exception("Error during session manager shutdown: %s", e) _session_manager_cm = None _session_manager_stateful_cm = None @@ -765,10 +765,11 @@ if MCP_AVAILABLE: raw_headers, _client_ip, ) = await get_or_extract_auth_context() - verbose_logger.debug(f"MCP list_tools - User API Key Auth from context: {user_api_key_auth}") - verbose_logger.debug(f"MCP list_tools - MCP servers from context: {mcp_servers}") + verbose_logger.debug("MCP list_tools - User API Key Auth from context: %s", user_api_key_auth) + verbose_logger.debug("MCP list_tools - MCP servers from context: %s", mcp_servers) verbose_logger.debug( - f"MCP list_tools - MCP server auth headers: {list(mcp_server_auth_headers.keys()) if mcp_server_auth_headers else None}" + "MCP list_tools - MCP server auth headers: %s", + list(mcp_server_auth_headers.keys()) if mcp_server_auth_headers else None, ) if getattr( getattr(user_api_key_auth, "object_permission", None), @@ -795,7 +796,7 @@ if MCP_AVAILABLE: log_list_tools_to_spendlogs=True, list_tools_log_source="mcp_protocol", ) - verbose_logger.info(f"MCP list_tools - Successfully returned {len(listing.tools)} tools") + verbose_logger.info("MCP list_tools - Successfully returned %s tools", len(listing.tools)) if not listing.outcomes: return listing.tools outcome_meta = { @@ -805,7 +806,7 @@ if MCP_AVAILABLE: } return ListToolsResult.model_validate({"tools": listing.tools, "_meta": outcome_meta}) except Exception as e: - verbose_logger.exception(f"Error in list_tools endpoint: {e}") + verbose_logger.exception("Error in list_tools endpoint: %s", e) # Return empty list instead of failing completely # This prevents the HTTP stream from failing and allows the client to get a response return [] @@ -823,7 +824,7 @@ if MCP_AVAILABLE: try: host_ctx = host_server.request_context except Exception as e: - verbose_logger.warning(f"Could not capture host progress context: {e}") + verbose_logger.warning("Could not capture host progress context: %s", e) return None if not (host_ctx and hasattr(host_ctx, "meta") and host_ctx.meta): @@ -841,11 +842,11 @@ if MCP_AVAILABLE: progress=progress, total=total, ) - verbose_logger.debug(f"Forwarded progress {progress}/{total} to Host") + verbose_logger.debug("Forwarded progress %s/%s to Host", progress, total) except Exception as e: - verbose_logger.error(f"Failed to forward progress to Host: {e}") + verbose_logger.error("Failed to forward progress to Host: %s", e) - verbose_logger.debug(f"Host progressToken captured: {str(host_token)[:8]}...") + verbose_logger.debug("Host progressToken captured: %s...", str(host_token)[:8]) return forward_progress async def _build_virtual_call_logging_obj( @@ -1000,10 +1001,12 @@ if MCP_AVAILABLE: _client_ip, ) = await get_or_extract_auth_context() verbose_logger.debug( - f"MCP mcp_server_tool_call - user_api_key_auth={user_api_key_auth}, user_role={getattr(user_api_key_auth, 'user_role', 'N/A')}" + "MCP mcp_server_tool_call - user_api_key_auth=%s, user_role=%s", + user_api_key_auth, + getattr(user_api_key_auth, "user_role", "N/A"), ) - verbose_logger.debug(f"MCP mcp_server_tool_call - User API Key Auth from context: {user_api_key_auth}") + verbose_logger.debug("MCP mcp_server_tool_call - User API Key Auth from context: %s", user_api_key_auth) try: # Inside this try so virtual-tool errors convert to isError @@ -1080,7 +1083,7 @@ if MCP_AVAILABLE: isError=True, ) except BlockedPiiEntityError as e: - verbose_logger.error(f"BlockedPiiEntityError in MCP tool call: {e}") + verbose_logger.error("BlockedPiiEntityError in MCP tool call: %s", e) return CallToolResult( content=[ TextContent( @@ -1091,13 +1094,13 @@ if MCP_AVAILABLE: isError=True, ) except GuardrailRaisedException as e: - verbose_logger.error(f"GuardrailRaisedException in MCP tool call: {e}") + verbose_logger.error("GuardrailRaisedException in MCP tool call: %s", e) return CallToolResult( content=[TextContent(text=f"Error: Guardrail violation - {e}", type="text")], isError=True, ) except HTTPException as e: - verbose_logger.error(f"HTTPException in MCP tool call: {e}") + verbose_logger.error("HTTPException in MCP tool call: %s", e) return CallToolResult( content=[TextContent(text=f"Error: {e.detail}", type="text")], isError=True, @@ -1108,7 +1111,7 @@ if MCP_AVAILABLE: # call path and the connect-time preemptive check do. Return an explicit isError # naming the upstream status (at info level, not a traceback) so the client still # learns it must re-authenticate upstream and expected pass-through 401s don't spam. - verbose_logger.info(f"Upstream auth failure calling MCP tool: HTTP {e.status_code}") + verbose_logger.info("Upstream auth failure calling MCP tool: HTTP %s", e.status_code) return CallToolResult( content=[ TextContent( @@ -1119,7 +1122,7 @@ if MCP_AVAILABLE: isError=True, ) except Exception as e: - verbose_logger.exception(f"MCP mcp_server_tool_call - error: {e}") + verbose_logger.exception("MCP mcp_server_tool_call - error: %s", e) return CallToolResult( content=[TextContent(text=f"Error: {e}", type="text")], isError=True, @@ -1155,10 +1158,11 @@ if MCP_AVAILABLE: raw_headers, _client_ip, ) = await get_or_extract_auth_context() - verbose_logger.debug(f"MCP list_prompts - User API Key Auth from context: {user_api_key_auth}") - verbose_logger.debug(f"MCP list_prompts - MCP servers from context: {mcp_servers}") + verbose_logger.debug("MCP list_prompts - User API Key Auth from context: %s", user_api_key_auth) + verbose_logger.debug("MCP list_prompts - MCP servers from context: %s", mcp_servers) verbose_logger.debug( - f"MCP list_prompts - MCP server auth headers: {list(mcp_server_auth_headers.keys()) if mcp_server_auth_headers else None}" + "MCP list_prompts - MCP server auth headers: %s", + list(mcp_server_auth_headers.keys()) if mcp_server_auth_headers else None, ) # Get mcp_servers from context variable verbose_logger.debug("MCP list_prompts - Calling _list_prompts") @@ -1170,10 +1174,10 @@ if MCP_AVAILABLE: oauth2_headers=oauth2_headers, raw_headers=raw_headers, ) - verbose_logger.info(f"MCP list_prompts - Successfully returned {len(prompts)} prompts") + verbose_logger.info("MCP list_prompts - Successfully returned %s prompts", len(prompts)) return prompts except Exception as e: - verbose_logger.exception(f"Error in list_prompts endpoint: {e}") + verbose_logger.exception("Error in list_prompts endpoint: %s", e) # Return empty list instead of failing completely # This prevents the HTTP stream from failing and allows the client to get a response return [] @@ -1213,7 +1217,7 @@ if MCP_AVAILABLE: _client_ip, ) = await get_or_extract_auth_context() - verbose_logger.debug(f"MCP mcp_server_tool_call - User API Key Auth from context: {user_api_key_auth}") + verbose_logger.debug("MCP mcp_server_tool_call - User API Key Auth from context: %s", user_api_key_auth) return await mcp_get_prompt( name=name, arguments=arguments, @@ -1248,10 +1252,11 @@ if MCP_AVAILABLE: raw_headers, _client_ip, ) = await get_or_extract_auth_context() - verbose_logger.debug(f"MCP list_resources - User API Key Auth from context: {user_api_key_auth}") - verbose_logger.debug(f"MCP list_resources - MCP servers from context: {mcp_servers}") + verbose_logger.debug("MCP list_resources - User API Key Auth from context: %s", user_api_key_auth) + verbose_logger.debug("MCP list_resources - MCP servers from context: %s", mcp_servers) verbose_logger.debug( - f"MCP list_resources - MCP server auth headers: {list(mcp_server_auth_headers.keys()) if mcp_server_auth_headers else None}" + "MCP list_resources - MCP server auth headers: %s", + list(mcp_server_auth_headers.keys()) if mcp_server_auth_headers else None, ) resources = await _list_mcp_resources( @@ -1262,10 +1267,10 @@ if MCP_AVAILABLE: oauth2_headers=oauth2_headers, raw_headers=raw_headers, ) - verbose_logger.info(f"MCP list_resources - Successfully returned {len(resources)} resources") + verbose_logger.info("MCP list_resources - Successfully returned %s resources", len(resources)) return resources except Exception as e: - verbose_logger.exception(f"Error in list_resources endpoint: {e}") + verbose_logger.exception("Error in list_resources endpoint: %s", e) return [] finally: if _session_reset_token is not None: @@ -1291,10 +1296,11 @@ if MCP_AVAILABLE: raw_headers, _client_ip, ) = await get_or_extract_auth_context() - verbose_logger.debug(f"MCP list_resource_templates - User API Key Auth from context: {user_api_key_auth}") - verbose_logger.debug(f"MCP list_resource_templates - MCP servers from context: {mcp_servers}") + verbose_logger.debug("MCP list_resource_templates - User API Key Auth from context: %s", user_api_key_auth) + verbose_logger.debug("MCP list_resource_templates - MCP servers from context: %s", mcp_servers) verbose_logger.debug( - f"MCP list_resource_templates - MCP server auth headers: {list(mcp_server_auth_headers.keys()) if mcp_server_auth_headers else None}" + "MCP list_resource_templates - MCP server auth headers: %s", + list(mcp_server_auth_headers.keys()) if mcp_server_auth_headers else None, ) resource_templates = await _list_mcp_resource_templates( @@ -1306,11 +1312,11 @@ if MCP_AVAILABLE: raw_headers=raw_headers, ) verbose_logger.info( - f"MCP list_resource_templates - Successfully returned {len(resource_templates)} resource templates" + "MCP list_resource_templates - Successfully returned %s resource templates", len(resource_templates) ) return resource_templates except Exception as e: - verbose_logger.exception(f"Error in list_resource_templates endpoint: {e}") + verbose_logger.exception("Error in list_resource_templates endpoint: %s", e) return [] finally: if _session_reset_token is not None: @@ -1400,7 +1406,7 @@ if MCP_AVAILABLE: if server_id == server.server_id: filtered_server[server.server_id] = server except Exception as e: - verbose_logger.debug(f"Could not resolve '{server_or_group}' as access group: {e}") + verbose_logger.debug("Could not resolve '%s' as access group: %s", server_or_group, e) if filtered_server: return list(filtered_server.values()) @@ -1659,7 +1665,7 @@ if MCP_AVAILABLE: creds = await list_user_oauth_credentials(prisma_client, user_id) return {c["server_id"]: c for c in creds if "server_id" in c} except Exception as e: - verbose_logger.warning(f"_prefetch_oauth_creds_for_user: failed to prefetch for user={user_id}: {e}") + verbose_logger.warning("_prefetch_oauth_creds_for_user: failed to prefetch for user=%s: %s", user_id, e) return {} def _prepare_mcp_server_headers( @@ -2023,7 +2029,10 @@ if MCP_AVAILABLE: filtered_tools = apply_tool_overrides(filtered_tools, server) verbose_logger.debug( - f"Successfully fetched {len(tools)} tools from server {server.name}, {len(filtered_tools)} after filtering" + "Successfully fetched %s tools from server %s, %s after filtering", + len(tools), + server.name, + len(filtered_tools), ) return filtered_tools, ServerListOk(tool_count=len(filtered_tools)) except MCPUpstreamAuthError as e: @@ -2033,10 +2042,10 @@ if MCP_AVAILABLE: # 401 + WWW-Authenticate (the MCP session manager serializes it as a JSON-RPC # error). Single-server routes surface it via the request-scope preemptive # check in _raise_preemptive_401_for_unauthenticated_servers instead. - verbose_logger.debug(f"MCP list_tools: omitting {server.name}; it needs upstream auth") + verbose_logger.debug("MCP list_tools: omitting %s; it needs upstream auth", server.name) return [], classify_list_exception(e) except Exception as e: - verbose_logger.exception(f"Error getting tools from server {server.name}: {e}") + verbose_logger.exception("Error getting tools from server %s: %s", server.name, e) return [], classify_list_exception(e) # Fetch tools from all servers in parallel @@ -2089,7 +2098,7 @@ if MCP_AVAILABLE: log_exc, ) - verbose_logger.info(f"Successfully fetched {len(all_tools)} tools total from all MCP servers") + verbose_logger.info("Successfully fetched %s tools total from all MCP servers", len(all_tools)) return AggregateToolListing(tools=all_tools, outcomes=server_outcomes) except Exception as e: @@ -2167,12 +2176,12 @@ if MCP_AVAILABLE: all_prompts.extend(prompts) - verbose_logger.debug(f"Successfully fetched {len(prompts)} prompts from server {server.name}") + verbose_logger.debug("Successfully fetched %s prompts from server %s", len(prompts), server.name) except Exception as e: - verbose_logger.exception(f"Error getting prompts from server {server.name}: {e}") + verbose_logger.exception("Error getting prompts from server %s: %s", server.name, e) # Continue with other servers instead of failing completely - verbose_logger.info(f"Successfully fetched {len(all_prompts)} prompts total from all MCP servers") + verbose_logger.info("Successfully fetched %s prompts total from all MCP servers", len(all_prompts)) return all_prompts @@ -2219,11 +2228,11 @@ if MCP_AVAILABLE: ) all_resources.extend(resources) - verbose_logger.debug(f"Successfully fetched {len(resources)} resources from server {server.name}") + verbose_logger.debug("Successfully fetched %s resources from server %s", len(resources), server.name) except Exception as e: - verbose_logger.exception(f"Error getting resources from server {server.name}: {e}") + verbose_logger.exception("Error getting resources from server %s: %s", server.name, e) - verbose_logger.info(f"Successfully fetched {len(all_resources)} resources total from all MCP servers") + verbose_logger.info("Successfully fetched %s resources total from all MCP servers", len(all_resources)) return all_resources @@ -2356,10 +2365,10 @@ if MCP_AVAILABLE: list_tools_log_source=list_tools_log_source, client_ip=client_ip, ) - verbose_logger.debug(f"Successfully fetched {len(listing.tools)} tools from managed MCP servers") + verbose_logger.debug("Successfully fetched %s tools from managed MCP servers", len(listing.tools)) return listing except Exception as e: - verbose_logger.exception(f"Error getting tools from managed MCP servers: {e}") + verbose_logger.exception("Error getting tools from managed MCP servers: %s", e) # Continue with an empty listing instead of failing completely return AggregateToolListing(tools=[], outcomes={}) @@ -2396,9 +2405,9 @@ if MCP_AVAILABLE: oauth2_headers=oauth2_headers, raw_headers=raw_headers, ) - verbose_logger.debug(f"Successfully fetched {len(managed_prompts)} prompts from managed MCP servers") + verbose_logger.debug("Successfully fetched %s prompts from managed MCP servers", len(managed_prompts)) except Exception as e: - verbose_logger.exception(f"Error getting tools from managed MCP servers: {e}") + verbose_logger.exception("Error getting tools from managed MCP servers: %s", e) # Continue with empty managed tools list instead of failing completely return managed_prompts @@ -2426,9 +2435,9 @@ if MCP_AVAILABLE: oauth2_headers=oauth2_headers, raw_headers=raw_headers, ) - verbose_logger.debug(f"Successfully fetched {len(managed_resources)} resources from managed MCP servers") + verbose_logger.debug("Successfully fetched %s resources from managed MCP servers", len(managed_resources)) except Exception as e: - verbose_logger.exception(f"Error getting resources from managed MCP servers: {e}") + verbose_logger.exception("Error getting resources from managed MCP servers: %s", e) return managed_resources @@ -2814,7 +2823,7 @@ if MCP_AVAILABLE: if isinstance(hook_result, dict) and "arguments" in hook_result: arguments = hook_result["arguments"] - verbose_logger.debug(f"Executing local registry tool: {name}") + verbose_logger.debug("Executing local registry tool: %s", name) # For BYOK servers the credential must be injected via a ContextVar # because the tool function has headers baked into its closure. # Pre-format the full Authorization header value using the server's @@ -3335,7 +3344,7 @@ if MCP_AVAILABLE: result = tool.handler(**arguments) return [TextContent(text=str(result), type="text")] except Exception as e: - verbose_logger.exception(f"Error executing local tool {name}: {e}") + verbose_logger.exception("Error executing local tool %s: %s", name, e) return [TextContent(text=f"Error: {e}", type="text")] def _get_mcp_servers_in_path(path: str) -> list[str] | None: @@ -3986,7 +3995,7 @@ if MCP_AVAILABLE: # to the appropriate response. return exc.response.status_code, exc.response.headers.get("www-authenticate") except Exception as exc: - verbose_logger.debug(f"_probe_upstream_auth: probe to {url} failed ({exc}), allowing request through") + verbose_logger.debug("_probe_upstream_auth: probe to %s failed (%s), allowing request through", url, exc) return 200, None async def _check_passthrough_upstream_auth( @@ -4124,9 +4133,9 @@ if MCP_AVAILABLE: # Extract client IP for MCP access control _client_ip = IPAddressUtils.get_mcp_client_ip(StarletteRequest(scope)) - verbose_logger.debug(f"MCP request mcp_servers (header/path): {mcp_servers}") + verbose_logger.debug("MCP request mcp_servers (header/path): %s", mcp_servers) verbose_logger.debug( - f"MCP server auth headers: {list(mcp_server_auth_headers.keys()) if mcp_server_auth_headers else None}" + "MCP server auth headers: %s", list(mcp_server_auth_headers.keys()) if mcp_server_auth_headers else None ) # Strip any client-supplied x-mcp-toolset-id to prevent forgery. @@ -4413,7 +4422,7 @@ if MCP_AVAILABLE: # 500 that surfaces as a cancelled tool call. raise _proxy_exception_to_http_exception(e) except Exception as e: - verbose_logger.exception(f"Error handling MCP request: {e}") + verbose_logger.exception("Error handling MCP request: %s", e) # Try to send a graceful error response for non-HTTP exceptions try: from starlette.status import HTTP_500_INTERNAL_SERVER_ERROR @@ -4424,7 +4433,7 @@ if MCP_AVAILABLE: ) await error_response(scope, receive, send) except Exception as response_error: - verbose_logger.exception(f"Failed to send error response: {response_error}") + verbose_logger.exception("Failed to send error response: %s", response_error) # If we can't send a proper response, re-raise the original error raise e @@ -4445,9 +4454,9 @@ if MCP_AVAILABLE: # Extract client IP for MCP access control _sse_client_ip = IPAddressUtils.get_mcp_client_ip(StarletteRequest(scope)) - verbose_logger.debug(f"MCP request mcp_servers (header/path): {mcp_servers}") + verbose_logger.debug("MCP request mcp_servers (header/path): %s", mcp_servers) verbose_logger.debug( - f"MCP server auth headers: {list(mcp_server_auth_headers.keys()) if mcp_server_auth_headers else None}" + "MCP server auth headers: %s", list(mcp_server_auth_headers.keys()) if mcp_server_auth_headers else None ) # Strip any client-supplied x-mcp-toolset-id to prevent forgery. @@ -4524,7 +4533,7 @@ if MCP_AVAILABLE: # 500 that surfaces as a cancelled tool call. raise _proxy_exception_to_http_exception(e) except Exception as e: - verbose_logger.exception(f"Error handling MCP request: {e}") + verbose_logger.exception("Error handling MCP request: %s", e) # Try to send a graceful error response for non-HTTP exceptions try: # Send a proper HTTP error response instead of letting the exception bubble up @@ -4537,7 +4546,7 @@ if MCP_AVAILABLE: ) await error_response(scope, receive, send) except Exception as response_error: - verbose_logger.exception(f"Failed to send error response: {response_error}") + verbose_logger.exception("Failed to send error response: %s", response_error) # If we can't send a proper response, re-raise the original error raise e diff --git a/litellm/proxy/_experimental/mcp_server/sse_transport.py b/litellm/proxy/_experimental/mcp_server/sse_transport.py index 09863a7d391..fd90cb59d97 100644 --- a/litellm/proxy/_experimental/mcp_server/sse_transport.py +++ b/litellm/proxy/_experimental/mcp_server/sse_transport.py @@ -46,7 +46,7 @@ class SseServerTransport: super().__init__() self._endpoint = endpoint self._read_stream_writers = {} - verbose_logger.debug(f"SseServerTransport initialized with endpoint: {endpoint}") + verbose_logger.debug("SseServerTransport initialized with endpoint: %s", endpoint) @asynccontextmanager async def connect_sse(self, request: Request): @@ -67,7 +67,7 @@ class SseServerTransport: session_id = uuid4() session_uri = f"{quote(self._endpoint)}?session_id={session_id.hex}" self._read_stream_writers[session_id] = read_stream_writer - verbose_logger.debug(f"Created new session with ID: {session_id}") + verbose_logger.debug("Created new session with ID: %s", session_id) sse_stream_writer: MemoryObjectSendStream[dict[str, Any]] sse_stream_reader: MemoryObjectReceiveStream[dict[str, Any]] @@ -77,10 +77,10 @@ class SseServerTransport: verbose_logger.debug("Starting SSE writer") async with sse_stream_writer, write_stream_reader: await sse_stream_writer.send({"event": "endpoint", "data": session_uri}) - verbose_logger.debug(f"Sent endpoint event: {session_uri}") + verbose_logger.debug("Sent endpoint event: %s", session_uri) async for message in write_stream_reader: - verbose_logger.debug(f"Sending message via SSE: {message}") + verbose_logger.debug("Sending message via SSE: %s", message) await sse_stream_writer.send( { "event": "message", @@ -108,31 +108,31 @@ class SseServerTransport: try: session_id = UUID(hex=session_id_param) - verbose_logger.debug(f"Parsed session ID: {session_id}") + verbose_logger.debug("Parsed session ID: %s", session_id) except ValueError: - verbose_logger.warning(f"Received invalid session ID: {session_id_param}") + verbose_logger.warning("Received invalid session ID: %s", session_id_param) response = Response("Invalid session ID", status_code=400) return response writer = self._read_stream_writers.get(session_id) if not writer: - verbose_logger.warning(f"Could not find session for ID: {session_id}") + verbose_logger.warning("Could not find session for ID: %s", session_id) response = Response("Could not find session", status_code=404) return response json = await request.json() - verbose_logger.debug(f"Received JSON: {json}") + verbose_logger.debug("Received JSON: %s", json) try: message = types.JSONRPCMessage.model_validate(json) - verbose_logger.debug(f"Validated client message: {message}") + verbose_logger.debug("Validated client message: %s", message) except ValidationError as err: - verbose_logger.error(f"Failed to parse message: {err}") + verbose_logger.error("Failed to parse message: %s", err) response = Response("Could not parse message", status_code=400) await writer.send(err) return response - verbose_logger.debug(f"Sending message to writer: {message}") + verbose_logger.debug("Sending message to writer: %s", message) response = Response("Accepted", status_code=202) await writer.send(message) return response diff --git a/litellm/proxy/_experimental/mcp_server/tool_registry.py b/litellm/proxy/_experimental/mcp_server/tool_registry.py index 1ebeac9993a..f2ef94f412b 100644 --- a/litellm/proxy/_experimental/mcp_server/tool_registry.py +++ b/litellm/proxy/_experimental/mcp_server/tool_registry.py @@ -40,7 +40,7 @@ class MCPToolRegistry: input_schema=input_schema, handler=handler, ) - verbose_logger.debug(f"Registered tool: {name}") + verbose_logger.debug("Registered tool: %s", name) def get_tool(self, name: str) -> MCPTool | None: """ @@ -122,7 +122,7 @@ class MCPToolRegistry: handler = get_instance_fn(handler_name, config_file_path) if handler is None: - verbose_logger.warning(f"Warning: Could not find handler {handler_name} for tool {name}") + verbose_logger.warning("Warning: Could not find handler %s for tool %s", handler_name, name) continue # Register the tool diff --git a/litellm/proxy/_experimental/mcp_server/toolset_db.py b/litellm/proxy/_experimental/mcp_server/toolset_db.py index a321c40b9e2..26c830d5d50 100644 --- a/litellm/proxy/_experimental/mcp_server/toolset_db.py +++ b/litellm/proxy/_experimental/mcp_server/toolset_db.py @@ -55,7 +55,7 @@ async def list_mcp_toolsets( rows = await MCPToolsetRepository(prisma_client).table.find_many(where=where) return [_toolset_from_row(r) for r in rows] except Exception as e: - verbose_proxy_logger.warning(f"litellm.proxy._experimental.mcp_server.toolset_db::list_mcp_toolsets - {e}") + verbose_proxy_logger.warning("litellm.proxy._experimental.mcp_server.toolset_db::list_mcp_toolsets - %s", e) return [] diff --git a/litellm/proxy/_experimental/mcp_server/ui_session_utils.py b/litellm/proxy/_experimental/mcp_server/ui_session_utils.py index 14726cba3a7..0e750453be6 100644 --- a/litellm/proxy/_experimental/mcp_server/ui_session_utils.py +++ b/litellm/proxy/_experimental/mcp_server/ui_session_utils.py @@ -91,7 +91,7 @@ async def admitted_user_context(user_api_key_auth: UserAPIKeyAuth) -> UserAPIKey try: admitted = await MCPRequestHandler._reload_admitted_user(user_id) except HTTPException as e: - verbose_logger.warning(f"MCP dashboard session: admitted-subject reload failed for {user_id}: {e.detail}") + verbose_logger.warning("MCP dashboard session: admitted-subject reload failed for %s: %s", user_id, e.detail) return None return admitted.model_copy(update={"parent_otel_span": user_api_key_auth.parent_otel_span}) diff --git a/litellm/proxy/agent_endpoints/a2a_endpoints.py b/litellm/proxy/agent_endpoints/a2a_endpoints.py index 6d48b31658b..c10b3d95cd3 100644 --- a/litellm/proxy/agent_endpoints/a2a_endpoints.py +++ b/litellm/proxy/agent_endpoints/a2a_endpoints.py @@ -468,7 +468,7 @@ async def _handle_stream_message( obj = normalize_stream_event(obj, served_version, request_id=request_id) yield json.dumps(obj) + "\n" except Exception as e: - verbose_proxy_logger.exception(f"Error streaming A2A response: {e}") + verbose_proxy_logger.exception("Error streaming A2A response: %s", e) if ( use_proxy_hooks and proxy_logging_obj is not None @@ -561,13 +561,13 @@ async def get_agent_card( served_version = _served_version(agent, request) agent_card = normalize_agent_card(agent_card, served_version) - verbose_proxy_logger.debug(f"Returning agent card for '{agent_id}' with proxy URL: {proxy_url}") + verbose_proxy_logger.debug("Returning agent card for '%s' with proxy URL: %s", agent_id, proxy_url) return JSONResponse(content=agent_card) except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error getting agent card: {e}") + verbose_proxy_logger.exception("Error getting agent card: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -615,7 +615,7 @@ async def invoke_agent_a2a( body = await request.json() request_data = body - verbose_proxy_logger.debug(f"A2A request for agent '{agent_id}': {body}") + verbose_proxy_logger.debug("A2A request for agent '%s': %s", agent_id, body) # Validate JSON-RPC format if body.get("jsonrpc") != "2.0": @@ -690,7 +690,9 @@ async def invoke_agent_a2a( if not agent_url and not custom_llm_provider: return _jsonrpc_error(request_id, -32000, f"Agent '{agent_id}' has no URL configured", 500) - verbose_proxy_logger.info(f"Proxying A2A request to agent '{agent_id}' at {agent_url or 'completion-bridge'}") + verbose_proxy_logger.info( + "Proxying A2A request to agent '%s' at %s", agent_id, agent_url or "completion-bridge" + ) # Set up data dict for litellm processing if "metadata" not in body: @@ -965,7 +967,7 @@ async def invoke_agent_a2a( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error invoking agent: {e}") + verbose_proxy_logger.exception("Error invoking agent: %s", e) try: await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, diff --git a/litellm/proxy/agent_endpoints/a2a_routing.py b/litellm/proxy/agent_endpoints/a2a_routing.py index 0410f067560..6446a9ad221 100644 --- a/litellm/proxy/agent_endpoints/a2a_routing.py +++ b/litellm/proxy/agent_endpoints/a2a_routing.py @@ -46,7 +46,7 @@ async def route_a2a_agent_request( # Look up agent in registry agent = global_agent_registry.get_agent_by_name(agent_name) if agent is None: - verbose_proxy_logger.error(f"[A2A] Agent '{agent_name}' not found in registry") + verbose_proxy_logger.error("[A2A] Agent '%s' not found in registry", agent_name) route_name = ROUTE_ENDPOINT_MAPPING.get(route_type, route_type) raise ProxyModelNotFoundError(route=route_name, model_name=model_name) @@ -68,12 +68,12 @@ async def route_a2a_agent_request( # Get API base URL from agent config if not agent.agent_card_params or "url" not in agent.agent_card_params: - verbose_proxy_logger.error(f"[A2A] Agent '{agent_name}' has no URL configured") + verbose_proxy_logger.error("[A2A] Agent '%s' has no URL configured", agent_name) route_name = ROUTE_ENDPOINT_MAPPING.get(route_type, route_type) raise ProxyModelNotFoundError(route=route_name, model_name=model_name) # Inject API base and route to litellm data["api_base"] = agent.agent_card_params["url"] - verbose_proxy_logger.debug(f"[A2A] Routing {model_name} to {data['api_base']}") + verbose_proxy_logger.debug("[A2A] Routing %s to %s", model_name, data["api_base"]) return getattr(litellm, f"{route_type}")(**data) diff --git a/litellm/proxy/agent_endpoints/auth/agent_permission_handler.py b/litellm/proxy/agent_endpoints/auth/agent_permission_handler.py index 6999228c83d..e0b8b24de97 100644 --- a/litellm/proxy/agent_endpoints/auth/agent_permission_handler.py +++ b/litellm/proxy/agent_endpoints/auth/agent_permission_handler.py @@ -59,7 +59,7 @@ class AgentRequestHandler: return list(set(allowed_agents)) except Exception as e: - verbose_logger.warning(f"Failed to get allowed agents: {e}") + verbose_logger.warning("Failed to get allowed agents: %s", e) return [] @staticmethod @@ -179,7 +179,7 @@ class AgentRequestHandler: return list(set(all_agents)) except Exception as e: - verbose_logger.warning(f"Failed to get allowed agents for key: {e}") + verbose_logger.warning("Failed to get allowed agents for key: %s", e) return [] @staticmethod @@ -255,7 +255,7 @@ class AgentRequestHandler: # litellm-dashboard is the default UI team and will never have agents; # skip noisy warnings for it. if user_api_key_auth.team_id != UI_TEAM_ID: - verbose_logger.warning(f"Failed to get allowed agents for team: {e}") + verbose_logger.warning("Failed to get allowed agents for team: %s", e) return [] @staticmethod @@ -285,7 +285,7 @@ class AgentRequestHandler: for agent in agents: agent_ids.add(agent.agent_id) except Exception as e: - verbose_logger.debug(f"Error getting agents from access groups: {e}") + verbose_logger.debug("Error getting agents from access groups: %s", e) return agent_ids @staticmethod @@ -310,7 +310,7 @@ class AgentRequestHandler: return list(agent_ids) except Exception as e: - verbose_logger.warning(f"Failed to get agents from access groups: {e}") + verbose_logger.warning("Failed to get agents from access groups: %s", e) return [] @staticmethod @@ -369,7 +369,7 @@ class AgentRequestHandler: return key_object_permission.agent_access_groups or [] except Exception as e: - verbose_logger.warning(f"Failed to get agent access groups for key: {e}") + verbose_logger.warning("Failed to get agent access groups for key: %s", e) return [] @staticmethod @@ -412,5 +412,5 @@ class AgentRequestHandler: return object_permissions.agent_access_groups or [] except Exception as e: - verbose_logger.warning(f"Failed to get agent access groups for team: {e}") + verbose_logger.warning("Failed to get agent access groups for team: %s", e) return [] diff --git a/litellm/proxy/agent_endpoints/endpoints.py b/litellm/proxy/agent_endpoints/endpoints.py index db5341dbe5a..b4c0675c5ef 100644 --- a/litellm/proxy/agent_endpoints/endpoints.py +++ b/litellm/proxy/agent_endpoints/endpoints.py @@ -316,7 +316,7 @@ async def get_agents( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.agent_endpoints.get_agents(): Exception occurred - {e}") + verbose_proxy_logger.exception("litellm.proxy.agent_endpoints.get_agents(): Exception occurred - %s", e) raise HTTPException(status_code=500, detail={"error": f"Internal server error: {e}"}) @@ -434,10 +434,10 @@ async def create_agent( # Also register in memory try: AGENT_REGISTRY.register_agent(agent_config=result) - verbose_proxy_logger.info(f"Successfully registered agent '{agent_name}' (ID: {agent_id}) in memory") + verbose_proxy_logger.info("Successfully registered agent '%s' (ID: %s) in memory", agent_name, agent_id) except Exception as reg_error: verbose_proxy_logger.warning( - f"Failed to register agent '{agent_name}' (ID: {agent_id}) in memory: {reg_error}" + "Failed to register agent '%s' (ID: %s) in memory: %s", agent_name, agent_id, reg_error ) return result @@ -445,7 +445,7 @@ async def create_agent( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error adding agent to db: {e}") + verbose_proxy_logger.exception("Error adding agent to db: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -529,7 +529,7 @@ async def get_agent_by_id( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error getting agent from db: {e}") + verbose_proxy_logger.exception("Error getting agent from db: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -624,14 +624,14 @@ async def update_agent( AGENT_REGISTRY.register_agent(agent_config=result) verbose_proxy_logger.info( - f"Successfully updated agent '{existing_agent.get('agent_name')}' (ID: {agent_id}) in memory" + "Successfully updated agent '%s' (ID: %s) in memory", existing_agent.get("agent_name"), agent_id ) return result except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error updating agent: {e}") + verbose_proxy_logger.exception("Error updating agent: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -727,14 +727,14 @@ async def patch_agent( AGENT_REGISTRY.register_agent(agent_config=result) verbose_proxy_logger.info( - f"Successfully updated agent '{existing_agent.get('agent_name')}' (ID: {agent_id}) in memory" + "Successfully updated agent '%s' (ID: %s) in memory", existing_agent.get("agent_name"), agent_id ) return result except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error updating agent: {e}") + verbose_proxy_logger.exception("Error updating agent: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -789,7 +789,7 @@ async def delete_agent( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error deleting agent: {e}") + verbose_proxy_logger.exception("Error deleting agent: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -884,7 +884,7 @@ async def make_agent_public( await proxy_config.save_config(new_config=config) verbose_proxy_logger.debug( - f"Updated public agent groups to: {litellm.public_agent_groups} by user: {user_api_key_dict.user_id}" + "Updated public agent groups to: %s by user: %s", litellm.public_agent_groups, user_api_key_dict.user_id ) return { @@ -895,7 +895,7 @@ async def make_agent_public( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error making agent public: {e}") + verbose_proxy_logger.exception("Error making agent public: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -988,7 +988,7 @@ async def make_agents_public( await proxy_config.save_config(new_config=config) verbose_proxy_logger.debug( - f"Updated public agent groups to: {litellm.public_agent_groups} by user: {user_api_key_dict.user_id}" + "Updated public agent groups to: %s by user: %s", litellm.public_agent_groups, user_api_key_dict.user_id ) return { @@ -999,7 +999,7 @@ async def make_agents_public( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error making agent public: {e}") + verbose_proxy_logger.exception("Error making agent public: %s", e) raise HTTPException(status_code=500, detail=str(e)) diff --git a/litellm/proxy/agent_endpoints/model_list_helpers.py b/litellm/proxy/agent_endpoints/model_list_helpers.py index 56053f59c85..fc70ca75ae6 100644 --- a/litellm/proxy/agent_endpoints/model_list_helpers.py +++ b/litellm/proxy/agent_endpoints/model_list_helpers.py @@ -40,7 +40,7 @@ async def append_agents_to_model_group( ) ) except Exception as e: - verbose_proxy_logger.debug(f"Error appending agents to model_group/info: {e}") + verbose_proxy_logger.debug("Error appending agents to model_group/info: %s", e) return model_groups @@ -84,6 +84,6 @@ async def append_agents_to_model_info( } ) except Exception as e: - verbose_proxy_logger.debug(f"Error appending agents to v2/model/info: {e}") + verbose_proxy_logger.debug("Error appending agents to v2/model/info: %s", e) return models diff --git a/litellm/proxy/anthropic_endpoints/claude_code_endpoints/claude_code_marketplace.py b/litellm/proxy/anthropic_endpoints/claude_code_endpoints/claude_code_marketplace.py index bf797b92850..a6c45cf736d 100644 --- a/litellm/proxy/anthropic_endpoints/claude_code_endpoints/claude_code_marketplace.py +++ b/litellm/proxy/anthropic_endpoints/claude_code_endpoints/claude_code_marketplace.py @@ -79,12 +79,12 @@ async def get_marketplace(): try: manifest = json.loads(plugin.manifest_json) except json.JSONDecodeError: - verbose_proxy_logger.warning(f"Plugin {plugin.name} has invalid manifest JSON, skipping") + verbose_proxy_logger.warning("Plugin %s has invalid manifest JSON, skipping", plugin.name) continue # Source must be specified for URL-based marketplaces if "source" not in manifest: - verbose_proxy_logger.warning(f"Plugin {plugin.name} has no source field, skipping") + verbose_proxy_logger.warning("Plugin %s has no source field, skipping", plugin.name) continue entry: dict[str, Any] = { @@ -118,7 +118,7 @@ async def get_marketplace(): except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error generating marketplace: {e}") + verbose_proxy_logger.exception("Error generating marketplace: %s", e) raise HTTPException( status_code=500, detail={"error": f"Failed to generate marketplace: {e}"}, @@ -283,7 +283,7 @@ async def register_plugin( ) action = "created" - verbose_proxy_logger.info(f"Plugin {request.name} {action} successfully") + verbose_proxy_logger.info("Plugin %s %s successfully", request.name, action) return { "status": "success", @@ -301,7 +301,7 @@ async def register_plugin( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error registering plugin: {e}") + verbose_proxy_logger.exception("Error registering plugin: %s", e) raise HTTPException( status_code=500, detail={"error": f"Registration failed: {e}"}, @@ -368,7 +368,7 @@ async def list_plugins( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error listing plugins: {e}") + verbose_proxy_logger.exception("Error listing plugins: %s", e) raise HTTPException( status_code=500, detail={"error": str(e)}, @@ -425,7 +425,7 @@ async def get_plugin( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error getting plugin: {e}") + verbose_proxy_logger.exception("Error getting plugin: %s", e) raise HTTPException( status_code=500, detail={"error": str(e)}, @@ -462,13 +462,13 @@ async def enable_plugin( data={"enabled": True, "updated_at": datetime.now(timezone.utc)}, ) - verbose_proxy_logger.info(f"Plugin {plugin_name} enabled") + verbose_proxy_logger.info("Plugin %s enabled", plugin_name) return {"status": "success", "message": f"Plugin '{plugin_name}' enabled"} except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error enabling plugin: {e}") + verbose_proxy_logger.exception("Error enabling plugin: %s", e) raise HTTPException( status_code=500, detail={"error": str(e)}, @@ -505,13 +505,13 @@ async def disable_plugin( data={"enabled": False, "updated_at": datetime.now(timezone.utc)}, ) - verbose_proxy_logger.info(f"Plugin {plugin_name} disabled") + verbose_proxy_logger.info("Plugin %s disabled", plugin_name) return {"status": "success", "message": f"Plugin '{plugin_name}' disabled"} except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error disabling plugin: {e}") + verbose_proxy_logger.exception("Error disabling plugin: %s", e) raise HTTPException( status_code=500, detail={"error": str(e)}, @@ -545,13 +545,13 @@ async def delete_plugin( await ClaudeCodePluginRepository(prisma_client).table.delete(where={"name": plugin_name}) - verbose_proxy_logger.info(f"Plugin {plugin_name} deleted") + verbose_proxy_logger.info("Plugin %s deleted", plugin_name) return {"status": "success", "message": f"Plugin '{plugin_name}' deleted"} except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error deleting plugin: {e}") + verbose_proxy_logger.exception("Error deleting plugin: %s", e) raise HTTPException( status_code=500, detail={"error": str(e)}, diff --git a/litellm/proxy/anthropic_endpoints/endpoints.py b/litellm/proxy/anthropic_endpoints/endpoints.py index 5535928dfac..397ee64d399 100644 --- a/litellm/proxy/anthropic_endpoints/endpoints.py +++ b/litellm/proxy/anthropic_endpoints/endpoints.py @@ -189,7 +189,7 @@ async def anthropic_response( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.anthropic_response(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.anthropic_response(): Exception occured - %s", e) # Extract model_id from request metadata (same as success path) litellm_metadata = data.get("litellm_metadata", {}) or {} @@ -301,7 +301,7 @@ async def count_tokens( detail=detail, ) except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.anthropic_endpoints.count_tokens(): Exception occurred - {e}") + verbose_proxy_logger.exception("litellm.proxy.anthropic_endpoints.count_tokens(): Exception occurred - %s", e) raise HTTPException(status_code=500, detail={"error": f"Internal server error: {e}"}) diff --git a/litellm/proxy/auth/auth_checks.py b/litellm/proxy/auth/auth_checks.py index 6b1d845ec95..c186bbc15ee 100644 --- a/litellm/proxy/auth/auth_checks.py +++ b/litellm/proxy/auth/auth_checks.py @@ -136,8 +136,10 @@ def _log_budget_lookup_failure(entity: str, error: Exception) -> None: if any(x in err_str for x in ("column", "schema", "does not exist", "prisma", "migrate")): hint = " Run `prisma db push` or `prisma migrate deploy` to fix schema mismatches." verbose_proxy_logger.error( - f"Budget lookup failed for {entity}; cache will not be populated. " - f"Each request will hit the database. Error: {error}.{hint}" + "Budget lookup failed for %s; cache will not be populated. Each request will hit the database. Error: %s.%s", + entity, + error, + hint, ) @@ -192,7 +194,7 @@ def _is_model_cost_zero(model: str | list[str] | None, llm_router: Router | None if model_group_info is None: # Model not found or no pricing info available # Conservative approach: assume it has cost - verbose_proxy_logger.debug(f"No model group info found for {model_name}, assuming it has cost") + verbose_proxy_logger.debug("No model group info found for %s, assuming it has cost", model_name) if zero_cost_cache is not None: zero_cost_cache[model_name] = False return False @@ -205,7 +207,10 @@ def _is_model_cost_zero(model: str | list[str] | None, llm_router: Router | None # If costs are not explicitly configured (None), assume it has cost if input_cost is None or output_cost is None: verbose_proxy_logger.debug( - f"Model {model_name} has undefined cost (input: {input_cost}, output: {output_cost}), assuming it has cost" + "Model %s has undefined cost (input: %s, output: %s), assuming it has cost", + model_name, + input_cost, + output_cost, ) if zero_cost_cache is not None: zero_cost_cache[model_name] = False @@ -214,7 +219,7 @@ def _is_model_cost_zero(model: str | list[str] | None, llm_router: Router | None # If either cost is non-zero, return False if input_cost > 0 or output_cost > 0: verbose_proxy_logger.debug( - f"Model {model_name} has non-zero cost (input: {input_cost}, output: {output_cost})" + "Model %s has non-zero cost (input: %s, output: %s)", model_name, input_cost, output_cost ) if zero_cost_cache is not None: zero_cost_cache[model_name] = False @@ -246,7 +251,7 @@ def _is_model_cost_zero(model: str | list[str] | None, llm_router: Router | None except Exception as e: # If we can't determine the cost, assume it has cost (conservative approach) - verbose_proxy_logger.debug(f"Error checking cost for model {model_name}: {e}, assuming it has cost") + verbose_proxy_logger.debug("Error checking cost for model %s: %s, assuming it has cost", model_name, e) return False # All models checked have zero cost @@ -957,7 +962,7 @@ async def get_default_end_user_budget( if budget_record is None: verbose_proxy_logger.warning( - f"Default end user budget not found in database: {litellm.max_end_user_budget_id}" + "Default end user budget not found in database: %s", litellm.max_end_user_budget_id ) return None @@ -973,7 +978,7 @@ async def get_default_end_user_budget( return _budget_obj except Exception as e: - verbose_proxy_logger.error(f"Error fetching default end user budget: {e}") + verbose_proxy_logger.error("Error fetching default end user budget: %s", e) return None @@ -1013,7 +1018,7 @@ async def get_team_member_default_budget( budget_record = await BudgetRepository(prisma_client).table.find_unique(where={"budget_id": budget_id}) if budget_record is None: - verbose_proxy_logger.warning(f"Team-default member budget not found in database: {budget_id}") + verbose_proxy_logger.warning("Team-default member budget not found in database: %s", budget_id) return None await user_api_key_cache.async_set_cache( @@ -1025,7 +1030,7 @@ async def get_team_member_default_budget( return LiteLLM_BudgetTable.model_validate(budget_record.dict()) except Exception: - verbose_proxy_logger.exception(f"Error fetching team-default member budget {budget_id}") + verbose_proxy_logger.exception("Error fetching team-default member budget %s", budget_id) return None @@ -1066,7 +1071,7 @@ async def _apply_default_budget_to_end_user( # Apply default budget to end user object end_user_obj.litellm_budget_table = default_budget verbose_proxy_logger.debug( - f"Applied default budget {litellm.max_end_user_budget_id} to end user {end_user_obj.user_id}" + "Applied default budget %s to end user %s", litellm.max_end_user_budget_id, end_user_obj.user_id ) return end_user_obj @@ -1289,7 +1294,7 @@ async def _end_user_id_exists_in_db( if end_user_obj is not None: return True except Exception as e: - verbose_proxy_logger.debug(f"end_user validation: get_end_user_object lookup failed: {e}") + verbose_proxy_logger.debug("end_user validation: get_end_user_object lookup failed: %s", e) try: user_obj = await get_user_object( @@ -1305,7 +1310,7 @@ async def _end_user_id_exists_in_db( if user_obj is not None: return True except Exception as e: - verbose_proxy_logger.debug(f"end_user validation: get_user_object lookup failed: {e}") + verbose_proxy_logger.debug("end_user validation: get_user_object lookup failed: %s", e) return False @@ -1376,7 +1381,7 @@ async def get_tag_objects_batch( ) tag_objects[tag_name] = _tag_obj except Exception as e: - verbose_proxy_logger.debug(f"Error batch fetching tags from database: {e}") + verbose_proxy_logger.debug("Error batch fetching tags from database: %s", e) return tag_objects @@ -1974,7 +1979,10 @@ async def _get_team_object_from_user_api_key_cache( ) except Exception as e: verbose_proxy_logger.debug( - f"Failed to load object_permission for team {team_id} with object_permission_id={_response.object_permission_id}: {e}" + "Failed to load object_permission for team %s with object_permission_id=%s: %s", + team_id, + _response.object_permission_id, + e, ) # save the team object to cache @@ -2250,7 +2258,10 @@ async def get_team_object_by_alias( ) except Exception as e: verbose_proxy_logger.debug( - f"Failed to load object_permission for team {team_obj.team_id} with object_permission_id={team_obj.object_permission_id}: {e}" + "Failed to load object_permission for team %s with object_permission_id=%s: %s", + team_obj.team_id, + team_obj.object_permission_id, + e, ) # Cache the result by both alias and team_id @@ -2610,7 +2621,9 @@ async def get_key_object( ) except Exception as e: verbose_proxy_logger.debug( - f"Failed to load object_permission for key with object_permission_id={_response.object_permission_id}: {e}" + "Failed to load object_permission for key with object_permission_id=%s: %s", + _response.object_permission_id, + e, ) # save the key object to cache diff --git a/litellm/proxy/auth/auth_exception_handler.py b/litellm/proxy/auth/auth_exception_handler.py index 681647814e7..b79e01eda21 100644 --- a/litellm/proxy/auth/auth_exception_handler.py +++ b/litellm/proxy/auth/auth_exception_handler.py @@ -95,7 +95,9 @@ class UserAPIKeyAuthExceptionHandler: use_x_forwarded_for=general_settings.get("use_x_forwarded_for", False), ) verbose_proxy_logger.exception( - f"litellm.proxy.proxy_server.user_api_key_auth(): Exception occured - {e}\nRequester IP Address:{requester_ip}", + "litellm.proxy.proxy_server.user_api_key_auth(): Exception occured - %s\nRequester IP Address:%s", + e, + requester_ip, extra={"requester_ip": requester_ip}, ) diff --git a/litellm/proxy/auth/auth_utils.py b/litellm/proxy/auth/auth_utils.py index a03ed13180c..df4f4caa78f 100644 --- a/litellm/proxy/auth/auth_utils.py +++ b/litellm/proxy/auth/auth_utils.py @@ -529,10 +529,11 @@ async def pre_db_read_auth_checks( _allowed_routes = general_settings["allowed_routes"] if premium_user is not True: verbose_proxy_logger.error( - f"Trying to set allowed_routes. This is an Enterprise feature. {CommonProxyErrors.not_premium_user.value}" + "Trying to set allowed_routes. This is an Enterprise feature. %s", + CommonProxyErrors.not_premium_user.value, ) if route not in _allowed_routes: - verbose_proxy_logger.error(f"Route {route} not in allowed_routes={_allowed_routes}") + verbose_proxy_logger.error("Route %s not in allowed_routes=%s", route, _allowed_routes) raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=f"Access forbidden: Route {route} not allowed", @@ -582,7 +583,7 @@ def route_in_additonal_public_routes(current_route: str): return False except Exception as e: - verbose_proxy_logger.error(f"route_in_additonal_public_routes: {e}") + verbose_proxy_logger.error("route_in_additonal_public_routes: %s", e) return False @@ -619,7 +620,7 @@ def get_request_route(request: Request) -> str: return raw_path except Exception as e: verbose_proxy_logger.debug( - f"error on get_request_route: {e}, defaulting to request.url.path={request.url.path}" + "error on get_request_route: %s, defaulting to request.url.path=%s", e, request.url.path ) return str(request.url.path) @@ -639,7 +640,7 @@ def get_request_route_template(request: Request) -> str | None: template = getattr(route, "path", None) return template if isinstance(template, str) and template else None except Exception as e: - verbose_proxy_logger.debug(f"error on get_request_route_template: {e}") + verbose_proxy_logger.debug("error on get_request_route_template: %s", e) return None @@ -781,7 +782,8 @@ async def check_if_request_size_is_safe(request: Request) -> bool: # Check if premium user if premium_user is not True: verbose_proxy_logger.warning( - f"using max_request_size_mb - not checking - this is an enterprise only feature. {CommonProxyErrors.not_premium_user.value}" + "using max_request_size_mb - not checking - this is an enterprise only feature. %s", + CommonProxyErrors.not_premium_user.value, ) return True @@ -791,7 +793,7 @@ async def check_if_request_size_is_safe(request: Request) -> bool: if content_length: header_size = int(content_length) header_size_mb = bytes_to_mb(bytes_value=header_size) - verbose_proxy_logger.debug(f"content_length request size in MB={header_size_mb}") + verbose_proxy_logger.debug("content_length request size in MB=%s", header_size_mb) if header_size_mb > max_request_size_mb: raise ProxyException( @@ -806,7 +808,7 @@ async def check_if_request_size_is_safe(request: Request) -> bool: body_size = len(body) request_size_mb = bytes_to_mb(bytes_value=body_size) - verbose_proxy_logger.debug(f"request body request size in MB={request_size_mb}") + verbose_proxy_logger.debug("request body request size in MB=%s", request_size_mb) if request_size_mb > max_request_size_mb: raise ProxyException( message=f"Request size is too large. Request size is {request_size_mb} MB. Max size is {max_request_size_mb} MB", @@ -841,12 +843,13 @@ async def check_response_size_is_safe(response: Any) -> bool: # Check if premium user if premium_user is not True: verbose_proxy_logger.warning( - f"using max_response_size_mb - not checking - this is an enterprise only feature. {CommonProxyErrors.not_premium_user.value}" + "using max_response_size_mb - not checking - this is an enterprise only feature. %s", + CommonProxyErrors.not_premium_user.value, ) return True response_size_mb = bytes_to_mb(bytes_value=sys.getsizeof(response)) - verbose_proxy_logger.debug(f"response size in MB={response_size_mb}") + verbose_proxy_logger.debug("response size in MB=%s", response_size_mb) if response_size_mb > max_response_size_mb: raise ProxyException( message=f"Response size is too large. Response size is {response_size_mb} MB. Max size is {max_response_size_mb} MB", diff --git a/litellm/proxy/auth/handle_jwt.py b/litellm/proxy/auth/handle_jwt.py index cf4b47e3180..cb860f5df4e 100644 --- a/litellm/proxy/auth/handle_jwt.py +++ b/litellm/proxy/auth/handle_jwt.py @@ -379,8 +379,10 @@ class JWTHandler: if not team_id: return default_value verbose_proxy_logger.debug( - f"JWT Auth: team_id_jwt_field '{self.litellm_jwtauth.team_id_jwt_field}' " - f"returned a list {team_id}; using first element '{team_id[0]}' automatically." + "JWT Auth: team_id_jwt_field '%s' returned a list %s; using first element '%s' automatically.", + self.litellm_jwtauth.team_id_jwt_field, + team_id, + team_id[0], ) team_id = team_id[0] return team_id # type: ignore[return-value] @@ -614,7 +616,7 @@ class JWTHandler: if cached_jwks_uri is not None: return cached_jwks_uri - verbose_proxy_logger.debug(f"JWT Auth: Fetching OIDC discovery document from {url}") + verbose_proxy_logger.debug("JWT Auth: Fetching OIDC discovery document from %s", url) response = await self.http_handler.get(url) if response.status_code != 200: raise Exception( @@ -629,7 +631,7 @@ class JWTHandler: if not jwks_uri: raise Exception(f"JWT Auth: OIDC discovery document at {url} does not contain a 'jwks_uri' field.") - verbose_proxy_logger.debug(f"JWT Auth: Resolved OIDC discovery {url} -> jwks_uri={jwks_uri}") + verbose_proxy_logger.debug("JWT Auth: Resolved OIDC discovery %s -> jwks_uri=%s", url, jwks_uri) await self.user_api_key_cache.async_set_cache( key=cache_key, value=jwks_uri, @@ -655,7 +657,7 @@ class JWTHandler: try: response_json = response.json() except Exception as e: - verbose_proxy_logger.error(f"Error parsing response: {e}. Original Response: {response.text}") + verbose_proxy_logger.error("Error parsing response: %s. Original Response: %s", e, response.text) raise Exception(f"Error parsing response: {e}. Check server logs for original response.") if "keys" in response_json: @@ -749,7 +751,7 @@ class JWTHandler: verbose_proxy_logger.debug("Returning cached OIDC UserInfo") return cached_userinfo - verbose_proxy_logger.debug(f"Calling OIDC UserInfo endpoint: {self.litellm_jwtauth.oidc_userinfo_endpoint}") + verbose_proxy_logger.debug("Calling OIDC UserInfo endpoint: %s", self.litellm_jwtauth.oidc_userinfo_endpoint) try: # Call the UserInfo endpoint with the access token @@ -765,7 +767,7 @@ class JWTHandler: raise Exception(f"OIDC UserInfo endpoint returned status {response.status_code}: {response.text}") userinfo = response.json() - verbose_proxy_logger.debug(f"Received OIDC UserInfo: {userinfo}") + verbose_proxy_logger.debug("Received OIDC UserInfo: %s", userinfo) # Cache the userinfo response await self.user_api_key_cache.async_set_cache( @@ -777,7 +779,7 @@ class JWTHandler: return userinfo except Exception as e: - verbose_proxy_logger.error(f"Error fetching OIDC UserInfo: {e}") + verbose_proxy_logger.error("Error fetching OIDC UserInfo: %s", e) raise Exception(f"Failed to fetch OIDC UserInfo: {e}") _unscoped_jwt_warning_emitted = False @@ -1239,7 +1241,7 @@ class JWTAuthManager: return None, None if team_alias: - verbose_proxy_logger.info(f"JWT Auth: Resolving team by alias: '{team_alias}'") + verbose_proxy_logger.info("JWT Auth: Resolving team by alias: '%s'", team_alias) team_object = await get_team_object_by_alias( team_alias=team_alias, prisma_client=prisma_client, @@ -1250,7 +1252,7 @@ class JWTAuthManager: if team_object: individual_team_id = team_object.team_id verbose_proxy_logger.info( - f"JWT Auth: Resolved team_alias='{team_alias}' to team_id='{individual_team_id}'" + "JWT Auth: Resolved team_alias='%s' to team_id='%s'", team_alias, individual_team_id ) return individual_team_id, team_object @@ -1391,7 +1393,7 @@ class JWTAuthManager: is_allowed = False denied_auth_enforced_pass_through_route = True verbose_proxy_logger.debug( - f"JWT team route check: team_id={team_id}, route={route}, is_allowed={is_allowed}" + "JWT team route check: team_id=%s, route=%s, is_allowed=%s", team_id, route, is_allowed ) if is_allowed: return team_id, team_object @@ -1482,7 +1484,7 @@ class JWTAuthManager: else None ) elif org_alias: - verbose_proxy_logger.info(f"JWT Auth: Resolving org by alias: '{org_alias}'") + verbose_proxy_logger.info("JWT Auth: Resolving org by alias: '%s'", org_alias) org_object = await get_org_object_by_alias( org_alias=org_alias, prisma_client=prisma_client, @@ -1492,7 +1494,7 @@ class JWTAuthManager: ) if org_object: verbose_proxy_logger.info( - f"JWT Auth: Resolved org_alias='{org_alias}' to org_id='{org_object.organization_id}'" + "JWT Auth: Resolved org_alias='%s' to org_id='%s'", org_alias, org_object.organization_id ) # Check if email domain is allowed before attempting to get/create user @@ -1625,7 +1627,7 @@ class JWTAuthManager: detail=f"Team '{header_team_id}' from x-litellm-team-id header is not in your JWT's allowed teams. Allowed teams: {list(allowed_team_ids)}", ) - verbose_proxy_logger.debug(f"Using team_id from x-litellm-team-id header: {header_team_id}") + verbose_proxy_logger.debug("Using team_id from x-litellm-team-id header: %s", header_team_id) return header_team_id @staticmethod @@ -1666,11 +1668,13 @@ class JWTAuthManager: user_role=LitellmUserRoles.PROXY_ADMIN ), # [TODO]: expose an internal service role, for better tracking ) - verbose_proxy_logger.debug(f"Successfully added user {user_object.user_id} to team {team_object.team_id}") + verbose_proxy_logger.debug( + "Successfully added user %s to team %s", user_object.user_id, team_object.team_id + ) except ProxyException as e: if e.type == ProxyErrorTypes.team_member_already_in_team: verbose_proxy_logger.debug( - f"User {user_object.user_id} is already a member of team {team_object.team_id}" + "User %s is already a member of team %s", user_object.user_id, team_object.team_id ) return else: diff --git a/litellm/proxy/auth/litellm_license.py b/litellm/proxy/auth/litellm_license.py index 1f61ef7ea28..357ea284103 100644 --- a/litellm/proxy/auth/litellm_license.py +++ b/litellm/proxy/auth/litellm_license.py @@ -26,7 +26,7 @@ class LicenseCheck: def __init__(self) -> None: self.license_str = os.getenv("LITELLM_LICENSE", None) - verbose_proxy_logger.debug(f"License Str value - {self.license_str}") + verbose_proxy_logger.debug("License Str value - %s", self.license_str) self.http_handler = HTTPHandler(timeout=NON_LLM_CONNECTION_TIMEOUT) self._premium_check_logged = False self.public_key = None @@ -48,11 +48,13 @@ class LicenseCheck: else: self.public_key = None except Exception as e: - verbose_proxy_logger.error(f"Error reading public key: {e}") + verbose_proxy_logger.error("Error reading public key: %s", e) def _verify(self, license_str: str) -> bool: verbose_proxy_logger.debug( - f"litellm.proxy.auth.litellm_license.py::_verify - Checking license against {self.base_url}/verify_license - {license_str}" + "litellm.proxy.auth.litellm_license.py::_verify - Checking license against %s/verify_license - %s", + self.base_url, + license_str, ) url = f"{self.base_url}/verify_license/{license_str}" @@ -79,12 +81,14 @@ class LicenseCheck: assert isinstance(premium, bool) verbose_proxy_logger.debug( - f"litellm.proxy.auth.litellm_license.py::_verify - License={license_str} is premium={premium}" + "litellm.proxy.auth.litellm_license.py::_verify - License=%s is premium=%s", license_str, premium ) return premium except Exception as e: verbose_proxy_logger.exception( - f"litellm.proxy.auth.litellm_license.py::_verify - Unable to verify License={license_str} via api. - {e}" + "litellm.proxy.auth.litellm_license.py::_verify - Unable to verify License=%s via api. - %s", + license_str, + e, ) return False @@ -96,7 +100,8 @@ class LicenseCheck: try: if not self._premium_check_logged: verbose_proxy_logger.debug( - f"litellm.proxy.auth.litellm_license.py::is_premium() - ENTERING 'IS_PREMIUM' - LiteLLM License={self.license_str}" + "litellm.proxy.auth.litellm_license.py::is_premium() - ENTERING 'IS_PREMIUM' - LiteLLM License=%s", + self.license_str, ) if self.license_str is None: @@ -104,7 +109,8 @@ class LicenseCheck: if not self._premium_check_logged: verbose_proxy_logger.debug( - f"litellm.proxy.auth.litellm_license.py::is_premium() - Updated 'self.license_str' - {self.license_str}" + "litellm.proxy.auth.litellm_license.py::is_premium() - Updated 'self.license_str' - %s", + self.license_str, ) self._premium_check_logged = True @@ -187,6 +193,7 @@ class LicenseCheck: except Exception as e: verbose_proxy_logger.debug( - f"litellm.proxy.auth.litellm_license.py::verify_license_without_api_request - Unable to verify License locally. - {e}" + "litellm.proxy.auth.litellm_license.py::verify_license_without_api_request - Unable to verify License locally. - %s", + e, ) return False diff --git a/litellm/proxy/auth/model_checks.py b/litellm/proxy/auth/model_checks.py index 24875dae9ab..fa0abe71081 100644 --- a/litellm/proxy/auth/model_checks.py +++ b/litellm/proxy/auth/model_checks.py @@ -132,7 +132,7 @@ def get_key_models( # deduplicate while preserving order all_models = list(dict.fromkeys(all_models)) - verbose_proxy_logger.debug(f"ALL KEY MODELS - {len(all_models)}") + verbose_proxy_logger.debug("ALL KEY MODELS - %s", len(all_models)) return all_models @@ -173,7 +173,7 @@ def get_team_models( # deduplicate while preserving order all_models = list(dict.fromkeys(all_models)) - verbose_proxy_logger.debug(f"ALL TEAM MODELS - {len(all_models)}") + verbose_proxy_logger.debug("ALL TEAM MODELS - %s", len(all_models)) return all_models @@ -448,7 +448,7 @@ def get_all_fallbacks( elif fallback_type == "content_policy": fallbacks_config = getattr(llm_router, "content_policy_fallbacks", []) else: - verbose_proxy_logger.warning(f"Unknown fallback_type: {fallback_type}") + verbose_proxy_logger.warning("Unknown fallback_type: %s", fallback_type) return [] if not fallbacks_config: @@ -463,5 +463,5 @@ def get_all_fallbacks( return fallback_model_group except Exception as e: - verbose_proxy_logger.error(f"Error getting fallbacks for model {model}: {e}") + verbose_proxy_logger.error("Error getting fallbacks for model %s: %s", model, e) return [] diff --git a/litellm/proxy/auth/oauth2_proxy_hook.py b/litellm/proxy/auth/oauth2_proxy_hook.py index a7e34072712..9c0bf11a851 100644 --- a/litellm/proxy/auth/oauth2_proxy_hook.py +++ b/litellm/proxy/auth/oauth2_proxy_hook.py @@ -65,7 +65,7 @@ async def handle_oauth2_proxy_request(request: Request) -> UserAPIKeyAuth: ) oauth2_config_mappings: dict[str, str] = general_settings.get("oauth2_config_mappings") or {} - verbose_proxy_logger.debug(f"Oauth2 config mappings: {oauth2_config_mappings}") + verbose_proxy_logger.debug("Oauth2 config mappings: %s", oauth2_config_mappings) if not oauth2_config_mappings: raise ValueError("Oauth2 config mappings not found in general_settings") diff --git a/litellm/proxy/auth/resolvers/store.py b/litellm/proxy/auth/resolvers/store.py index 0702f47fa99..e15a5668701 100644 --- a/litellm/proxy/auth/resolvers/store.py +++ b/litellm/proxy/auth/resolvers/store.py @@ -132,7 +132,9 @@ class IdentityStore: ) except Exception as e: verbose_proxy_logger.debug( - f"Failed to load object_permission for key with object_permission_id={key.object_permission_id}: {e}" + "Failed to load object_permission for key with object_permission_id=%s: %s", + key.object_permission_id, + e, ) await _cache_key_object( diff --git a/litellm/proxy/auth/route_checks.py b/litellm/proxy/auth/route_checks.py index 1e63d9746a4..6c485504a0f 100644 --- a/litellm/proxy/auth/route_checks.py +++ b/litellm/proxy/auth/route_checks.py @@ -258,7 +258,7 @@ class RouteChecks: # check if user can access this route query_params = request.query_params user_id = query_params.get("user_id") - verbose_proxy_logger.debug(f"user_id: {user_id} & valid_token.user_id: {valid_token.user_id}") + verbose_proxy_logger.debug("user_id: %s & valid_token.user_id: %s", user_id, valid_token.user_id) if user_id and user_id != valid_token.user_id: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, @@ -326,7 +326,8 @@ class RouteChecks: if "admin_only_routes" in general_settings: if premium_user is not True: verbose_proxy_logger.error( - f"Trying to use 'admin_only_routes' this is an Enterprise only feature. {CommonProxyErrors.not_premium_user.value}" + "Trying to use 'admin_only_routes' this is an Enterprise only feature. %s", + CommonProxyErrors.not_premium_user.value, ) return if route in general_settings["admin_only_routes"]: diff --git a/litellm/proxy/auth/user_api_key_auth.py b/litellm/proxy/auth/user_api_key_auth.py index 286837c8909..b295a25ab9f 100644 --- a/litellm/proxy/auth/user_api_key_auth.py +++ b/litellm/proxy/auth/user_api_key_auth.py @@ -102,7 +102,7 @@ try: enterprise_custom_auth: Callable | None = _enterprise_custom_auth except ImportError as e: - verbose_proxy_logger.debug(f"Error in enterprise custom auth: {e}") + verbose_proxy_logger.debug("Error in enterprise custom auth: %s", e) enterprise_custom_auth = None user_api_key_service_logger_obj = ServiceLogging() # used for tracking latency on OTEL @@ -406,7 +406,7 @@ def _apply_budget_limits_to_end_user_params( if budget_info.model_max_budget is not None: end_user_params["end_user_model_max_budget"] = budget_info.model_max_budget - verbose_proxy_logger.debug(f"Applied budget limits to end user {end_user_id}") + verbose_proxy_logger.debug("Applied budget limits to end user %s", end_user_id) async def user_api_key_auth_websocket(websocket: WebSocket): @@ -865,7 +865,9 @@ async def _resolve_jwt_to_virtual_key( ) if claim_value is None: - verbose_proxy_logger.debug(f"JWT Key Mapping: Claim field '{virtual_key_claim_field}' not found in JWT claims.") + verbose_proxy_logger.debug( + "JWT Key Mapping: Claim field '%s' not found in JWT claims.", virtual_key_claim_field + ) # A missing claim is an unmapped client — apply the no-match policy # rather than returning early. Otherwise a caller can bypass REJECT # simply by presenting a JWT that omits the configured field. For @@ -1248,7 +1250,7 @@ async def _user_api_key_auth_builder( user_email=mapped_user_email, ) except Exception as e: - verbose_proxy_logger.debug(f"JWT mapped-key user_email backfill skipped: {e}") + verbose_proxy_logger.debug("JWT mapped-key user_email backfill skipped: %s", e) else: if mapped_user_obj is not None: valid_token.user_email = mapped_user_obj.user_email @@ -1390,7 +1392,7 @@ async def _user_api_key_auth_builder( skip_budget_checks = _is_model_cost_zero(model=model, llm_router=llm_router) if skip_budget_checks: - verbose_proxy_logger.info(f"Skipping all budget checks for zero-cost model: {model}") + verbose_proxy_logger.info("Skipping all budget checks for zero-cost model: %s", model) # Fetch project object for JWT path if project_id is set _jwt_project_obj = None @@ -1501,7 +1503,7 @@ async def _user_api_key_auth_builder( except Exception as e: if isinstance(e, litellm.BudgetExceededError): raise e - verbose_proxy_logger.debug(f"Unable to find user in db. Error - {e}") + verbose_proxy_logger.debug("Unable to find user in db. Error - %s", e) ### CHECK IF ADMIN ### # note: never string compare api keys, this is vulenerable to a time attack. Use secrets.compare_digest instead @@ -1749,7 +1751,8 @@ async def _user_api_key_auth_builder( ) except Exception as e: verbose_logger.debug( - f"litellm.proxy.auth.user_api_key_auth.py::user_api_key_auth() - Unable to get user from db/cache. Setting user_obj to None. Exception received - {e}" + "litellm.proxy.auth.user_api_key_auth.py::user_api_key_auth() - Unable to get user from db/cache. Setting user_obj to None. Exception received - %s", + e, ) user_obj = None @@ -1775,7 +1778,7 @@ async def _user_api_key_auth_builder( skip_budget_checks = _is_model_cost_zero(model=model, llm_router=llm_router) if skip_budget_checks: - verbose_proxy_logger.info(f"Skipping all budget checks for zero-cost model: {model}") + verbose_proxy_logger.info("Skipping all budget checks for zero-cost model: %s", model) # Check 3. Check if user is in their team budget if not skip_budget_checks and valid_token.team_member_spend is not None: @@ -1839,7 +1842,7 @@ async def _user_api_key_auth_builder( if expiry_time.tzinfo is None or expiry_time.tzinfo.utcoffset(expiry_time) is None: expiry_time = expiry_time.replace(tzinfo=timezone.utc) verbose_proxy_logger.debug( - f"Checking if token expired, expiry time {expiry_time} and current time {current_time}" + "Checking if token expired, expiry time %s and current time %s", expiry_time, current_time ) if expiry_time < current_time: # Token exists but is expired. @@ -2689,11 +2692,13 @@ def get_api_key_from_custom_header(request: Request, custom_litellm_key_header_n if custom_api_key: api_key = _get_bearer_token(api_key=custom_api_key) verbose_proxy_logger.debug( - f"Found custom API key using header: {custom_litellm_key_header_name}, setting api_key={abbreviate_api_key(api_key)}" + "Found custom API key using header: %s, setting api_key=%s", + custom_litellm_key_header_name, + abbreviate_api_key(api_key), ) else: verbose_proxy_logger.exception( - f"No LiteLLM Virtual Key pass. Please set header={custom_litellm_key_header_name}: Bearer " + "No LiteLLM Virtual Key pass. Please set header=%s: Bearer ", custom_litellm_key_header_name ) return api_key @@ -2774,7 +2779,7 @@ async def _lookup_end_user_and_apply_budget( except Exception as e: if isinstance(e, litellm.BudgetExceededError): raise e - verbose_proxy_logger.debug(f"Unable to find user in db. Error - {e}") + verbose_proxy_logger.debug("Unable to find user in db. Error - %s", e) return valid_token, end_user_object @@ -2796,7 +2801,7 @@ async def _enforce_key_and_fallback_model_access( if config != {}: model_list = config.get("model_list", []) new_model_list = model_list - verbose_proxy_logger.debug(f"\n new llm router model list {new_model_list}") + verbose_proxy_logger.debug("\n new llm router model list %s", new_model_list) elif isinstance(valid_token.models, list) and "all-team-models" in valid_token.models: pass else: diff --git a/litellm/proxy/batches_endpoints/endpoints.py b/litellm/proxy/batches_endpoints/endpoints.py index 0c2764db33f..0d815d370e7 100644 --- a/litellm/proxy/batches_endpoints/endpoints.py +++ b/litellm/proxy/batches_endpoints/endpoints.py @@ -120,7 +120,8 @@ async def create_batch( try: data = await _read_request_body(request=request) verbose_proxy_logger.debug( - f"Request received by LiteLLM:\n{json.dumps(data, indent=4)}", + "Request received by LiteLLM:\n%s", + json.dumps(data, indent=4), ) base_llm_response_processor = ProxyBaseLLMRequestProcessing(data=data) ( @@ -225,8 +226,10 @@ async def create_batch( ) verbose_proxy_logger.debug( - f"Created batch using model: {model_from_file_id}, " - f"original_batch_id: {original_batch_id}, encoded: {encoded_batch_id}" + "Created batch using model: %s, original_batch_id: %s, encoded: %s", + model_from_file_id, + original_batch_id, + encoded_batch_id, ) response.input_file_id = input_file_id @@ -293,7 +296,7 @@ async def create_batch( encode_batch_response_ids(response, model=model_param) - verbose_proxy_logger.debug(f"Created batch using model: {model_param}") + verbose_proxy_logger.debug("Created batch using model: %s", model_param) else: # SCENARIO 3: Fallback to custom_llm_provider (uses env variables) apply_team_provider_credentials( @@ -340,7 +343,7 @@ async def create_batch( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.create_batch(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.create_batch(): Exception occured - %s", e) raise handle_exception_on_proxy(e) @@ -471,7 +474,7 @@ async def retrieve_batch( # If batch is still processing, sync with provider to get latest state if response is not None: verbose_proxy_logger.debug( - f"Batch {batch_id} is in non-terminal state {response.status}, syncing with provider" + "Batch %s is in non-terminal state %s, syncing with provider", batch_id, response.status ) # Retrieve from provider (for non-terminal states or if DB lookup failed) @@ -505,7 +508,7 @@ async def retrieve_batch( encode_batch_response_ids(response, model=model_from_id) verbose_proxy_logger.debug( - f"Retrieved batch using model: {model_from_id}, original_id: {original_batch_id}" + "Retrieved batch using model: %s, original_id: %s", model_from_id, original_batch_id ) elif litellm.enable_loadbalancing_on_batch_endpoints is True or unified_batch_id: @@ -592,7 +595,7 @@ async def retrieve_batch( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.retrieve_batch(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.retrieve_batch(): Exception occured - %s", e) raise handle_exception_on_proxy(e) @@ -641,7 +644,7 @@ async def list_batches( version, ) - verbose_proxy_logger.debug(f"GET /v1/batches after={after} limit={limit}") + verbose_proxy_logger.debug("GET /v1/batches after=%s limit=%s", after, limit) try: if llm_router is None: raise HTTPException( @@ -703,7 +706,7 @@ async def list_batches( for batch in response_data: encode_batch_response_ids(batch, model=model_param) - verbose_proxy_logger.debug(f"Listed batches using model: {model_param}") + verbose_proxy_logger.debug("Listed batches using model: %s", model_param) # SCENARIO 2 (alternative): target_model_names based routing elif target_model_names or data.get("target_model_names", None): @@ -773,7 +776,7 @@ async def list_batches( original_exception=e, request_data={"after": after, "limit": limit}, ) - verbose_proxy_logger.error(f"litellm.proxy.proxy_server.retrieve_batch(): Exception occured - {e}") + verbose_proxy_logger.error("litellm.proxy.proxy_server.retrieve_batch(): Exception occured - %s", e) raise handle_exception_on_proxy(e) @@ -886,7 +889,7 @@ async def cancel_batch( encode_batch_response_ids(response, model=model_from_id) verbose_proxy_logger.debug( - f"Cancelled batch using model: {model_from_id}, original_id: {original_batch_id}" + "Cancelled batch using model: %s, original_id: %s", model_from_id, original_batch_id ) # SCENARIO 2: target_model_names based routing @@ -982,7 +985,7 @@ async def cancel_batch( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.create_batch(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.create_batch(): Exception occured - %s", e) raise handle_exception_on_proxy(e) diff --git a/litellm/proxy/caching_routes.py b/litellm/proxy/caching_routes.py index 50b2f63e18a..d823fa2d532 100644 --- a/litellm/proxy/caching_routes.py +++ b/litellm/proxy/caching_routes.py @@ -43,7 +43,7 @@ def _extract_cache_params() -> dict[str, Any]: cleaned_params = HealthCheckCacheParams(**cache_params).model_dump() if cache_params else {} return masker.mask_dict(cleaned_params) except (AttributeError, TypeError) as e: - verbose_proxy_logger.debug(f"Error extracting cache params: {e}") + verbose_proxy_logger.debug("Error extracting cache params: %s", e) return {} @@ -173,7 +173,7 @@ def _get_redis_client_info(cache_instance) -> tuple[list, int]: client_list = cache_instance.client_list() return client_list, len(client_list) except Exception as e: - verbose_proxy_logger.warning(f"CLIENT LIST command failed (likely restricted on managed Redis): {e}") + verbose_proxy_logger.warning("CLIENT LIST command failed (likely restricted on managed Redis): %s", e) return ["CLIENT LIST command not available on this Redis instance"], -1 diff --git a/litellm/proxy/client/cli/interface.py b/litellm/proxy/client/cli/interface.py index 9f42c3b06bb..ea20cbb5ea4 100644 --- a/litellm/proxy/client/cli/interface.py +++ b/litellm/proxy/client/cli/interface.py @@ -20,7 +20,7 @@ def styled_prompt(): click.echo("\n" * 3) except Exception as e: # Fallback if we can't get terminal size - verbose_logger.debug(f"Error getting terminal size: {e}") + verbose_logger.debug("Error getting terminal size: %s", e) click.echo("\n" * 3) # ASCII box drawing characters diff --git a/litellm/proxy/common_request_processing.py b/litellm/proxy/common_request_processing.py index bc3bcd233f0..f9cad283166 100644 --- a/litellm/proxy/common_request_processing.py +++ b/litellm/proxy/common_request_processing.py @@ -439,7 +439,7 @@ async def _parse_event_data_for_error(event_line: str | bytes) -> int | None: error_code = int(error_code_raw) except ValueError: verbose_proxy_logger.warning( - f"Error code is a string but not a valid integer: {error_code_raw}" + "Error code is a string but not a valid integer: %s", error_code_raw ) # Not a valid integer string, treat as if no valid code was found for this check @@ -447,7 +447,7 @@ async def _parse_event_data_for_error(event_line: str | bytes) -> int | None: if error_code is not None and 100 <= error_code <= 599: return error_code elif error_code_raw is not None: # Log if original code was present but not valid - verbose_proxy_logger.warning(f"Error has invalid or non-convertible code: {error_code_raw}") + verbose_proxy_logger.warning("Error has invalid or non-convertible code: %s", error_code_raw) except (orjson.JSONDecodeError, json.JSONDecodeError): # not a known error chunk pass @@ -644,7 +644,8 @@ async def create_response( # Should return standard JSON error response instead of SSE format final_status_code = error_code_from_chunk verbose_proxy_logger.debug( - f"Error detected in first stream chunk. Returning JSON error response with status code: {final_status_code}" + "Error detected in first stream chunk. Returning JSON error response with status code: %s", + final_status_code, ) # Parse error content @@ -663,7 +664,7 @@ async def create_response( headers=headers, ) except Exception as e: - verbose_proxy_logger.debug(f"Error parsing first chunk value: {e}") + verbose_proxy_logger.debug("Error parsing first chunk value: %s", e) except _ClientDisconnectedBeforeFirstChunk: # Client vanished during the time-to-first-token wait; the upstream @@ -694,7 +695,7 @@ async def create_response( ) except Exception as e: # Unexpected error consuming first chunk. - verbose_proxy_logger.exception(f"Error consuming first chunk from generator: {e}") + verbose_proxy_logger.exception("Error consuming first chunk from generator: %s", e) # Preserve status code from HTTPException (e.g., guardrail blocks) error_status = getattr(e, "status_code", status.HTTP_500_INTERNAL_SERVER_ERROR) @@ -943,7 +944,7 @@ def _log_llm_api_exception(e: Exception) -> None: "litellm.proxy.proxy_server._handle_llm_api_exception(): client disconnected, upstream LLM request cancelled" ) return - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server._handle_llm_api_exception(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server._handle_llm_api_exception(): Exception occured - %s", e) async def _cancel_llm_call_on_client_disconnect( @@ -1083,7 +1084,7 @@ class ProxyBaseLLMRequestProcessing: try: return {key: str(value) for key, value in headers.items() if value not in exclude_values} except Exception as e: - verbose_proxy_logger.error(f"Error setting custom headers: {e}") + verbose_proxy_logger.error("Error setting custom headers: %s", e) return {} @staticmethod @@ -2945,7 +2946,7 @@ class ProxyBaseLLMRequestProcessing: raise except Exception as e: verbose_proxy_logger.exception( - f"litellm.proxy.proxy_server.async_data_generator(): Exception occured - {e}" + "litellm.proxy.proxy_server.async_data_generator(): Exception occured - %s", e ) transformed_exception = await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, @@ -2955,7 +2956,8 @@ class ProxyBaseLLMRequestProcessing: if transformed_exception is not None: e = transformed_exception verbose_proxy_logger.debug( - f"\033[1;31mAn error occurred: {e}\n\n Debug this by setting `--debug`, e.g. `litellm --model gpt-3.5-turbo --debug`" + "\x1b[1;31mAn error occurred: %s\n\n Debug this by setting `--debug`, e.g. `litellm --model gpt-3.5-turbo --debug`", + e, ) if isinstance(e, HTTPException): diff --git a/litellm/proxy/common_utils/callback_utils.py b/litellm/proxy/common_utils/callback_utils.py index 1eca0eb768c..6325a27b7d1 100644 --- a/litellm/proxy/common_utils/callback_utils.py +++ b/litellm/proxy/common_utils/callback_utils.py @@ -61,7 +61,7 @@ def initialize_callbacks_on_proxy( ) from litellm.proxy.proxy_server import prisma_client - verbose_proxy_logger.debug(f"{blue_color_code}initializing callbacks={value} on proxy{reset_color_code}") + verbose_proxy_logger.debug("%sinitializing callbacks=%s on proxy%s", blue_color_code, value, reset_color_code) if isinstance(value, list): imported_list: list[Any] = [] for callback in value: # ["presidio", ] @@ -298,7 +298,7 @@ def initialize_callbacks_on_proxy( imported_list.append(callback) else: verbose_proxy_logger.debug( - f"{blue_color_code} attempting to import custom calback={callback} {reset_color_code}" + "%s attempting to import custom calback=%s %s", blue_color_code, callback, reset_color_code ) imported_list.append( get_instance_fn( @@ -322,7 +322,7 @@ def initialize_callbacks_on_proxy( config_file_path=config_file_path, ) ] - verbose_proxy_logger.debug(f"{blue_color_code} Initialized Callbacks - {litellm.callbacks} {reset_color_code}") + verbose_proxy_logger.debug("%s Initialized Callbacks - %s %s", blue_color_code, litellm.callbacks, reset_color_code) def get_model_group_from_litellm_kwargs(kwargs: dict) -> str | None: diff --git a/litellm/proxy/common_utils/custom_openapi_spec.py b/litellm/proxy/common_utils/custom_openapi_spec.py index a884eab462a..de4f9ceaa63 100644 --- a/litellm/proxy/common_utils/custom_openapi_spec.py +++ b/litellm/proxy/common_utils/custom_openapi_spec.py @@ -49,7 +49,7 @@ class CustomOpenAPISpec: except Exception as e: # FastAPI 0.120+ may fail schema generation for certain types (e.g., openai.Timeout) # Log the error and return None to skip schema generation for this model - verbose_proxy_logger.debug(f"Failed to generate schema for {model_class}: {e}") + verbose_proxy_logger.debug("Failed to generate schema for %s: %s", model_class, e) return None @staticmethod @@ -267,13 +267,13 @@ class CustomOpenAPISpec: openapi_schema, paths, f"#/components/schemas/{schema_name}" ) - verbose_proxy_logger.debug(f"Successfully added {schema_name} schema to OpenAPI spec") + verbose_proxy_logger.debug("Successfully added %s schema to OpenAPI spec", schema_name) else: - verbose_proxy_logger.debug(f"Could not get schema for {schema_name}") + verbose_proxy_logger.debug("Could not get schema for %s", schema_name) except Exception as e: # If schema addition fails, continue without it - verbose_proxy_logger.debug(f"Failed to add {operation_name} request schema: {e}") + verbose_proxy_logger.debug("Failed to add %s request schema: %s", operation_name, e) return openapi_schema @@ -302,7 +302,7 @@ class CustomOpenAPISpec: operation_name="chat completion", ) except ImportError as e: - verbose_proxy_logger.debug(f"Failed to import ProxyChatCompletionRequest: {e}") + verbose_proxy_logger.debug("Failed to import ProxyChatCompletionRequest: %s", e) return openapi_schema @staticmethod @@ -328,7 +328,7 @@ class CustomOpenAPISpec: operation_name="embedding", ) except ImportError as e: - verbose_proxy_logger.debug(f"Failed to import EmbeddingRequest: {e}") + verbose_proxy_logger.debug("Failed to import EmbeddingRequest: %s", e) return openapi_schema @staticmethod @@ -356,7 +356,7 @@ class CustomOpenAPISpec: operation_name="responses API", ) except ImportError as e: - verbose_proxy_logger.debug(f"Failed to import ResponsesAPIRequestParams: {e}") + verbose_proxy_logger.debug("Failed to import ResponsesAPIRequestParams: %s", e) return openapi_schema @staticmethod diff --git a/litellm/proxy/common_utils/debug_utils.py b/litellm/proxy/common_utils/debug_utils.py index 7d2b303a7ca..7cbf8d4527e 100644 --- a/litellm/proxy/common_utils/debug_utils.py +++ b/litellm/proxy/common_utils/debug_utils.py @@ -29,18 +29,21 @@ def configure_gc_thresholds(): thresholds = [int(x.strip()) for x in gc_threshold_env.split(",")] if len(thresholds) == 3: gc.set_threshold(*thresholds) - verbose_proxy_logger.info(f"GC thresholds set to: {thresholds}") + verbose_proxy_logger.info("GC thresholds set to: %s", thresholds) else: verbose_proxy_logger.warning( - f"GC threshold not set: {gc_threshold_env}. Expected format: 'gen0,gen1,gen2'" + "GC threshold not set: %s. Expected format: 'gen0,gen1,gen2'", gc_threshold_env ) except ValueError as e: - verbose_proxy_logger.warning(f"Failed to parse GC threshold: {gc_threshold_env}. Error: {e}") + verbose_proxy_logger.warning("Failed to parse GC threshold: %s. Error: %s", gc_threshold_env, e) # Log current thresholds current_thresholds = gc.get_threshold() verbose_proxy_logger.info( - f"Current GC thresholds: gen0={current_thresholds[0]}, gen1={current_thresholds[1]}, gen2={current_thresholds[2]}" + "Current GC thresholds: gen0=%s, gen1=%s, gen2=%s", + current_thresholds[0], + current_thresholds[1], + current_thresholds[2], ) @@ -425,12 +428,12 @@ def _get_cache_memory_stats(user_api_key_cache, llm_router, proxy_logging_obj, r ), } except Exception as e: - verbose_proxy_logger.debug(f"Error getting Redis pool info: {e}") + verbose_proxy_logger.debug("Error getting Redis pool info: %s", e) else: cache_stats["redis_usage_cache"] = {"enabled": False} except Exception as e: - verbose_proxy_logger.debug(f"Error calculating cache stats: {e}") + verbose_proxy_logger.debug("Error calculating cache stats: %s", e) cache_stats["error"] = str(e) return cache_stats @@ -496,7 +499,7 @@ def _get_router_memory_stats(llm_router) -> dict[str, Any]: else: litellm_router_memory = {"note": "Router not initialized"} except Exception as e: - verbose_proxy_logger.debug(f"Error getting router memory info: {e}") + verbose_proxy_logger.debug("Error getting router memory info: %s", e) litellm_router_memory = {"error": str(e)} return litellm_router_memory @@ -546,7 +549,7 @@ def _get_process_memory_info(worker_pid: int, include_process_info: bool) -> dic "error": "psutil not installed. Install with: pip install psutil", } except Exception as e: - verbose_proxy_logger.debug(f"Error getting process info: {e}") + verbose_proxy_logger.debug("Error getting process info: %s", e) return {"pid": worker_pid, "error": str(e)} @@ -649,10 +652,10 @@ async def configure_gc_thresholds_endpoint( try: gc.set_threshold(generation_0, generation_1, generation_2) verbose_proxy_logger.info( - f"GC thresholds updated from {old_thresholds} to ({generation_0}, {generation_1}, {generation_2})" + "GC thresholds updated from %s to (%s, %s, %s)", old_thresholds, generation_0, generation_1, generation_2 ) except Exception as e: - verbose_proxy_logger.error(f"Failed to set GC thresholds: {e}") + verbose_proxy_logger.error("Failed to set GC thresholds: %s", e) raise HTTPException(status_code=500, detail=f"Failed to set GC thresholds: {e}") # Get current object count to show immediate impact @@ -783,4 +786,4 @@ def init_verbose_loggers(): except Exception as e: import logging - logging.warning(f"Failed to init verbose loggers: {e}") + logging.warning("Failed to init verbose loggers: %s", e) diff --git a/litellm/proxy/common_utils/encrypt_decrypt_utils.py b/litellm/proxy/common_utils/encrypt_decrypt_utils.py index 651e59ef959..e288de6ec44 100644 --- a/litellm/proxy/common_utils/encrypt_decrypt_utils.py +++ b/litellm/proxy/common_utils/encrypt_decrypt_utils.py @@ -108,7 +108,7 @@ def encrypt_value_helper(value: str, new_encryption_key: str | None = None): return encrypted_value verbose_proxy_logger.debug( - f"Invalid value type passed to encrypt_value: {type(value)} for Value: {value}\n Value must be a string" + "Invalid value type passed to encrypt_value: %s for Value: %s\n Value must be a string", type(value), value ) # if it's not a string - do not encrypt it and return the value return value @@ -150,7 +150,7 @@ def decrypt_value_helper( verbose_proxy_logger.debug(error_message) return value if return_original_value else None - verbose_proxy_logger.debug(f"Unable to decrypt value for key: {key}, returning None") + verbose_proxy_logger.debug("Unable to decrypt value for key: %s, returning None", key) if return_original_value: return value else: diff --git a/litellm/proxy/common_utils/expired_ui_session_key_cleanup_manager.py b/litellm/proxy/common_utils/expired_ui_session_key_cleanup_manager.py index a8acc28d9de..cabd1ca84ef 100644 --- a/litellm/proxy/common_utils/expired_ui_session_key_cleanup_manager.py +++ b/litellm/proxy/common_utils/expired_ui_session_key_cleanup_manager.py @@ -101,7 +101,7 @@ class ExpiredUISessionKeyCleanupManager: e, ) return 0 - verbose_proxy_logger.error(f"Expired UI session key cleanup failed: {e}") + verbose_proxy_logger.error("Expired UI session key cleanup failed: %s", e) return 0 finally: if lock_acquired and self.pod_lock_manager and self.pod_lock_manager.redis_cache: diff --git a/litellm/proxy/common_utils/get_routes.py b/litellm/proxy/common_utils/get_routes.py index 4e3c908a8bb..4f320889fe6 100644 --- a/litellm/proxy/common_utils/get_routes.py +++ b/litellm/proxy/common_utils/get_routes.py @@ -70,5 +70,5 @@ class GetRoutes: else: return None except Exception: - verbose_logger.exception(f"Error getting endpoint name for route: {endpoint_function}") + verbose_logger.exception("Error getting endpoint name for route: %s", endpoint_function) return None diff --git a/litellm/proxy/common_utils/http_parsing_utils.py b/litellm/proxy/common_utils/http_parsing_utils.py index 67212539cc4..f8cfb14326d 100644 --- a/litellm/proxy/common_utils/http_parsing_utils.py +++ b/litellm/proxy/common_utils/http_parsing_utils.py @@ -72,7 +72,7 @@ async def _read_request_body(request: Request | None) -> dict: # a later raw-body re-read sees the original payload — # banned-param checks must see the same body the handler # acts on. - verbose_proxy_logger.error(f"Invalid form payload: {e}") + verbose_proxy_logger.error("Invalid form payload: %s", e) raise ProxyException( message=f"Invalid form payload: {e}", type="invalid_request_error", @@ -98,7 +98,7 @@ async def _read_request_body(request: Request | None) -> dict: # Above the configured size, skip the repair and raise the 400 now. repair_limit_bytes = MAX_REQUEST_BODY_SIZE_TO_REPAIR_MB * 1024 * 1024 if repair_limit_bytes > 0 and len(body) > repair_limit_bytes: - verbose_proxy_logger.error(f"Invalid JSON payload received: {e}") + verbose_proxy_logger.error("Invalid JSON payload received: %s", e) raise ProxyException( message=f"Invalid JSON payload: {e}", type="invalid_request_error", @@ -120,7 +120,7 @@ async def _read_request_body(request: Request | None) -> dict: parsed_body = json.loads(body_str) except json.JSONDecodeError: # If both orjson and json.loads fail, throw a proper error - verbose_proxy_logger.error(f"Invalid JSON payload received: {e}") + verbose_proxy_logger.error("Invalid JSON payload received: %s", e) raise ProxyException( message=f"Invalid JSON payload: {e}", type="invalid_request_error", @@ -134,11 +134,11 @@ async def _read_request_body(request: Request | None) -> dict: except (json.JSONDecodeError, orjson.JSONDecodeError, ProxyException) as e: # Re-raise ProxyException as-is - verbose_proxy_logger.error(f"Invalid JSON payload received: {e}") + verbose_proxy_logger.error("Invalid JSON payload received: %s", e) raise except Exception as e: # Catch unexpected errors to avoid crashes - verbose_proxy_logger.exception(f"Unexpected error reading request body - {e}") + verbose_proxy_logger.exception("Unexpected error reading request body - %s", e) return {} @@ -159,7 +159,7 @@ def _safe_get_request_query_params(request: Request | None) -> dict: return dict(request.query_params) return {} except Exception as e: - verbose_proxy_logger.debug(f"Unexpected error reading request query params - {e}") + verbose_proxy_logger.debug("Unexpected error reading request query params - %s", e) return {} @@ -172,7 +172,7 @@ def _safe_set_request_parsed_body( return request.scope["parsed_body"] = (tuple(parsed_body.keys()), parsed_body) except Exception as e: - verbose_proxy_logger.debug(f"Unexpected error setting request parsed body - {e}") + verbose_proxy_logger.debug("Unexpected error setting request parsed body - %s", e) def _safe_get_request_headers(request: Request | None) -> dict: @@ -190,11 +190,11 @@ def _safe_get_request_headers(request: Request | None) -> dict: if isinstance(cached, dict): return cached if cached is not None: - verbose_proxy_logger.debug(f"Unexpected cached request headers type - {type(cached)}") + verbose_proxy_logger.debug("Unexpected cached request headers type - %s", type(cached)) try: headers = dict(request.headers) except Exception as e: - verbose_proxy_logger.debug(f"Unexpected error reading request headers - {e}") + verbose_proxy_logger.debug("Unexpected error reading request headers - %s", e) headers = {} try: if state is not None: @@ -393,7 +393,7 @@ def extract_nested_form_metadata(form_data: dict[str, Any], prefix: str = "litel # Skip UploadFile objects - they should not be in metadata if isinstance(value, UploadFile): - verbose_proxy_logger.warning(f"Skipping UploadFile in metadata extraction for key: {key}") + verbose_proxy_logger.warning("Skipping UploadFile in metadata extraction for key: %s", key) continue # Extract the nested path from bracket notation @@ -406,7 +406,7 @@ def extract_nested_form_metadata(form_data: dict[str, Any], prefix: str = "litel parts = path_string.split("][") if not parts or not parts[0]: - verbose_proxy_logger.warning(f"Invalid metadata key format (empty path): {key}") + verbose_proxy_logger.warning("Invalid metadata key format (empty path): %s", key) continue # Navigate/create nested dictionary structure @@ -414,7 +414,7 @@ def extract_nested_form_metadata(form_data: dict[str, Any], prefix: str = "litel for part in parts[:-1]: if not isinstance(current, dict): verbose_proxy_logger.warning( - f"Cannot create nested path - intermediate value is not a dict at: {part}" + "Cannot create nested path - intermediate value is not a dict at: %s", part ) break current = current.setdefault(part, {}) @@ -423,10 +423,10 @@ def extract_nested_form_metadata(form_data: dict[str, Any], prefix: str = "litel if isinstance(current, dict): current[parts[-1]] = value else: - verbose_proxy_logger.warning(f"Cannot set value - parent is not a dict for key: {key}") + verbose_proxy_logger.warning("Cannot set value - parent is not a dict for key: %s", key) except Exception as e: - verbose_proxy_logger.error(f"Error parsing metadata key '{key}': {e}") + verbose_proxy_logger.error("Error parsing metadata key '%s': %s", key, e) continue return metadata @@ -505,7 +505,8 @@ def populate_request_with_path_params(request_data: dict, request: Request) -> d continue request_data.setdefault(key, value) verbose_proxy_logger.debug( - f"populate_request_with_path_params: Found path_params, vector_store_ids={request_data.get('vector_store_ids')}" + "populate_request_with_path_params: Found path_params, vector_store_ids=%s", + request_data.get("vector_store_ids"), ) return request_data @@ -533,7 +534,7 @@ def _add_vector_store_id_from_path(request_data: dict, request: Request) -> None if vector_store_match: vector_store_id = vector_store_match.group(1) verbose_proxy_logger.debug( - f"populate_request_with_path_params: Extracted vector_store_id={vector_store_id} from path={path}" + "populate_request_with_path_params: Extracted vector_store_id=%s from path=%s", vector_store_id, path ) request_data.setdefault("vector_store_id", vector_store_id) existing_ids = request_data.get("vector_store_ids") @@ -543,7 +544,8 @@ def _add_vector_store_id_from_path(request_data: dict, request: Request) -> None else: request_data["vector_store_ids"] = [vector_store_id] verbose_proxy_logger.debug( - f"populate_request_with_path_params: Updated request_data with vector_store_ids={request_data.get('vector_store_ids')}" + "populate_request_with_path_params: Updated request_data with vector_store_ids=%s", + request_data.get("vector_store_ids"), ) else: - verbose_proxy_logger.debug(f"populate_request_with_path_params: No vector_store_id present in path={path}") + verbose_proxy_logger.debug("populate_request_with_path_params: No vector_store_id present in path=%s", path) diff --git a/litellm/proxy/common_utils/key_rotation_manager.py b/litellm/proxy/common_utils/key_rotation_manager.py index 8e065a06979..a7e8f7aeb13 100644 --- a/litellm/proxy/common_utils/key_rotation_manager.py +++ b/litellm/proxy/common_utils/key_rotation_manager.py @@ -84,20 +84,20 @@ class KeyRotationManager: verbose_proxy_logger.debug("No keys are due for rotation at this time") return - verbose_proxy_logger.info(f"Found {len(keys_to_rotate)} keys due for rotation") + verbose_proxy_logger.info("Found %s keys due for rotation", len(keys_to_rotate)) # Rotate each key for key in keys_to_rotate: try: await self._rotate_key(key) key_identifier = key.key_name or (key.token[:8] + "..." if key.token else "unknown") - verbose_proxy_logger.info(f"Successfully rotated key: {key_identifier}") + verbose_proxy_logger.info("Successfully rotated key: %s", key_identifier) except Exception as e: key_identifier = key.key_name or (key.token[:8] + "..." if key.token else "unknown") - verbose_proxy_logger.error(f"Failed to rotate key {key_identifier}: {e}") + verbose_proxy_logger.error("Failed to rotate key %s: %s", key_identifier, e) except Exception as e: - verbose_proxy_logger.error(f"Key rotation process failed: {e}") + verbose_proxy_logger.error("Key rotation process failed: %s", e) finally: # Only release the lock if it was actually acquired if lock_acquired and self.pod_lock_manager and self.pod_lock_manager.redis_cache: diff --git a/litellm/proxy/common_utils/load_config_utils.py b/litellm/proxy/common_utils/load_config_utils.py index 56aedb76590..67b3baaf626 100644 --- a/litellm/proxy/common_utils/load_config_utils.py +++ b/litellm/proxy/common_utils/load_config_utils.py @@ -20,9 +20,9 @@ def get_file_contents_from_s3(bucket_name, object_key): aws_secret_access_key=credentials.secret_key, aws_session_token=credentials.token, # Optional, if using temporary credentials ) - verbose_proxy_logger.debug(f"Retrieving {object_key} from S3 bucket: {bucket_name}") + verbose_proxy_logger.debug("Retrieving %s from S3 bucket: %s", object_key, bucket_name) response = s3_client.get_object(Bucket=bucket_name, Key=object_key) - verbose_proxy_logger.debug(f"Response: {response}") + verbose_proxy_logger.debug("Response: %s", response) # Read the file contents and directly parse YAML file_contents = response["Body"].read().decode("utf-8") @@ -34,9 +34,9 @@ def get_file_contents_from_s3(bucket_name, object_key): except ImportError as e: # this is most likely if a user is not using the litellm docker container - verbose_proxy_logger.error(f"ImportError: {e}") + verbose_proxy_logger.error("ImportError: %s", e) except Exception as e: - verbose_proxy_logger.error(f"Error retrieving file contents: {e}") + verbose_proxy_logger.error("Error retrieving file contents: %s", e) return None @@ -57,7 +57,7 @@ async def get_config_file_contents_from_gcs(bucket_name, object_key): return config except Exception as e: - verbose_proxy_logger.error(f"Error retrieving file contents: {e}") + verbose_proxy_logger.error("Error retrieving file contents: %s", e) return None @@ -93,12 +93,12 @@ def download_python_file_from_s3( aws_session_token=credentials.token, ) - verbose_proxy_logger.debug(f"Downloading Python file {object_key} from S3 bucket: {bucket_name}") + verbose_proxy_logger.debug("Downloading Python file %s from S3 bucket: %s", object_key, bucket_name) response = s3_client.get_object(Bucket=bucket_name, Key=object_key) # Read the file contents file_contents = response["Body"].read().decode("utf-8") - verbose_proxy_logger.debug(f"File contents: {file_contents}") + verbose_proxy_logger.debug("File contents: %s", file_contents) # Ensure directory exists os.makedirs(os.path.dirname(local_file_path), exist_ok=True) @@ -107,14 +107,14 @@ def download_python_file_from_s3( with open(local_file_path, "w") as f: f.write(file_contents) - verbose_proxy_logger.debug(f"Python file downloaded successfully to {local_file_path}") + verbose_proxy_logger.debug("Python file downloaded successfully to %s", local_file_path) return True except ImportError as e: - verbose_proxy_logger.error(f"ImportError: {e}") + verbose_proxy_logger.error("ImportError: %s", e) return False except Exception as e: - verbose_proxy_logger.exception(f"Error downloading Python file: {e}") + verbose_proxy_logger.exception("Error downloading Python file: %s", e) return False @@ -154,11 +154,11 @@ async def download_python_file_from_gcs( with open(local_file_path, "w") as f: f.write(file_contents) - verbose_proxy_logger.debug(f"Python file downloaded successfully to {local_file_path}") + verbose_proxy_logger.debug("Python file downloaded successfully to %s", local_file_path) return True except Exception as e: - verbose_proxy_logger.exception(f"Error downloading Python file from GCS: {e}") + verbose_proxy_logger.exception("Error downloading Python file from GCS: %s", e) return False diff --git a/litellm/proxy/common_utils/openapi_schema_compat.py b/litellm/proxy/common_utils/openapi_schema_compat.py index 06a18524733..919a9fa3939 100644 --- a/litellm/proxy/common_utils/openapi_schema_compat.py +++ b/litellm/proxy/common_utils/openapi_schema_compat.py @@ -80,7 +80,7 @@ def get_openapi_schema_with_compat( except (ImportError, AttributeError) as e: # If patching fails, try normal generation with error handling - verbose_proxy_logger.debug(f"Could not patch Pydantic schema generation: {e}. Trying normal generation.") + verbose_proxy_logger.debug("Could not patch Pydantic schema generation: %s. Trying normal generation.", e) try: return get_openapi_func( title=title, @@ -97,7 +97,7 @@ def get_openapi_schema_with_compat( ): # If we still get the error, log it and return minimal schema verbose_proxy_logger.warning( - f"PydanticSchemaGenerationError during schema generation: {pydantic_error}" + "PydanticSchemaGenerationError during schema generation: %s", pydantic_error ) return { "openapi": "3.0.0", diff --git a/litellm/proxy/common_utils/performance_utils.py b/litellm/proxy/common_utils/performance_utils.py index 50de40480fd..09ef61b7116 100644 --- a/litellm/proxy/common_utils/performance_utils.py +++ b/litellm/proxy/common_utils/performance_utils.py @@ -55,7 +55,7 @@ def _start_profiling(profile_sampling_rate: float) -> None: if _profiler is None: _profiler = cProfile.Profile() _profiler.enable() - verbose_proxy_logger.info(f"Profiling started with sampling rate: {profile_sampling_rate}") + verbose_proxy_logger.info("Profiling started with sampling rate: %s", profile_sampling_rate) def _start_profiling_for_request(profile_sampling_rate: float) -> bool: @@ -77,9 +77,9 @@ def _save_stats(profile_file: PathLib) -> None: _profiler.dump_stats(str(profile_file)) # Re-enable profiler to continue profiling _profiler.enable() - verbose_proxy_logger.debug(f"Profiling stats saved to {profile_file}") + verbose_proxy_logger.debug("Profiling stats saved to %s", profile_file) except Exception as e: - verbose_proxy_logger.error(f"Error saving profiling stats: {e}") + verbose_proxy_logger.error("Error saving profiling stats: %s", e) # Make sure profiler is re-enabled even if there's an error try: _profiler.enable() @@ -178,7 +178,7 @@ def wrap_function_with_line_profiler(module: Any, function_name: str) -> bool: try: original_function = getattr(module, function_name, None) if original_function is None: - verbose_proxy_logger.warning(f"Function {function_name} not found in module {module.__name__}") + verbose_proxy_logger.warning("Function %s not found in module %s", function_name, module.__name__) return False # Store original function if not already wrapped @@ -189,10 +189,10 @@ def wrap_function_with_line_profiler(module: Any, function_name: str) -> bool: profiled_function = _line_profiler(original_function) setattr(module, function_name, profiled_function) - verbose_proxy_logger.info(f"Wrapped {module.__name__}.{function_name} with line_profiler") + verbose_proxy_logger.info("Wrapped %s.%s with line_profiler", module.__name__, function_name) return True except Exception as e: - verbose_proxy_logger.error(f"Error wrapping {function_name} with line_profiler: {e}") + verbose_proxy_logger.error("Error wrapping %s with line_profiler: %s", function_name, e) return False @@ -226,7 +226,7 @@ def wrap_function_directly(func: Callable) -> Callable: _line_profiler.add_function(func) profiled_function = _line_profiler(func) - verbose_proxy_logger.info(f"Wrapped function {func.__name__} with line_profiler") + verbose_proxy_logger.info("Wrapped function %s with line_profiler", func.__name__) return profiled_function @@ -251,7 +251,7 @@ def collect_line_profiler_stats(output_file: str | None = None) -> None: # Save to file output_path = PathLib(output_file) _line_profiler.dump_stats(str(output_path)) - verbose_proxy_logger.info(f"Line profiler stats saved to {output_path}") + verbose_proxy_logger.info("Line profiler stats saved to %s", output_path) else: # Print to stdout from io import StringIO @@ -261,7 +261,7 @@ def collect_line_profiler_stats(output_file: str | None = None) -> None: stats_output = stream.getvalue() verbose_proxy_logger.info("Line profiler stats:\n" + stats_output) except Exception as e: - verbose_proxy_logger.error(f"Error collecting line profiler stats: {e}") + verbose_proxy_logger.error("Error collecting line profiler stats: %s", e) def register_shutdown_handler(output_file: str | None = None) -> None: @@ -282,4 +282,4 @@ def register_shutdown_handler(output_file: str | None = None) -> None: collect_line_profiler_stats(output_file=output_file) atexit.register(shutdown_handler) - verbose_proxy_logger.debug(f"Registered line_profiler shutdown handler for {output_file}") + verbose_proxy_logger.debug("Registered line_profiler shutdown handler for %s", output_file) diff --git a/litellm/proxy/custom_prompt_management.py b/litellm/proxy/custom_prompt_management.py index 355edb69897..ff95e58a3b4 100644 --- a/litellm/proxy/custom_prompt_management.py +++ b/litellm/proxy/custom_prompt_management.py @@ -27,7 +27,10 @@ class X42PromptManagement(CustomPromptManagement): - non_default_params: dict - update with any optional params (e.g. temperature, max_tokens, etc.) to use (can be pulled from prompt management tool) """ verbose_logger.debug( - f"in async get chat completion prompt. Prompt ID: {prompt_id}, Prompt Variables: {prompt_variables}, Dynamic Callback Params: {dynamic_callback_params}" + "in async get chat completion prompt. Prompt ID: %s, Prompt Variables: %s, Dynamic Callback Params: %s", + prompt_id, + prompt_variables, + dynamic_callback_params, ) return model, messages, non_default_params diff --git a/litellm/proxy/db/check_migration.py b/litellm/proxy/db/check_migration.py index 5e53e118e45..62333324c90 100644 --- a/litellm/proxy/db/check_migration.py +++ b/litellm/proxy/db/check_migration.py @@ -97,5 +97,6 @@ def check_prisma_schema_diff(db_url: str | None = None) -> None: has_diff, message = check_prisma_schema_diff_helper(db_url) if has_diff: verbose_logger.exception( - f"🚨🚨🚨 prisma schema out of sync with db. Consider running these sql_commands to sync the two - {message}" + "🚨🚨🚨 prisma schema out of sync with db. Consider running these sql_commands to sync the two - %s", + message, ) diff --git a/litellm/proxy/db/create_views.py b/litellm/proxy/db/create_views.py index 3ced1589757..27d978f5b8c 100644 --- a/litellm/proxy/db/create_views.py +++ b/litellm/proxy/db/create_views.py @@ -238,7 +238,7 @@ async def should_create_missing_views(db: _db) -> bool: result = await db.query_raw(query=sql_query) - verbose_logger.debug(f"Estimated Row count of LiteLLM_SpendLogs = {result}") + verbose_logger.debug("Estimated Row count of LiteLLM_SpendLogs = %s", result) if ( result and isinstance(result, list) diff --git a/litellm/proxy/db/db_spend_update_writer.py b/litellm/proxy/db/db_spend_update_writer.py index 17410698aed..47f5b898610 100644 --- a/litellm/proxy/db/db_spend_update_writer.py +++ b/litellm/proxy/db/db_spend_update_writer.py @@ -141,7 +141,11 @@ class DBSpendUpdateWriter: try: verbose_proxy_logger.debug( - f"Enters prisma db call, response_cost: {response_cost}, token: {token}; user_id: {user_id}; team_id: {team_id}" + "Enters prisma db call, response_cost: %s, token: %s; user_id: %s; team_id: %s", + response_cost, + token, + user_id, + team_id, ) if ProxyUpdateSpend.disable_spend_updates() is True: return @@ -706,7 +710,7 @@ class DBSpendUpdateWriter: if isinstance(request_tags, str): tags = safe_json_loads(request_tags, default=[]) if not tags: - verbose_proxy_logger.debug(f"Failed to parse request_tags JSON: {request_tags}") + verbose_proxy_logger.debug("Failed to parse request_tags JSON: %s", request_tags) return elif isinstance(request_tags, list): tags = request_tags @@ -1098,7 +1102,7 @@ class DBSpendUpdateWriter: ### UPDATE USER TABLE ### user_list_transactions = db_spend_update_transactions["user_list_transactions"] - verbose_proxy_logger.debug(f"User Spend transactions: {user_list_transactions}") + verbose_proxy_logger.debug("User Spend transactions: %s", user_list_transactions) if user_list_transactions is not None and len(user_list_transactions.keys()) > 0: for i in range(n_retry_times + 1): start_time = time.time() @@ -1130,7 +1134,7 @@ class DBSpendUpdateWriter: ### UPDATE END-USER TABLE ### end_user_list_transactions = db_spend_update_transactions["end_user_list_transactions"] - verbose_proxy_logger.debug(f"End-User Spend transactions: {end_user_list_transactions}") + verbose_proxy_logger.debug("End-User Spend transactions: %s", end_user_list_transactions) if end_user_list_transactions is not None and len(end_user_list_transactions.keys()) > 0: await ProxyUpdateSpend.update_end_user_spend( n_retry_times=n_retry_times, @@ -1140,7 +1144,7 @@ class DBSpendUpdateWriter: ) ### UPDATE KEY TABLE ### key_list_transactions = db_spend_update_transactions["key_list_transactions"] - verbose_proxy_logger.debug(f"KEY Spend transactions: {key_list_transactions}") + verbose_proxy_logger.debug("KEY Spend transactions: %s", key_list_transactions) if key_list_transactions is not None and len(key_list_transactions.keys()) > 0: for i in range(n_retry_times + 1): start_time = time.time() @@ -1173,7 +1177,7 @@ class DBSpendUpdateWriter: ### UPDATE TEAM TABLE ### team_list_transactions = db_spend_update_transactions["team_list_transactions"] - verbose_proxy_logger.debug(f"Team Spend transactions: {team_list_transactions}") + verbose_proxy_logger.debug("Team Spend transactions: %s", team_list_transactions) if team_list_transactions is not None and len(team_list_transactions.keys()) > 0: for i in range(n_retry_times + 1): start_time = time.time() @@ -1182,7 +1186,9 @@ class DBSpendUpdateWriter: async with transaction.batch_() as batcher: # Sort by team_id for consistent lock ordering across pods to prevent deadlocks. for team_id, response_cost in sorted(team_list_transactions.items()): - verbose_proxy_logger.debug(f"Updating spend for team id={team_id} by {response_cost}") + verbose_proxy_logger.debug( + "Updating spend for team id=%s by %s", team_id, response_cost + ) batcher.litellm_teamtable.update_many( # 'update_many' prevents error from being raised if no row exists where={"team_id": team_id}, data={"spend": {"increment": response_cost}}, @@ -1204,7 +1210,7 @@ class DBSpendUpdateWriter: ### UPDATE TEAM Membership TABLE with spend ### team_member_list_transactions = db_spend_update_transactions["team_member_list_transactions"] - verbose_proxy_logger.debug(f"Team Membership Spend transactions: {team_member_list_transactions}") + verbose_proxy_logger.debug("Team Membership Spend transactions: %s", team_member_list_transactions) if team_member_list_transactions is not None and len(team_member_list_transactions.keys()) > 0: # Track which team memberships will be updated for cache invalidation team_memberships_to_invalidate: list[tuple[str, str]] = [] @@ -1258,12 +1264,12 @@ class DBSpendUpdateWriter: cache_key = f"team_membership:{user_id}:{team_id}" await user_api_key_cache.async_delete_cache(key=cache_key) verbose_proxy_logger.debug( - f"Invalidated team membership cache for user_id={user_id}, team_id={team_id}" + "Invalidated team membership cache for user_id=%s, team_id=%s", user_id, team_id ) ### UPDATE ORG TABLE ### org_list_transactions = db_spend_update_transactions["org_list_transactions"] - verbose_proxy_logger.debug(f"Org Spend transactions: {org_list_transactions}") + verbose_proxy_logger.debug("Org Spend transactions: %s", org_list_transactions) if org_list_transactions is not None and len(org_list_transactions.keys()) > 0: for i in range(n_retry_times + 1): start_time = time.time() @@ -1346,7 +1352,7 @@ class DBSpendUpdateWriter: """ from litellm.proxy.utils import _raise_failed_update_spend_exception - verbose_proxy_logger.debug(f"{entity_name} Spend transactions: {transactions}") + verbose_proxy_logger.debug("%s Spend transactions: %s", entity_name, transactions) if transactions is not None and len(transactions.keys()) > 0: for i in range(n_retry_times + 1): start_time = time.time() @@ -1356,7 +1362,11 @@ class DBSpendUpdateWriter: # Sort by entity_id for consistent lock ordering across pods to prevent deadlocks. for entity_id, response_cost in sorted(transactions.items()): verbose_proxy_logger.debug( - f"Updating spend for {entity_name} {where_field}={entity_id} by {response_cost}" + "Updating spend for %s %s=%s by %s", + entity_name, + where_field, + entity_id, + response_cost, ) getattr(batcher, table_accessor).update_many( where={where_field: entity_id}, @@ -1485,7 +1495,7 @@ class DBSpendUpdateWriter: from litellm.proxy.utils import _raise_failed_update_spend_exception verbose_proxy_logger.debug( - f"Daily {entity_type.capitalize()} Spend transactions: {len(daily_spend_transactions)}" + "Daily %s Spend transactions: %s", entity_type.capitalize(), len(daily_spend_transactions) ) BATCH_SIZE = 100 start_time = time.time() @@ -1519,7 +1529,7 @@ class DBSpendUpdateWriter: if len(transactions_to_process) == 0: verbose_proxy_logger.debug( - f"No new transactions to process for daily {entity_type} spend update" + "No new transactions to process for daily %s spend update", entity_type ) return @@ -1829,14 +1839,15 @@ class DBSpendUpdateWriter: raise ValueError(f"Invalid type: {type}") if not all(key in payload for key in expected_keys): verbose_proxy_logger.debug( - f"Missing expected keys: {expected_keys}, in payload, skipping from daily_user_spend_transactions" + "Missing expected keys: %s, in payload, skipping from daily_user_spend_transactions", expected_keys ) return None any_expected_keys = ["model", "mcp_namespaced_tool_name"] if not any(key in payload for key in any_expected_keys): verbose_proxy_logger.debug( - f"Missing any expected keys: {any_expected_keys}, in payload, skipping from daily_user_spend_transactions" + "Missing any expected keys: %s, in payload, skipping from daily_user_spend_transactions", + any_expected_keys, ) return None elif "mcp_namespaced_tool_name" in payload: @@ -1848,7 +1859,7 @@ class DBSpendUpdateWriter: return None request_status = prisma_client.get_request_status(payload) - verbose_proxy_logger.debug(f"Logged request status: {request_status}") + verbose_proxy_logger.debug("Logged request status: %s", request_status) _metadata: SpendLogsMetadata = json.loads(payload["metadata"]) usage_obj = _metadata.get("usage_object", {}) or {} if isinstance(payload["startTime"], datetime): @@ -1858,7 +1869,7 @@ class DBSpendUpdateWriter: date = payload["startTime"].split("T")[0] else: verbose_proxy_logger.debug( - f"Invalid start time: {payload['startTime']}, skipping from daily_user_spend_transactions" + "Invalid start time: %s, skipping from daily_user_spend_transactions", payload["startTime"] ) return None try: diff --git a/litellm/proxy/db/db_transaction_queue/pod_lock_manager.py b/litellm/proxy/db/db_transaction_queue/pod_lock_manager.py index 01f6a92485a..604cde4a88c 100644 --- a/litellm/proxy/db/db_transaction_queue/pod_lock_manager.py +++ b/litellm/proxy/db/db_transaction_queue/pod_lock_manager.py @@ -106,7 +106,7 @@ end ) return False except Exception as e: - verbose_proxy_logger.error(f"Error acquiring Redis lock for {cronjob_id}: {e}") + verbose_proxy_logger.error("Error acquiring Redis lock for %s: %s", cronjob_id, e) return False async def release_lock( @@ -148,7 +148,7 @@ end cronjob_id, ) except Exception as e: - verbose_proxy_logger.error(f"Error releasing Redis lock for {cronjob_id}: {e}") + verbose_proxy_logger.error("Error releasing Redis lock for %s: %s", cronjob_id, e) async def _compare_and_delete_lock(self, lock_key: str) -> int: """ diff --git a/litellm/proxy/db/db_transaction_queue/spend_log_cleanup.py b/litellm/proxy/db/db_transaction_queue/spend_log_cleanup.py index d7c70bdb20c..6e5d83bc500 100644 --- a/litellm/proxy/db/db_transaction_queue/spend_log_cleanup.py +++ b/litellm/proxy/db/db_transaction_queue/spend_log_cleanup.py @@ -43,14 +43,14 @@ class SpendLogCleanup: pod_lock_manager = proxy_logging_obj.db_spend_update_writer.pod_lock_manager self.pod_lock_manager = pod_lock_manager - verbose_proxy_logger.info(f"SpendLogCleanup initialized with batch size: {self.batch_size}") + verbose_proxy_logger.info("SpendLogCleanup initialized with batch size: %s", self.batch_size) def _should_delete_spend_logs(self) -> bool: """ Determines if logs should be deleted based on the max retention period in settings. """ retention_setting = self.general_settings.get("maximum_spend_logs_retention_period") - verbose_proxy_logger.info(f"Checking retention setting: {retention_setting}") + verbose_proxy_logger.info("Checking retention setting: %s", retention_setting) if retention_setting is None: verbose_proxy_logger.info("No retention setting found") @@ -59,16 +59,16 @@ class SpendLogCleanup: try: if isinstance(retention_setting, int): verbose_proxy_logger.warning( - f"maximum_spend_logs_retention_period is an integer ({retention_setting}); treating as days. " - "Use a string like '3d' to be explicit." + "maximum_spend_logs_retention_period is an integer (%s); treating as days. Use a string like '3d' to be explicit.", + retention_setting, ) retention_setting = f"{retention_setting}d" self.retention_seconds = duration_in_seconds(retention_setting) - verbose_proxy_logger.info(f"Retention period set to {self.retention_seconds} seconds") + verbose_proxy_logger.info("Retention period set to %s seconds", self.retention_seconds) return True except ValueError as e: verbose_proxy_logger.warning( - f"Invalid maximum_spend_logs_retention_period value: {retention_setting}, error: {e}" + "Invalid maximum_spend_logs_retention_period value: %s, error: %s", retention_setting, e ) return False @@ -145,15 +145,16 @@ class SpendLogCleanup: deleted_count = deleted_result else: verbose_proxy_logger.error( - f"Unexpected execute_raw return type for {table_name} cleanup: {type(deleted_result)}; " - "aborting cleanup to avoid infinite loop" + "Unexpected execute_raw return type for %s cleanup: %s; aborting cleanup to avoid infinite loop", + table_name, + type(deleted_result), ) break - verbose_proxy_logger.info(f"Deleted {deleted_count} {table_name} rows in this batch") + verbose_proxy_logger.info("Deleted %s %s rows in this batch", deleted_count, table_name) if deleted_count == 0: - verbose_proxy_logger.info(f"No more {table_name} rows to delete. Total deleted: {total_deleted}") + verbose_proxy_logger.info("No more %s rows to delete. Total deleted: %s", table_name, total_deleted) break total_deleted += deleted_count @@ -192,7 +193,7 @@ class SpendLogCleanup: """ lock_acquired = False try: - verbose_proxy_logger.info(f"Cleanup job triggered at {datetime.now()}") + verbose_proxy_logger.info("Cleanup job triggered at %s", datetime.now()) if not self._should_delete_spend_logs(): return @@ -210,7 +211,7 @@ class SpendLogCleanup: or False ) verbose_proxy_logger.info( - f"Lock acquisition attempt: {'successful' if lock_acquired else 'failed'} at {datetime.now()}" + "Lock acquisition attempt: %s at %s", "successful" if lock_acquired else "failed", datetime.now() ) if not lock_acquired: @@ -218,7 +219,7 @@ class SpendLogCleanup: return cutoff_date = datetime.now(timezone.utc) - timedelta(seconds=float(self.retention_seconds)) - verbose_proxy_logger.info(f"Removing logs older than {cutoff_date.isoformat()}") + verbose_proxy_logger.info("Removing logs older than %s", cutoff_date.isoformat()) if self.general_settings.get( "use_spend_logs_partitioning", False @@ -235,13 +236,13 @@ class SpendLogCleanup: # or in a partition that spans the cutoff, so retention must # also delete those stragglers row-wise. total_deleted = await self._delete_old_logs(prisma_client, cutoff_date) - verbose_proxy_logger.info(f"Deleted {total_deleted} expired logs not covered by dropped partitions") + verbose_proxy_logger.info("Deleted %s expired logs not covered by dropped partitions", total_deleted) else: total_deleted = await self._delete_old_logs(prisma_client, cutoff_date) - verbose_proxy_logger.info(f"Deleted {total_deleted} logs") + verbose_proxy_logger.info("Deleted %s logs", total_deleted) index_deleted = await self._delete_old_tool_index_rows(prisma_client, cutoff_date) - verbose_proxy_logger.info(f"Deleted {index_deleted} expired tool index rows") + verbose_proxy_logger.info("Deleted %s expired tool index rows", index_deleted) except Exception as e: # .exception() captures the traceback; str(e) alone on a Prisma/DB diff --git a/litellm/proxy/db/dynamo_db.py b/litellm/proxy/db/dynamo_db.py index 6367c34341f..805d17b36ac 100644 --- a/litellm/proxy/db/dynamo_db.py +++ b/litellm/proxy/db/dynamo_db.py @@ -39,7 +39,7 @@ class DynamoDBWrapper(CustomDB): def set_env_vars_based_on_arn(self): if self.database_arguments.aws_role_name is None: return - verbose_proxy_logger.debug(f"DynamoDB: setting env vars based on arn={self.database_arguments.aws_role_name}") + verbose_proxy_logger.debug("DynamoDB: setting env vars based on arn=%s", self.database_arguments.aws_role_name) import os import boto3 @@ -63,7 +63,7 @@ class DynamoDBWrapper(CustomDB): aws_secret_access_key = assumed_role["Credentials"]["SecretAccessKey"] aws_session_token = assumed_role["Credentials"]["SessionToken"] - verbose_proxy_logger.debug(f"Got STS assumed Role, aws_access_key_id={aws_access_key_id}") + verbose_proxy_logger.debug("Got STS assumed Role, aws_access_key_id=%s", aws_access_key_id) # set these in the env so aiodynamo can use them os.environ["AWS_ACCESS_KEY_ID"] = aws_access_key_id os.environ["AWS_SECRET_ACCESS_KEY"] = aws_secret_access_key diff --git a/litellm/proxy/db/prisma_client.py b/litellm/proxy/db/prisma_client.py index 79f86d548c5..f12f29a03d0 100644 --- a/litellm/proxy/db/prisma_client.py +++ b/litellm/proxy/db/prisma_client.py @@ -398,7 +398,7 @@ class PrismaWrapper: return token_created + timedelta(seconds=expires_in) except Exception as e: - verbose_proxy_logger.debug(f"Failed to parse token expiration: {e}") + verbose_proxy_logger.debug("Failed to parse token expiration: %s", e) return None def _calculate_seconds_until_refresh(self) -> float: @@ -420,8 +420,8 @@ class PrismaWrapper: if expiration_time is None: # If we can't parse the token, use fallback interval verbose_proxy_logger.debug( - f"Could not parse token expiration, using fallback interval of " - f"{self.FALLBACK_REFRESH_INTERVAL_SECONDS}s" + "Could not parse token expiration, using fallback interval of %ss", + self.FALLBACK_REFRESH_INTERVAL_SECONDS, ) return self.FALLBACK_REFRESH_INTERVAL_SECONDS @@ -670,8 +670,9 @@ class PrismaWrapper: This is more efficient than polling, requiring only 1 wake-up per token cycle. """ verbose_proxy_logger.info( - f"{self._log_prefix}RDS IAM token refresh loop started. " - f"Tokens will be refreshed {self.TOKEN_REFRESH_BUFFER_SECONDS}s before expiration." + "%sRDS IAM token refresh loop started. Tokens will be refreshed %ss before expiration.", + self._log_prefix, + self.TOKEN_REFRESH_BUFFER_SECONDS, ) while True: @@ -695,8 +696,10 @@ class PrismaWrapper: break except Exception as e: verbose_proxy_logger.error( - f"{self._log_prefix}Error in RDS IAM token refresh loop: {e}. " - f"Retrying in {self.FALLBACK_REFRESH_INTERVAL_SECONDS}s..." + "%sError in RDS IAM token refresh loop: %s. Retrying in %ss...", + self._log_prefix, + e, + self.FALLBACK_REFRESH_INTERVAL_SECONDS, ) # On error, wait before retrying to avoid tight error loops try: @@ -874,7 +877,7 @@ class PrismaManager: try: from litellm_proxy_extras.utils import ProxyExtrasDBManager except ImportError as e: - verbose_proxy_logger.error(f"\033[1;31mLiteLLM: Failed to import proxy extras. Got {e}\033[0m") + verbose_proxy_logger.error("\x1b[1;31mLiteLLM: Failed to import proxy extras. Got %s\x1b[0m", e) return False prisma_dir = PrismaManager._get_prisma_dir() @@ -899,12 +902,12 @@ class PrismaManager: PrismaManager._apply_replica_identity_full_if_requested() return True except subprocess.TimeoutExpired: - verbose_proxy_logger.warning(f"Attempt {attempt + 1} timed out") + verbose_proxy_logger.warning("Attempt %s timed out", attempt + 1) time.sleep(random.randrange(5, 15)) except subprocess.CalledProcessError as e: attempts_left = 3 - attempt retry_msg = f" Retrying... ({attempts_left} attempts left)" if attempts_left > 0 else "" - verbose_proxy_logger.warning(f"The process failed to execute. Details: {e}.{retry_msg}") + verbose_proxy_logger.warning("The process failed to execute. Details: %s.%s", e, retry_msg) time.sleep(random.randrange(5, 15)) finally: os.chdir(original_dir) diff --git a/litellm/proxy/example_config_yaml/custom_guardrail.py b/litellm/proxy/example_config_yaml/custom_guardrail.py index a755390743e..d30ed839ce4 100644 --- a/litellm/proxy/example_config_yaml/custom_guardrail.py +++ b/litellm/proxy/example_config_yaml/custom_guardrail.py @@ -23,7 +23,7 @@ class GuardrailForLBTestingA(CustomGuardrail): call_type: CallTypesLiteral, ) -> Optional[Union[Exception, str, dict]]: guardrail_lb_call_count["A"] += 1 - verbose_proxy_logger.info(f"GuardrailForLBTestingA called. Total A calls: {guardrail_lb_call_count['A']}") + verbose_proxy_logger.info("GuardrailForLBTestingA called. Total A calls: %s", guardrail_lb_call_count["A"]) return data @@ -38,7 +38,7 @@ class GuardrailForLBTestingB(CustomGuardrail): call_type: CallTypesLiteral, ) -> Optional[Union[Exception, str, dict]]: guardrail_lb_call_count["B"] += 1 - verbose_proxy_logger.info(f"GuardrailForLBTestingB called. Total B calls: {guardrail_lb_call_count['B']}") + verbose_proxy_logger.info("GuardrailForLBTestingB called. Total B calls: %s", guardrail_lb_call_count["B"]) return data diff --git a/litellm/proxy/fine_tuning_endpoints/endpoints.py b/litellm/proxy/fine_tuning_endpoints/endpoints.py index 4daab1caf96..3cdd57490c6 100644 --- a/litellm/proxy/fine_tuning_endpoints/endpoints.py +++ b/litellm/proxy/fine_tuning_endpoints/endpoints.py @@ -112,7 +112,8 @@ async def create_fine_tuning_job( # Convert Pydantic model to dict verbose_proxy_logger.debug( - f"Request received by LiteLLM:\n{json.dumps(data, indent=4)}", + "Request received by LiteLLM:\n%s", + json.dumps(data, indent=4), ) # Include original request and headers in the data @@ -199,7 +200,9 @@ async def create_fine_tuning_job( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.create_fine_tuning_job(): Exception occurred - {e}") + verbose_proxy_logger.exception( + "litellm.proxy.proxy_server.create_fine_tuning_job(): Exception occurred - %s", e + ) raise handle_exception_on_proxy(e) @@ -338,7 +341,7 @@ async def retrieve_fine_tuning_job( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) verbose_proxy_logger.exception( - f"litellm.proxy.proxy_server.retrieve_fine_tuning_job(): Exception occurred - {e}" + "litellm.proxy.proxy_server.retrieve_fine_tuning_job(): Exception occurred - %s", e ) raise handle_exception_on_proxy(e) @@ -466,7 +469,7 @@ async def list_fine_tuning_jobs( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.list_fine_tuning_jobs(): Exception occurred - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.list_fine_tuning_jobs(): Exception occurred - %s", e) raise handle_exception_on_proxy(e) @@ -604,5 +607,7 @@ async def cancel_fine_tuning_job( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.cancel_fine_tuning_job(): Exception occurred - {e}") + verbose_proxy_logger.exception( + "litellm.proxy.proxy_server.cancel_fine_tuning_job(): Exception occurred - %s", e + ) raise handle_exception_on_proxy(e) diff --git a/litellm/proxy/guardrails/guardrail_endpoints.py b/litellm/proxy/guardrails/guardrail_endpoints.py index 12373b7fb97..baf44e5a291 100644 --- a/litellm/proxy/guardrails/guardrail_endpoints.py +++ b/litellm/proxy/guardrails/guardrail_endpoints.py @@ -313,7 +313,7 @@ async def list_guardrails_v2( return ListGuardrailsResponse(guardrails=guardrail_configs) except Exception as e: - verbose_proxy_logger.exception(f"Error getting guardrails from db: {e}") + verbose_proxy_logger.exception("Error getting guardrails from db: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -397,7 +397,7 @@ async def create_guardrail( try: IN_MEMORY_GUARDRAIL_HANDLER.initialize_guardrail(guardrail=cast(Guardrail, result), source="db") verbose_proxy_logger.info( - f"Immediate sync: Successfully initialized guardrail '{guardrail_name}' (ID: {guardrail_id})" + "Immediate sync: Successfully initialized guardrail '%s' (ID: %s)", guardrail_name, guardrail_id ) except (ValueError, TypeError) as init_error: # Configuration error — roll back the DB write so the guardrail isn't orphaned @@ -405,19 +405,22 @@ async def create_guardrail( try: await _delete_guardrail_row(prisma_client, where={"guardrail_id": guardrail_id}) except Exception as rollback_err: - verbose_proxy_logger.warning(f"Rollback failed for guardrail '{guardrail_id}': {rollback_err}") + verbose_proxy_logger.warning("Rollback failed for guardrail '%s': %s", guardrail_id, rollback_err) raise HTTPException( status_code=400, detail=f"Guardrail configuration error: {init_error}", ) except Exception as init_error: verbose_proxy_logger.warning( - f"Immediate sync: Failed to initialize guardrail '{guardrail_name}' (ID: {guardrail_id}) in memory: {init_error}" + "Immediate sync: Failed to initialize guardrail '%s' (ID: %s) in memory: %s", + guardrail_name, + guardrail_id, + init_error, ) return result except Exception as e: - verbose_proxy_logger.exception(f"Error adding guardrail to db: {e}") + verbose_proxy_logger.exception("Error adding guardrail to db: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -515,11 +518,14 @@ async def update_guardrail( guardrail_id=guardrail_id, guardrail=cast(Guardrail, result) ) verbose_proxy_logger.info( - f"Immediate sync: Successfully updated guardrail '{guardrail_name}' (ID: {guardrail_id})" + "Immediate sync: Successfully updated guardrail '%s' (ID: %s)", guardrail_name, guardrail_id ) except Exception as update_error: verbose_proxy_logger.warning( - f"Immediate sync: Failed to update '{guardrail_name}' (ID: {guardrail_id}) in memory: {update_error}" + "Immediate sync: Failed to update '%s' (ID: %s) in memory: %s", + guardrail_name, + guardrail_id, + update_error, ) return result @@ -587,11 +593,14 @@ async def delete_guardrail( guardrail_id=guardrail_id, ) verbose_proxy_logger.info( - f"Immediate sync: Successfully removed guardrail '{guardrail_name}' (ID: {guardrail_id}) from memory" + "Immediate sync: Successfully removed guardrail '%s' (ID: %s) from memory", guardrail_name, guardrail_id ) except Exception as delete_error: verbose_proxy_logger.warning( - f"Immediate sync: Failed to remove guardrail '{guardrail_name}' (ID: {guardrail_id}) from memory: {delete_error}" + "Immediate sync: Failed to remove guardrail '%s' (ID: %s) from memory: %s", + guardrail_name, + guardrail_id, + delete_error, ) return result @@ -1203,18 +1212,21 @@ async def patch_guardrail( guardrail=guardrail, ) verbose_proxy_logger.info( - f"Immediate sync: Successfully updated guardrail '{guardrail_name}' (ID: {guardrail_id})" + "Immediate sync: Successfully updated guardrail '%s' (ID: %s)", guardrail_name, guardrail_id ) except Exception as update_error: verbose_proxy_logger.warning( - f"Immediate sync: Failed to update '{guardrail_name}' (ID: {guardrail_id}) in memory: {update_error}" + "Immediate sync: Failed to update '%s' (ID: %s) in memory: %s", + guardrail_name, + guardrail_id, + update_error, ) return result except HTTPException as e: raise e except Exception as e: - verbose_proxy_logger.exception(f"Error updating guardrail: {e}") + verbose_proxy_logger.exception("Error updating guardrail: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -2126,7 +2138,7 @@ async def test_custom_code_guardrail( ) except Exception as e: - verbose_proxy_logger.exception(f"Error testing custom code guardrail: {e}") + verbose_proxy_logger.exception("Error testing custom code guardrail: %s", e) return TestCustomCodeGuardrailResponse( success=False, error=f"Unexpected error: {e}", diff --git a/litellm/proxy/guardrails/guardrail_hooks/aim/aim.py b/litellm/proxy/guardrails/guardrail_hooks/aim/aim.py index 076cdfc8ecd..d9bcef731bb 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/aim/aim.py +++ b/litellm/proxy/guardrails/guardrail_hooks/aim/aim.py @@ -123,7 +123,7 @@ class AimGuardrail(CustomGuardrail): elif action_type == "anonymize_action": return self._anonymize_request(res, data) else: - verbose_proxy_logger.error(f"Aim: {action_type} action") + verbose_proxy_logger.error("Aim: %s action", action_type) return data @staticmethod @@ -328,7 +328,7 @@ class AimGuardrail(CustomGuardrail): from litellm.proxy.proxy_server import StreamingCallbackError raise StreamingCallbackError(blocking_message) - verbose_proxy_logger.error(f"Unknown message received from AIM: {result}") + verbose_proxy_logger.error("Unknown message received from AIM: %s", result) return async def forward_the_stream_to_aim( diff --git a/litellm/proxy/guardrails/guardrail_hooks/azure/prompt_shield.py b/litellm/proxy/guardrails/guardrail_hooks/azure/prompt_shield.py index 3df4f230dbf..95fe649a565 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/azure/prompt_shield.py +++ b/litellm/proxy/guardrails/guardrail_hooks/azure/prompt_shield.py @@ -58,7 +58,7 @@ class AzureContentSafetyPromptShieldGuardrail(AzureGuardrailBase, CustomGuardrai **kwargs, ) - verbose_proxy_logger.debug(f"Initialized Azure Prompt Shield Guardrail: {guardrail_name}") + verbose_proxy_logger.debug("Initialized Azure Prompt Shield Guardrail: %s", guardrail_name) async def async_make_request(self, user_prompt: str) -> "AzurePromptShieldGuardrailResponse": """ @@ -127,7 +127,7 @@ class AzureContentSafetyPromptShieldGuardrail(AzureGuardrailBase, CustomGuardrai user_prompt = self.get_user_prompt(new_messages) if user_prompt: - verbose_proxy_logger.debug(f"Azure Prompt Shield: User prompt: {user_prompt}") + verbose_proxy_logger.debug("Azure Prompt Shield: User prompt: %s", user_prompt) await self.async_make_request( user_prompt=user_prompt, ) diff --git a/litellm/proxy/guardrails/guardrail_hooks/azure/text_moderation.py b/litellm/proxy/guardrails/guardrail_hooks/azure/text_moderation.py index 0b1faf99469..5355631def6 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/azure/text_moderation.py +++ b/litellm/proxy/guardrails/guardrail_hooks/azure/text_moderation.py @@ -90,7 +90,7 @@ class AzureContentSafetyTextModerationGuardrail(AzureGuardrailBase, CustomGuardr self.severity_threshold = int(severity_threshold) if severity_threshold else None self.severity_threshold_by_category = severity_threshold_by_category - verbose_proxy_logger.info(f"Initialized Azure Text Moderation Guardrail: {guardrail_name}") + verbose_proxy_logger.info("Initialized Azure Text Moderation Guardrail: %s", guardrail_name) @staticmethod def get_config_model() -> type["GuardrailConfigModel"] | None: @@ -223,7 +223,7 @@ class AzureContentSafetyTextModerationGuardrail(AzureGuardrailBase, CustomGuardr user_prompt = self.get_user_prompt(new_messages) if user_prompt: - verbose_proxy_logger.info(f"Azure Text Moderation: User prompt: {user_prompt}") + verbose_proxy_logger.info("Azure Text Moderation: User prompt: %s", user_prompt) await self.async_make_request( text=user_prompt, ) diff --git a/litellm/proxy/guardrails/guardrail_hooks/bedrock_guardrails.py b/litellm/proxy/guardrails/guardrail_hooks/bedrock_guardrails.py index 5aae14b83e6..dab9a3d47f5 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/bedrock_guardrails.py +++ b/litellm/proxy/guardrails/guardrail_hooks/bedrock_guardrails.py @@ -2157,7 +2157,7 @@ class BedrockGuardrail(CustomGuardrail, BaseAWSLLM): # dict.get("texts", []) would return None if the key exists with a None value. texts = inputs.get("texts") or [] try: - verbose_proxy_logger.debug(f"Bedrock Guardrail: Applying guardrail to {len(texts)} text(s)") + verbose_proxy_logger.debug("Bedrock Guardrail: Applying guardrail to %s text(s)", len(texts)) if input_type == "request": incremental_result = await self._apply_incremental_request_scan( diff --git a/litellm/proxy/guardrails/guardrail_hooks/cato_networks/cato_networks.py b/litellm/proxy/guardrails/guardrail_hooks/cato_networks/cato_networks.py index e0411de2db4..661e1d4c749 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/cato_networks/cato_networks.py +++ b/litellm/proxy/guardrails/guardrail_hooks/cato_networks/cato_networks.py @@ -264,7 +264,7 @@ class CatoNetworksGuardrail(CustomGuardrail): elif action_type == "anonymize_action": return self._anonymize_request(res, data) else: - verbose_proxy_logger.error(f"Cato: {action_type} action") + verbose_proxy_logger.error("Cato: %s action", action_type) return data def _handle_block_action(self, analysis_result: Any, required_action: Any) -> None: @@ -555,7 +555,7 @@ class CatoNetworksGuardrail(CustomGuardrail): return if blocking_message := result.get("blocking_message"): raise StreamingCallbackError(blocking_message) - verbose_proxy_logger.error(f"Unknown message received from Cato: {result}") + verbose_proxy_logger.error("Unknown message received from Cato: %s", result) return finally: await self._cancel_background_task(sender) diff --git a/litellm/proxy/guardrails/guardrail_hooks/crowdstrike_aidr/crowdstrike_aidr.py b/litellm/proxy/guardrails/guardrail_hooks/crowdstrike_aidr/crowdstrike_aidr.py index 600da6ecfc4..b93a1f99a3a 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/crowdstrike_aidr/crowdstrike_aidr.py +++ b/litellm/proxy/guardrails/guardrail_hooks/crowdstrike_aidr/crowdstrike_aidr.py @@ -275,7 +275,7 @@ class CrowdStrikeAIDRHandler(CustomGuardrail): # Pass relevant kwargs to the parent class super().__init__(guardrail_name=guardrail_name, **kwargs) verbose_proxy_logger.debug( - f"Initialized CrowdStrike AIDR Guardrail: name={guardrail_name}, api_base={self.api_base}" + "Initialized CrowdStrike AIDR Guardrail: name=%s, api_base=%s", guardrail_name, self.api_base ) async def _call_crowdstrike_aidr_guard( @@ -306,7 +306,7 @@ class CrowdStrikeAIDRHandler(CustomGuardrail): } verbose_proxy_logger.debug( - f"CrowdStrike AIDR Guardrail ({hook_name}): Calling endpoint {endpoint} with payload: {payload}" + "CrowdStrike AIDR Guardrail (%s): Calling endpoint %s with payload: %s", hook_name, endpoint, payload ) response = await self.async_handler.post(url=endpoint, json=payload, headers=headers) @@ -317,7 +317,7 @@ class CrowdStrikeAIDRHandler(CustomGuardrail): if result.blocked: verbose_proxy_logger.warning( - f"CrowdStrike AIDR Guardrail ({hook_name}): Request blocked. Response: {result}" + "CrowdStrike AIDR Guardrail (%s): Request blocked. Response: %s", hook_name, result ) raise HTTPException( status_code=400, # Bad Request, indicating violation @@ -327,7 +327,7 @@ class CrowdStrikeAIDRHandler(CustomGuardrail): }, ) verbose_proxy_logger.debug( - f"CrowdStrike AIDR Guardrail ({hook_name}): Request passed. Response: {result.detectors}" + "CrowdStrike AIDR Guardrail (%s): Request passed. Response: %s", hook_name, result.detectors ) return result @@ -396,7 +396,7 @@ class CrowdStrikeAIDRHandler(CustomGuardrail): input_type: Literal["request", "response"], logging_obj: Optional["LiteLLMLoggingObj"] = None, ) -> GenericGuardrailAPIInputs: - verbose_proxy_logger.debug(f"CrowdStrike AIDR Guardrail: Applying guardrail to {input_type}") + verbose_proxy_logger.debug("CrowdStrike AIDR Guardrail: Applying guardrail to %s", input_type) # Extract inputs texts = inputs.get("texts", []) diff --git a/litellm/proxy/guardrails/guardrail_hooks/custom_code/custom_code_guardrail.py b/litellm/proxy/guardrails/guardrail_hooks/custom_code/custom_code_guardrail.py index c7a036562f7..8b7c231b690 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/custom_code/custom_code_guardrail.py +++ b/litellm/proxy/guardrails/guardrail_hooks/custom_code/custom_code_guardrail.py @@ -176,7 +176,7 @@ class CustomCodeGuardrail(CustomGuardrail): try: self._do_compile() - verbose_proxy_logger.debug(f"Custom code guardrail '{self.guardrail_name}' compiled successfully") + verbose_proxy_logger.debug("Custom code guardrail '%s' compiled successfully", self.guardrail_name) except SyntaxError as e: self._compile_error = f"Syntax error in custom code: {e}" @@ -254,7 +254,7 @@ class CustomCodeGuardrail(CustomGuardrail): # Pre-call block uses passthrough; must not wrap as execution error (500) raise except Exception as e: - verbose_proxy_logger.error(f"Custom code guardrail '{self.guardrail_name}' execution error: {e}") + verbose_proxy_logger.error("Custom code guardrail '%s' execution error: %s", self.guardrail_name, e) raise CustomCodeExecutionError( f"Custom code guardrail execution failed: {e}", details={ @@ -308,15 +308,16 @@ class CustomCodeGuardrail(CustomGuardrail): """ if not isinstance(result, dict): verbose_proxy_logger.warning( - f"Custom code guardrail '{self.guardrail_name}': " - f"Expected dict result, got {type(result).__name__}. Treating as allow." + "Custom code guardrail '%s': Expected dict result, got %s. Treating as allow.", + self.guardrail_name, + type(result).__name__, ) return inputs action = result.get("action", "allow") if action == "allow": - verbose_proxy_logger.debug(f"Custom code guardrail '{self.guardrail_name}': Allowing {input_type}") + verbose_proxy_logger.debug("Custom code guardrail '%s': Allowing %s", self.guardrail_name, input_type) return inputs elif action == "block": @@ -324,7 +325,7 @@ class CustomCodeGuardrail(CustomGuardrail): detection_info = result.get("detection_info", {}) verbose_proxy_logger.info( - f"Custom code guardrail '{self.guardrail_name}': Blocking {input_type} - {reason}" + "Custom code guardrail '%s': Blocking %s - %s", self.guardrail_name, input_type, reason ) is_output = input_type == "response" @@ -348,7 +349,7 @@ class CustomCodeGuardrail(CustomGuardrail): ) elif action == "modify": - verbose_proxy_logger.debug(f"Custom code guardrail '{self.guardrail_name}': Modifying {input_type}") + verbose_proxy_logger.debug("Custom code guardrail '%s': Modifying %s", self.guardrail_name, input_type) # Apply modifications modified_inputs = dict(inputs) @@ -366,7 +367,7 @@ class CustomCodeGuardrail(CustomGuardrail): else: verbose_proxy_logger.warning( - f"Custom code guardrail '{self.guardrail_name}': Unknown action '{action}'. Treating as allow." + "Custom code guardrail '%s': Unknown action '%s'. Treating as allow.", self.guardrail_name, action ) return inputs @@ -393,7 +394,7 @@ class CustomCodeGuardrail(CustomGuardrail): try: self.custom_code = new_code self._do_compile() - verbose_proxy_logger.info(f"Custom code guardrail '{self.guardrail_name}': Code updated successfully") + verbose_proxy_logger.info("Custom code guardrail '%s': Code updated successfully", self.guardrail_name) except SyntaxError as e: # Rollback on failure self.custom_code = old_code diff --git a/litellm/proxy/guardrails/guardrail_hooks/custom_code/primitives.py b/litellm/proxy/guardrails/guardrail_hooks/custom_code/primitives.py index 43a3671ad97..f77bd324462 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/custom_code/primitives.py +++ b/litellm/proxy/guardrails/guardrail_hooks/custom_code/primitives.py @@ -94,7 +94,7 @@ def regex_match(text: str, pattern: str, flags: int = 0) -> bool: try: return bool(re.search(pattern, text, flags)) except re.error as e: - verbose_proxy_logger.warning(f"Starlark regex_match error: {e}") + verbose_proxy_logger.warning("Starlark regex_match error: %s", e) return False @@ -113,7 +113,7 @@ def regex_match_all(text: str, pattern: str, flags: int = 0) -> bool: try: return bool(re.fullmatch(pattern, text, flags)) except re.error as e: - verbose_proxy_logger.warning(f"Starlark regex_match_all error: {e}") + verbose_proxy_logger.warning("Starlark regex_match_all error: %s", e) return False @@ -133,7 +133,7 @@ def regex_replace(text: str, pattern: str, replacement: str, flags: int = 0) -> try: return re.sub(pattern, replacement, text, flags=flags) except re.error as e: - verbose_proxy_logger.warning(f"Starlark regex_replace error: {e}") + verbose_proxy_logger.warning("Starlark regex_replace error: %s", e) return text @@ -152,7 +152,7 @@ def regex_find_all(text: str, pattern: str, flags: int = 0) -> list[str]: try: return re.findall(pattern, text, flags) except re.error as e: - verbose_proxy_logger.warning(f"Starlark regex_find_all error: {e}") + verbose_proxy_logger.warning("Starlark regex_find_all error: %s", e) return [] @@ -174,7 +174,7 @@ def json_parse(text: str) -> Any | None: try: return json.loads(text) except (json.JSONDecodeError, TypeError) as e: - verbose_proxy_logger.debug(f"Starlark json_parse error: {e}") + verbose_proxy_logger.debug("Starlark json_parse error: %s", e) return None @@ -191,7 +191,7 @@ def json_stringify(obj: Any) -> str: try: return json.dumps(obj) except (TypeError, ValueError) as e: - verbose_proxy_logger.warning(f"Starlark json_stringify error: {e}") + verbose_proxy_logger.warning("Starlark json_stringify error: %s", e) return "" @@ -222,7 +222,7 @@ def json_schema_valid(obj: Any, schema: dict[str, Any]) -> bool: return False raise except Exception as e: - verbose_proxy_logger.warning(f"Custom code json_schema_valid error: {e}") + verbose_proxy_logger.warning("Custom code json_schema_valid error: %s", e) return False @@ -473,16 +473,16 @@ async def http_request( return _http_success_response(response) except httpx.TimeoutException as e: - verbose_proxy_logger.warning(f"Custom code http_request timeout: {e}") + verbose_proxy_logger.warning("Custom code http_request timeout: %s", e) return _http_error_response(f"Request timeout after {timeout}s") except httpx.HTTPStatusError as e: # Return the response even for non-2xx status codes return _http_success_response(e.response) except httpx.RequestError as e: - verbose_proxy_logger.warning(f"Custom code http_request error: {e}") + verbose_proxy_logger.warning("Custom code http_request error: %s", e) return _http_error_response(f"Request failed: {e}") except Exception as e: - verbose_proxy_logger.warning(f"Custom code http_request unexpected error: {e}") + verbose_proxy_logger.warning("Custom code http_request unexpected error: %s", e) return _http_error_response(f"Unexpected error: {e}") diff --git a/litellm/proxy/guardrails/guardrail_hooks/hiddenlayer/hiddenlayer.py b/litellm/proxy/guardrails/guardrail_hooks/hiddenlayer/hiddenlayer.py index 73306ce1154..26f61418cae 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/hiddenlayer/hiddenlayer.py +++ b/litellm/proxy/guardrails/guardrail_hooks/hiddenlayer/hiddenlayer.py @@ -237,7 +237,7 @@ class HiddenlayerGuardrail(CustomGuardrail): response.raise_for_status() result = response.json() - verbose_proxy_logger.debug(f"Hiddenlayer reponse: {result}") + verbose_proxy_logger.debug("Hiddenlayer reponse: %s", result) return result except HTTPStatusError as e: @@ -261,7 +261,7 @@ class HiddenlayerGuardrail(CustomGuardrail): response.raise_for_status() result = response.json() - verbose_proxy_logger.debug(f"Hiddenlayer reponse: {result}") + verbose_proxy_logger.debug("Hiddenlayer reponse: %s", result) return result @staticmethod @@ -434,7 +434,7 @@ class HiddenlayerGuardrailV2(CustomGuardrail): ) response.raise_for_status() - verbose_proxy_logger.debug(f"Hiddenlayer reponse: {response}") + verbose_proxy_logger.debug("Hiddenlayer reponse: %s", response) return response except HTTPStatusError as e: @@ -457,7 +457,7 @@ class HiddenlayerGuardrailV2(CustomGuardrail): response.raise_for_status() - verbose_proxy_logger.debug(f"Hiddenlayer reponse: {response}") + verbose_proxy_logger.debug("Hiddenlayer reponse: %s", response) return response @staticmethod diff --git a/litellm/proxy/guardrails/guardrail_hooks/lasso/lasso.py b/litellm/proxy/guardrails/guardrail_hooks/lasso/lasso.py index 90d131893c6..6b713e4d519 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/lasso/lasso.py +++ b/litellm/proxy/guardrails/guardrail_hooks/lasso/lasso.py @@ -116,8 +116,10 @@ class LassoGuardrail(CustomGuardrail): self.api_base = api_base or os.getenv("LASSO_API_BASE") or "https://server.lasso.security/gateway/v3" verbose_proxy_logger.debug( - f"Lasso guardrail initialized: {kwargs.get('guardrail_name', 'unknown')}, " - f"event_hook: {kwargs.get('event_hook', 'unknown')}, mask: {self.mask}" + "Lasso guardrail initialized: %s, event_hook: %s, mask: %s", + kwargs.get("guardrail_name", "unknown"), + kwargs.get("event_hook", "unknown"), + self.mask, ) super().__init__(**kwargs) @@ -299,7 +301,7 @@ class LassoGuardrail(CustomGuardrail): except Exception as e: if isinstance(e, HTTPException): raise e - verbose_proxy_logger.error(f"Error in post-call Lasso masking: {e}") + verbose_proxy_logger.error("Error in post-call Lasso masking: %s", e) raise LassoGuardrailAPIError(f"Failed to apply post-call masking: {e}") else: # Use the same data for conversation_id consistency (no cache access needed) @@ -308,7 +310,7 @@ class LassoGuardrail(CustomGuardrail): else: verbose_proxy_logger.warning("No response messages found to validate") else: - verbose_proxy_logger.warning(f"Unexpected response type for post-call hook: {type(response)}") + verbose_proxy_logger.warning("Unexpected response type for post-call hook: %s", type(response)) return response @@ -353,7 +355,7 @@ class LassoGuardrail(CustomGuardrail): if cached_conversation_id: return cached_conversation_id except Exception as e: - verbose_proxy_logger.warning(f"Cache retrieval failed: {e}") + verbose_proxy_logger.warning("Cache retrieval failed: %s", e) # Generate new conversation_id and store in cache generated_id = self._generate_ulid() @@ -361,7 +363,7 @@ class LassoGuardrail(CustomGuardrail): try: cache.set_cache(cache_key, generated_id, ttl=3600) # Cache for 1 hour except Exception as e: - verbose_proxy_logger.warning(f"Cache storage failed: {e}") + verbose_proxy_logger.warning("Cache storage failed: %s", e) return generated_id @@ -599,7 +601,8 @@ class LassoGuardrail(CustomGuardrail): # Log error with context verbose_proxy_logger.error( - f"Error calling Lasso API: {error}", + "Error calling Lasso API: %s", + error, extra={ "guardrail_name": getattr(self, "guardrail_name", "unknown"), "message_type": message_type, @@ -810,7 +813,7 @@ class LassoGuardrail(CustomGuardrail): ) -> LassoResponse: """Call the Lasso API and return the response.""" url = api_url or f"{self.api_base}/classify" - verbose_proxy_logger.debug(f"Calling Lasso API with messageType: {payload.get('messageType')}") + verbose_proxy_logger.debug("Calling Lasso API with messageType: %s", payload.get("messageType")) response = await self.async_handler.post( url=url, headers=headers, @@ -848,7 +851,7 @@ class LassoGuardrail(CustomGuardrail): """ if response and response.get("violations_detected") is True: violated_deputies = self._parse_violated_deputies(response) - verbose_proxy_logger.warning(f"Lasso guardrail detected violations: {violated_deputies}") + verbose_proxy_logger.warning("Lasso guardrail detected violations: %s", violated_deputies) # Check if any findings have "BLOCK" action blocking_violations = self._check_for_blocking_actions(response) @@ -866,7 +869,7 @@ class LassoGuardrail(CustomGuardrail): else: # Continue with warning for non-blocking violations (e.g., AUTO_MASKING) verbose_proxy_logger.info( - f"Non-blocking Lasso violations detected, continuing with warning: {violated_deputies}" + "Non-blocking Lasso violations detected, continuing with warning: %s", violated_deputies ) def _check_for_blocking_actions(self, response: LassoResponse) -> list[str]: @@ -955,7 +958,7 @@ class LassoGuardrail(CustomGuardrail): if msg.content and apply_text and text_cursor < len(masked_text): msg.content = masked_text[text_cursor] text_cursor += 1 - verbose_proxy_logger.debug(f"Applied masked text content to choice {text_cursor}") + verbose_proxy_logger.debug("Applied masked text content to choice %s", text_cursor) for call in getattr(msg, "tool_calls", None) or []: call_id = self._get_field(call, "id") @@ -970,7 +973,7 @@ class LassoGuardrail(CustomGuardrail): func = getattr(call, "function", None) if func: func.arguments = json.dumps(masked_input) - verbose_proxy_logger.debug(f"Applied masked tool_call arguments for call_id={call_id}") + verbose_proxy_logger.debug("Applied masked tool_call arguments for call_id=%s", call_id) @staticmethod def get_config_model() -> type["GuardrailConfigModel"] | None: diff --git a/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/content_filter.py b/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/content_filter.py index c6900c38cbf..c36b5849fb6 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/content_filter.py +++ b/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/content_filter.py @@ -121,7 +121,7 @@ class CategoryConfig: try: self.phrase_patterns.append((p, re.compile(p, re.IGNORECASE))) except re.error: - verbose_proxy_logger.warning(f"Invalid phrase pattern in {category_name}: {p}") + verbose_proxy_logger.warning("Invalid phrase pattern in %s: %s", category_name, p) class ContentFilterGuardrail(CustomGuardrail): @@ -226,8 +226,8 @@ class ContentFilterGuardrail(CustomGuardrail): p["action"] == ContentFilterAction.MASK for p in self.compiled_patterns ): verbose_proxy_logger.warning( - f"ContentFilterGuardrail '{self.guardrail_name}': 'during_call' mode with 'MASK' action is unstable due to race conditions. " - "Use 'pre_call' mode for reliable request masking." + "ContentFilterGuardrail '%s': 'during_call' mode with 'MASK' action is unstable due to race conditions. Use 'pre_call' mode for reliable request masking.", + self.guardrail_name, ) # Load blocked words - always initialize as dict @@ -238,7 +238,7 @@ class ContentFilterGuardrail(CustomGuardrail): # Defensive check: ensure blocked_words is a dict (not a list) if not isinstance(self.blocked_words, dict): verbose_proxy_logger.error( - f"blocked_words is not a dict, got {type(self.blocked_words)}. Resetting to empty dict." + "blocked_words is not a dict, got %s. Resetting to empty dict.", type(self.blocked_words) ) self.blocked_words = {} @@ -247,11 +247,12 @@ class ContentFilterGuardrail(CustomGuardrail): self._load_blocked_words_file(blocked_words_file) verbose_proxy_logger.debug( - f"ContentFilterGuardrail initialized with {len(self.compiled_patterns)} patterns " - f"and {len(self.blocked_words)} blocked words" + "ContentFilterGuardrail initialized with %s patterns and %s blocked words", + len(self.compiled_patterns), + len(self.blocked_words), ) verbose_proxy_logger.debug( - f"Loaded {len(self.loaded_categories)} categories with {len(self.category_keywords)} keywords" + "Loaded %s categories with %s keywords", len(self.loaded_categories), len(self.category_keywords) ) def _init_competitor_intent_checker(self, competitor_intent_config: dict[str, Any]) -> None: @@ -406,7 +407,7 @@ class ContentFilterGuardrail(CustomGuardrail): # Prevent path traversal via category_name (e.g. "../../etc/passwd") if not re.match(r"^[a-zA-Z0-9_\-]+$", category_name): - verbose_proxy_logger.warning(f"Category name '{category_name}' contains invalid characters, skipping") + verbose_proxy_logger.warning("Category name '%s' contains invalid characters, skipping", category_name) continue enabled = cat_config.get("enabled", True) @@ -417,7 +418,7 @@ class ContentFilterGuardrail(CustomGuardrail): custom_file = cat_config.get("category_file") if not enabled: - verbose_proxy_logger.debug(f"Category {category_name} is disabled, skipping") + verbose_proxy_logger.debug("Category %s is disabled, skipping", category_name) continue # Load category file (custom or default) @@ -425,7 +426,9 @@ class ContentFilterGuardrail(CustomGuardrail): try: category_file_path = self._resolve_category_file_path(custom_file) except ValueError as e: - verbose_proxy_logger.warning(f"Category {category_name}: invalid category_file path, skipping. {e}") + verbose_proxy_logger.warning( + "Category %s: invalid category_file path, skipping. %s", category_name, e + ) continue else: # Try .yaml first, then .json (e.g. harm_toxic_abuse.json) @@ -439,7 +442,7 @@ class ContentFilterGuardrail(CustomGuardrail): category_file_path = yaml_path # will trigger "not found" below if not os.path.exists(category_file_path): - verbose_proxy_logger.warning(f"Category file not found: {category_file_path}, skipping") + verbose_proxy_logger.warning("Category file not found: %s, skipping", category_file_path) continue try: @@ -487,13 +490,14 @@ class ContentFilterGuardrail(CustomGuardrail): ) verbose_proxy_logger.info( - f"Loaded category {category_name}: " - f"{len(category_config_obj.keywords)} keywords, " - f"{len(category_config_obj.always_block_keywords)} always-block keywords, " - f"conditional: {bool(category_config_obj.identifier_words)}" + "Loaded category %s: %s keywords, %s always-block keywords, conditional: %s", + category_name, + len(category_config_obj.keywords), + len(category_config_obj.always_block_keywords), + bool(category_config_obj.identifier_words), ) except Exception as e: - verbose_proxy_logger.error(f"Error loading category {category_name}: {e}") + verbose_proxy_logger.error("Error loading category %s: %s", category_name, e) def _load_conditional_category( self, @@ -534,9 +538,12 @@ class ContentFilterGuardrail(CustomGuardrail): inherit_file_path = inherit_json_path else: verbose_proxy_logger.warning( - f"Category {category_name}: inherit_from '{inherit_from}' file not found at {categories_dir}" + "Category %s: inherit_from '%s' file not found at %s", + category_name, + inherit_from, + categories_dir, ) - verbose_proxy_logger.debug(f"Tried paths: {inherit_yaml_path}, {inherit_json_path}") + verbose_proxy_logger.debug("Tried paths: %s, %s", inherit_yaml_path, inherit_json_path) if inherit_file_path: # Load the inherited category @@ -583,7 +590,7 @@ class ContentFilterGuardrail(CustomGuardrail): verbose_proxy_logger.info(log_msg) except Exception as e: - verbose_proxy_logger.error(f"Error loading conditional category for {category_name}: {e}") + verbose_proxy_logger.error("Error loading conditional category for %s: %s", category_name, e) def _load_category_file(self, file_path: str) -> CategoryConfig: """ @@ -708,9 +715,9 @@ class ContentFilterGuardrail(CustomGuardrail): "allow_word_numbers": bool(extra_config.get("allow_word_numbers")), } ) - verbose_proxy_logger.debug(f"Added pattern: {pattern_name} with action {pattern_config.action}") + verbose_proxy_logger.debug("Added pattern: %s with action %s", pattern_name, pattern_config.action) except Exception as e: - verbose_proxy_logger.error(f"Error adding pattern {pattern_config}: {e}") + verbose_proxy_logger.error("Error adding pattern %s: %s", pattern_config, e) raise def _load_blocked_words_file(self, file_path: str) -> None: @@ -737,7 +744,7 @@ class ContentFilterGuardrail(CustomGuardrail): for word_data in data["blocked_words"]: if not isinstance(word_data, dict) or "keyword" not in word_data or "action" not in word_data: - verbose_proxy_logger.warning(f"Skipping invalid word entry: {word_data}") + verbose_proxy_logger.warning("Skipping invalid word entry: %s", word_data) continue keyword = word_data["keyword"].lower() @@ -746,7 +753,7 @@ class ContentFilterGuardrail(CustomGuardrail): self.blocked_words[keyword] = (action, description) - verbose_proxy_logger.info(f"Loaded {len(data['blocked_words'])} blocked words from {file_path}") + verbose_proxy_logger.info("Loaded %s blocked words from %s", len(data["blocked_words"]), file_path) except FileNotFoundError: raise FileNotFoundError(f"Blocked words file not found: {file_path}") except Exception as e: @@ -889,7 +896,7 @@ class ContentFilterGuardrail(CustomGuardrail): matched_text = text[start:end] pattern_name = pattern_entry["pattern_name"] action = pattern_entry["action"] - verbose_proxy_logger.debug(f"Pattern '{pattern_name}' matched: {matched_text[:20]}...") + verbose_proxy_logger.debug("Pattern '%s' matched: %s...", pattern_name, matched_text[:20]) return (matched_text, pattern_name, action) return None @@ -933,7 +940,7 @@ class ContentFilterGuardrail(CustomGuardrail): for exception in category_obj.exceptions: if exception in text_lower: verbose_proxy_logger.debug( - f"Category exception '{exception}' found for {category_name}, skipping" + "Category exception '%s' found for %s, skipping", exception, category_name ) exception_found = True break @@ -975,7 +982,7 @@ class ContentFilterGuardrail(CustomGuardrail): if block_word_found: matched_phrase = f"{identifier_found} + {block_word_found}" verbose_proxy_logger.warning( - f"Conditional match in {category_name}: '{matched_phrase}' in sentence" + "Conditional match in %s: '%s' in sentence", category_name, matched_phrase ) return (matched_phrase, category_name, severity, action) @@ -1020,7 +1027,7 @@ class ContentFilterGuardrail(CustomGuardrail): for pattern_str, pattern in config.phrase_patterns: if pattern.search(text): - verbose_proxy_logger.warning(f"Phrase pattern match in {category_name}: '{pattern_str}'") + verbose_proxy_logger.warning("Phrase pattern match in %s: '%s'", category_name, pattern_str) return ( f"phrase: {pattern_str}", category_name, @@ -1048,7 +1055,7 @@ class ContentFilterGuardrail(CustomGuardrail): # Check exceptions first — they take precedence over always-block keywords too. for exception in exceptions: if exception in text_lower: - verbose_proxy_logger.debug(f"Exception phrase '{exception}' found, skipping category keyword check") + verbose_proxy_logger.debug("Exception phrase '%s' found, skipping category keyword check", exception) return None # Always-block keywords are checked after exceptions. @@ -1064,7 +1071,7 @@ class ContentFilterGuardrail(CustomGuardrail): keyword_pattern = r"\b" + keyword_pattern_str + r"\b" keyword_found = bool(re.search(keyword_pattern, text_lower)) if keyword_found: - verbose_proxy_logger.debug(f"Always-block keyword '{keyword}' found in category '{category}'") + verbose_proxy_logger.debug("Always-block keyword '%s' found in category '%s'", keyword, category) return (keyword, category, severity, action) # Check category keywords @@ -1095,7 +1102,7 @@ class ContentFilterGuardrail(CustomGuardrail): for exception in category_obj.exceptions: if exception in text_lower: verbose_proxy_logger.debug( - f"Category exception '{exception}' found for keyword '{keyword}', skipping" + "Category exception '%s' found for keyword '%s', skipping", exception, keyword ) exception_found = True break @@ -1103,7 +1110,7 @@ class ContentFilterGuardrail(CustomGuardrail): continue verbose_proxy_logger.debug( - f"Category keyword '{keyword}' found in category '{category}' with severity {severity}" + "Category keyword '%s' found in category '%s' with severity %s", keyword, category, severity ) return (keyword, category, severity, action) return None @@ -1140,7 +1147,7 @@ class ContentFilterGuardrail(CustomGuardrail): text_lower = text.lower() for keyword, (action, description) in self.blocked_words.items(): if keyword in text_lower: - verbose_proxy_logger.debug(f"Blocked word '{keyword}' found with action {action}") + verbose_proxy_logger.debug("Blocked word '%s' found with action %s", keyword, action) return (keyword, action, description) return None @@ -1179,7 +1186,9 @@ class ContentFilterGuardrail(CustomGuardrail): ) elif action == ContentFilterAction.MASK: verbose_proxy_logger.warning( - f"Conditional match '{matched_phrase}' from {category_name} detected but MASK action not supported for conditional categories" + "Conditional match '%s' from %s detected but MASK action not supported for conditional categories", + matched_phrase, + category_name, ) def _handle_category_keyword_match( @@ -1223,7 +1232,7 @@ class ContentFilterGuardrail(CustomGuardrail): flags=re.IGNORECASE, ) verbose_proxy_logger.info( - f"Masked category keyword '{keyword}' from {category_name} (severity: {severity})" + "Masked category keyword '%s' from %s (severity: %s)", keyword, category_name, severity ) return text @@ -1255,7 +1264,7 @@ class ContentFilterGuardrail(CustomGuardrail): elif action == ContentFilterAction.MASK: redaction_tag = self.pattern_redaction_format.format(pattern_name=pattern_name.upper()) text = self._mask_spans(text, spans, redaction_tag) - verbose_proxy_logger.info(f"Masked all {pattern_name} matches in content") + verbose_proxy_logger.info("Masked all %s matches in content", pattern_name) return text @@ -1268,7 +1277,7 @@ class ContentFilterGuardrail(CustomGuardrail): detections: list[ContentFilterDetection] | None, ) -> str: """Handle blocked word match detection and action.""" - verbose_proxy_logger.debug(f"Blocked word '{keyword}' found with action {action}") + verbose_proxy_logger.debug("Blocked word '%s' found with action %s", keyword, action) if detections is not None: blocked_word_detection: BlockedWordDetection = { @@ -1300,7 +1309,7 @@ class ContentFilterGuardrail(CustomGuardrail): text, flags=re.IGNORECASE, ) - verbose_proxy_logger.info(f"Masked keyword '{keyword}' in content") + verbose_proxy_logger.info("Masked keyword '%s' in content", keyword) return text @@ -1427,14 +1436,14 @@ class ContentFilterGuardrail(CustomGuardrail): message = getattr(choice, "message", None) if message and getattr(message, "content", None): image_description = message.content - verbose_proxy_logger.debug(f"Image description: {image_description}") + verbose_proxy_logger.debug("Image description: %s", image_description) descriptions.append(image_description) else: verbose_proxy_logger.warning("No image description found") # Apply content filtering to image descriptions verbose_proxy_logger.debug( - f"ContentFilterGuardrail: Applying guardrail to {len(descriptions)} image description(s)" + "ContentFilterGuardrail: Applying guardrail to %s image description(s)", len(descriptions) ) for description in descriptions: # This will raise HTTPException if BLOCK action is triggered @@ -1780,7 +1789,7 @@ class ContentFilterGuardrail(CustomGuardrail): await self._process_images(images, detections) # Process texts - verbose_proxy_logger.debug(f"ContentFilterGuardrail: Applying guardrail to {len(texts)} text(s)") + verbose_proxy_logger.debug("ContentFilterGuardrail: Applying guardrail to %s text(s)", len(texts)) processed_texts = [] for text in texts: @@ -1852,7 +1861,7 @@ class ContentFilterGuardrail(CustomGuardrail): exception_str: str = "" verbose_proxy_logger.info( - f"ContentFilterGuardrail: Starting robust streaming masking for model {request_data.get('model')}" + "ContentFilterGuardrail: Starting robust streaming masking for model %s", request_data.get("model") ) try: @@ -1897,7 +1906,7 @@ class ContentFilterGuardrail(CustomGuardrail): latest_detections_by_choice[choice_index] = choice_detections raise except Exception as e: - verbose_proxy_logger.error(f"ContentFilterGuardrail: Error in masking: {e}") + verbose_proxy_logger.error("ContentFilterGuardrail: Error in masking: %s", e) masked_text = text_to_scan # Fallback to current text # Determine how much can be safely yielded diff --git a/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/patterns.py b/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/patterns.py index 8292f575c74..6b1d7f6a93e 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/patterns.py +++ b/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/patterns.py @@ -168,7 +168,7 @@ def get_available_content_categories() -> list[dict[str, str]]: # Skip files that can't be loaded but log the error for debugging from litellm._logging import verbose_proxy_logger - verbose_proxy_logger.warning(f"Failed to load category file {filename}: {e}") + verbose_proxy_logger.warning("Failed to load category file %s: %s", filename, e) continue elif filename.endswith(".json"): # JSON category files (e.g. harm_toxic_abuse.json) - no YAML header, use filename diff --git a/litellm/proxy/guardrails/guardrail_hooks/llm_as_a_judge/__init__.py b/litellm/proxy/guardrails/guardrail_hooks/llm_as_a_judge/__init__.py index afbc67f2abb..725719048d7 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/llm_as_a_judge/__init__.py +++ b/litellm/proxy/guardrails/guardrail_hooks/llm_as_a_judge/__init__.py @@ -216,7 +216,9 @@ class LLMAsAJudgeGuardrail(CustomGuardrail): try: judge_result = await self._run_judge(messages, response_text) except Exception as judge_err: - verbose_logger.warning(f"llm_as_a_judge guardrail: judge call failed, failing open. Error: {judge_err}") + verbose_logger.warning( + "llm_as_a_judge guardrail: judge call failed, failing open. Error: %s", judge_err + ) status = "guardrail_failed_to_respond" return inputs @@ -263,7 +265,7 @@ class LLMAsAJudgeGuardrail(CustomGuardrail): except HTTPException: raise except Exception as e: - verbose_logger.warning(f"llm_as_a_judge guardrail unexpected error: {e}") + verbose_logger.warning("llm_as_a_judge guardrail unexpected error: %s", e) return inputs finally: self.add_standard_logging_guardrail_information_to_request_data( diff --git a/litellm/proxy/guardrails/guardrail_hooks/mcp_end_user_permission/mcp_end_user_permission.py b/litellm/proxy/guardrails/guardrail_hooks/mcp_end_user_permission/mcp_end_user_permission.py index 1760d01e247..08bd79a4a0c 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/mcp_end_user_permission/mcp_end_user_permission.py +++ b/litellm/proxy/guardrails/guardrail_hooks/mcp_end_user_permission/mcp_end_user_permission.py @@ -80,7 +80,7 @@ class MCPEndUserPermissionGuardrail(CustomGuardrail): if allowed_mcp_servers is None: return inputs # No restrictions → pass through unchanged - verbose_proxy_logger.debug(f"MCP guardrail: end user restricted to MCP servers: {allowed_mcp_servers}") + verbose_proxy_logger.debug("MCP guardrail: end user restricted to MCP servers: %s", allowed_mcp_servers) filtered_tools = [] removed_tools = [] @@ -97,13 +97,14 @@ class MCPEndUserPermissionGuardrail(CustomGuardrail): else: removed_tools.append(tool_name) verbose_proxy_logger.warning( - f"MCP guardrail: removing tool '{tool_name}' " - f"(server: '{server_name}') — not in end user's allowed servers" + "MCP guardrail: removing tool '%s' (server: '%s') — not in end user's allowed servers", + tool_name, + server_name, ) if removed_tools: verbose_proxy_logger.debug( - f"MCP guardrail: removed {len(removed_tools)} unauthorized MCP tool(s): {removed_tools}" + "MCP guardrail: removed %s unauthorized MCP tool(s): %s", len(removed_tools), removed_tools ) inputs["tools"] = filtered_tools @@ -162,7 +163,7 @@ class MCPEndUserPermissionGuardrail(CustomGuardrail): route="/mcp", ) except Exception as e: - verbose_proxy_logger.warning(f"MCP guardrail: failed to fetch end_user_object for '{end_user_id}': {e}") + verbose_proxy_logger.warning("MCP guardrail: failed to fetch end_user_object for '%s': %s", end_user_id, e) return None # ------------------------------------------------------------------ diff --git a/litellm/proxy/guardrails/guardrail_hooks/noma/noma.py b/litellm/proxy/guardrails/guardrail_hooks/noma/noma.py index b2f91083cc0..a1980134166 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/noma/noma.py +++ b/litellm/proxy/guardrails/guardrail_hooks/noma/noma.py @@ -163,7 +163,7 @@ class NomaGuardrail(CustomGuardrail): try: asyncio.create_task(coro) except Exception as e: - verbose_proxy_logger.error(f"Failed to create background Noma task: {e}") + verbose_proxy_logger.error("Failed to create background Noma task: %s", e) async def _process_user_message_check( self, @@ -233,7 +233,7 @@ class NomaGuardrail(CustomGuardrail): if anonymized_content: # Replace the user message content with anonymized version self._replace_user_message_content(request_data, anonymized_content) - verbose_proxy_logger.debug(f"Noma guardrail anonymized user message: {anonymized_content}") + verbose_proxy_logger.debug("Noma guardrail anonymized user message: %s", anonymized_content) return anonymized_content await self._check_verdict(USER_ROLE, json.dumps(input_items), response_json) @@ -309,7 +309,7 @@ class NomaGuardrail(CustomGuardrail): if anonymized_content: # Replace the LLM response content with anonymized version self._replace_llm_response_content(response, anonymized_content) - verbose_proxy_logger.debug(f"Noma guardrail anonymized LLM response: {anonymized_content}") + verbose_proxy_logger.debug("Noma guardrail anonymized LLM response: %s", anonymized_content) return anonymized_content await self._check_verdict(ASSISTANT_ROLE, content, response_json) @@ -348,7 +348,7 @@ class NomaGuardrail(CustomGuardrail): return "guardrail_failed_to_respond" except Exception as e: - verbose_proxy_logger.error(f"Error determining NOMA guardrail status: {e}") + verbose_proxy_logger.error("Error determining NOMA guardrail status: %s", e) return "guardrail_failed_to_respond" def _should_only_sensitive_data_failed(self, classification_obj: dict) -> bool: @@ -513,7 +513,7 @@ class NomaGuardrail(CustomGuardrail): try: await self._process_user_message_check(request_data, user_auth) except Exception as e: - verbose_proxy_logger.error(f"Noma background user message check failed: {e}") + verbose_proxy_logger.error("Noma background user message check failed: %s", e) async def _check_llm_response_background( self, @@ -525,7 +525,7 @@ class NomaGuardrail(CustomGuardrail): try: await self._process_llm_response_check(request_data, response, user_auth) except Exception as e: - verbose_proxy_logger.error(f"Noma background response check failed: {e}") + verbose_proxy_logger.error("Noma background response check failed: %s", e) async def _handle_verdict_background( self, @@ -547,7 +547,7 @@ class NomaGuardrail(CustomGuardrail): msg = f"Noma guardrail allowed {type} message: {message}" verbose_proxy_logger.info(msg) except Exception as e: - verbose_proxy_logger.error(f"Noma background verdict handling failed: {e}") + verbose_proxy_logger.error("Noma background verdict handling failed: %s", e) async def async_pre_call_hook( self, @@ -570,7 +570,7 @@ class NomaGuardrail(CustomGuardrail): try: self._create_background_noma_check(self._check_user_message_background(data, user_api_key_dict)) except Exception as e: - verbose_proxy_logger.error(f"Failed to start background Noma pre-call check: {e}") + verbose_proxy_logger.error("Failed to start background Noma pre-call check: %s", e) return data try: @@ -594,7 +594,7 @@ class NomaGuardrail(CustomGuardrail): event_type=GuardrailEventHooks.pre_call, ) - verbose_proxy_logger.error(f"Noma pre-call hook failed: {e}") + verbose_proxy_logger.error("Noma pre-call hook failed: %s", e) if self.block_failures: raise @@ -618,7 +618,7 @@ class NomaGuardrail(CustomGuardrail): try: self._create_background_noma_check(self._check_user_message_background(data, user_api_key_dict)) except Exception as e: - verbose_proxy_logger.error(f"Failed to start background Noma moderation check: {e}") + verbose_proxy_logger.error("Failed to start background Noma moderation check: %s", e) return data try: @@ -642,7 +642,7 @@ class NomaGuardrail(CustomGuardrail): event_type=GuardrailEventHooks.during_call, ) - verbose_proxy_logger.error(f"Noma moderation hook failed: {e}") + verbose_proxy_logger.error("Noma moderation hook failed: %s", e) if self.block_failures: raise @@ -665,7 +665,7 @@ class NomaGuardrail(CustomGuardrail): self._check_llm_response_background(data, response, user_api_key_dict) ) except Exception as e: - verbose_proxy_logger.error(f"Failed to start background Noma post-call check: {e}") + verbose_proxy_logger.error("Failed to start background Noma post-call check: %s", e) return response try: @@ -689,7 +689,7 @@ class NomaGuardrail(CustomGuardrail): event_type=GuardrailEventHooks.post_call, ) - verbose_proxy_logger.error(f"Noma post-call hook failed: {e}") + verbose_proxy_logger.error("Noma post-call hook failed: %s", e) if self.block_failures: raise return response @@ -828,7 +828,7 @@ class NomaGuardrail(CustomGuardrail): except Exception as e: if self.block_failures: raise - verbose_proxy_logger.error(f"Noma streaming post-call hook failed: {e}") + verbose_proxy_logger.error("Noma streaming post-call hook failed: %s", e) for chunk in all_chunks: yield chunk return diff --git a/litellm/proxy/guardrails/guardrail_hooks/onyx/onyx.py b/litellm/proxy/guardrails/guardrail_hooks/onyx/onyx.py index 37ce84b8e6e..7f6787015f6 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/onyx/onyx.py +++ b/litellm/proxy/guardrails/guardrail_hooks/onyx/onyx.py @@ -59,7 +59,7 @@ class OnyxGuardrail(CustomGuardrail): raise ValueError("ONYX_API_KEY environment variable is not set") self.optional_params = kwargs super().__init__(**kwargs) - verbose_proxy_logger.info(f"OnyxGuard initialized with server: {self.api_base}") + verbose_proxy_logger.info("OnyxGuard initialized with server: %s", self.api_base) async def _validate_with_guard_server( self, @@ -87,7 +87,7 @@ class OnyxGuardrail(CustomGuardrail): detection_message = "Unknown violation" if "violated_rules" in result: detection_message = ", ".join(result["violated_rules"]) - verbose_proxy_logger.warning(f"Request blocked by Onyx Guard. Violations: {detection_message}.") + verbose_proxy_logger.warning("Request blocked by Onyx Guard. Violations: %s.", detection_message) raise HTTPException( status_code=400, detail=f"Request blocked by Onyx Guard. Violations: {detection_message}.", @@ -118,7 +118,8 @@ class OnyxGuardrail(CustomGuardrail): payload = parsed.get("response", {}) except Exception as e: verbose_proxy_logger.error( - f"Error in converting request_data to ModelResponse: {e}", + "Error in converting request_data to ModelResponse: %s", + e, extra={ "conversation_id": conversation_id, "input_type": input_type, @@ -133,7 +134,8 @@ class OnyxGuardrail(CustomGuardrail): raise e except Exception as e: verbose_proxy_logger.error( - f"Error in apply_guardrail guard: {e}", + "Error in apply_guardrail guard: %s", + e, extra={"conversation_id": conversation_id, "input_type": input_type}, ) return inputs diff --git a/litellm/proxy/guardrails/guardrail_hooks/openai/moderations.py b/litellm/proxy/guardrails/guardrail_hooks/openai/moderations.py index 5ff04864e75..31d777ff089 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/openai/moderations.py +++ b/litellm/proxy/guardrails/guardrail_hooks/openai/moderations.py @@ -87,7 +87,7 @@ class OpenAIModerationGuardrail(OpenAIGuardrailBase, CustomGuardrail): ) verbose_proxy_logger.debug( - f"Initialized OpenAI Moderation Guardrail: {guardrail_name} with model: {self.model}" + "Initialized OpenAI Moderation Guardrail: %s with model: %s", guardrail_name, self.model ) def _get_api_key(self) -> str | None: diff --git a/litellm/proxy/guardrails/guardrail_hooks/pangea/pangea.py b/litellm/proxy/guardrails/guardrail_hooks/pangea/pangea.py index 5c707153873..09e24cca9d8 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/pangea/pangea.py +++ b/litellm/proxy/guardrails/guardrail_hooks/pangea/pangea.py @@ -94,7 +94,10 @@ class PangeaHandler(CustomGuardrail): **kwargs, ) verbose_proxy_logger.debug( - f"Initialized Pangea Guardrail: name={guardrail_name}, recipe={pangea_input_recipe}, api_base={self.api_base}" + "Initialized Pangea Guardrail: name=%s, recipe=%s, api_base=%s", + guardrail_name, + pangea_input_recipe, + self.api_base, ) async def _call_pangea_ai_guard(self, api: str, payload: dict, hook_name: str) -> dict: @@ -125,7 +128,7 @@ class PangeaHandler(CustomGuardrail): } verbose_proxy_logger.debug( - f"Pangea Guardrail ({hook_name}): Calling endpoint {endpoint} with payload: {payload}" + "Pangea Guardrail (%s): Calling endpoint %s with payload: %s", hook_name, endpoint, payload ) response = await self.async_handler.post(url=endpoint, json=payload, headers=headers) @@ -134,7 +137,7 @@ class PangeaHandler(CustomGuardrail): result = response.json() if result.get("result", {}).get("blocked"): - verbose_proxy_logger.warning(f"Pangea Guardrail ({hook_name}): Request blocked. Response: {result}") + verbose_proxy_logger.warning("Pangea Guardrail (%s): Request blocked. Response: %s", hook_name, result) raise HTTPException( status_code=400, # Bad Request, indicating violation detail={ @@ -143,7 +146,7 @@ class PangeaHandler(CustomGuardrail): }, ) verbose_proxy_logger.debug( - f"Pangea Guardrail ({hook_name}): Request passed. Response: {result.get('result', {}).get('detectors')}" + "Pangea Guardrail (%s): Request passed. Response: %s", hook_name, result.get("result", {}).get("detectors") ) return result @@ -195,7 +198,7 @@ class PangeaHandler(CustomGuardrail): event_type = GuardrailEventHooks.pre_call if self.should_run_guardrail(data=data, event_type=event_type) is not True: verbose_proxy_logger.debug( - f"Pangea Guardrail (async_pre_call_hook): Guardrail is disabled {self.guardrail_name}." + "Pangea Guardrail (async_pre_call_hook): Guardrail is disabled %s.", self.guardrail_name ) return data @@ -286,7 +289,7 @@ class PangeaHandler(CustomGuardrail): event_type = GuardrailEventHooks.post_call if self.should_run_guardrail(data=data, event_type=event_type) is not True: verbose_proxy_logger.debug( - f"Pangea Guardrail (async_pre_call_hook): Guardrail is disabled {self.guardrail_name}." + "Pangea Guardrail (async_pre_call_hook): Guardrail is disabled %s.", self.guardrail_name ) return data try: diff --git a/litellm/proxy/guardrails/guardrail_hooks/panw_prisma_airs/panw_prisma_airs.py b/litellm/proxy/guardrails/guardrail_hooks/panw_prisma_airs/panw_prisma_airs.py index 782ffef61cf..64831c8161f 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/panw_prisma_airs/panw_prisma_airs.py +++ b/litellm/proxy/guardrails/guardrail_hooks/panw_prisma_airs/panw_prisma_airs.py @@ -122,10 +122,8 @@ class PanwPrismaAirsHandler(CustomGuardrail): # Warn if no profile is configured (user must have API key with linked profile) if not self.profile_name: verbose_proxy_logger.warning( - f"PANW Prisma AIRS Guardrail '{guardrail_name}': No profile_name configured. " - f"Ensure your API key has a linked profile in Strata Cloud Manager, " - f"or provide 'profile_name'/'profile_id' via config or per-request metadata. " - f"Requests will fail if the API key is not linked to a profile." + "PANW Prisma AIRS Guardrail '%s': No profile_name configured. Ensure your API key has a linked profile in Strata Cloud Manager, or provide 'profile_name'/'profile_id' via config or per-request metadata. Requests will fail if the API key is not linked to a profile.", + guardrail_name, ) self.fallback_on_error = fallback_on_error @@ -143,15 +141,18 @@ class PanwPrismaAirsHandler(CustomGuardrail): if self.fallback_on_error == "allow": verbose_proxy_logger.warning( - f"PANW Prisma AIRS Guardrail '{guardrail_name}': fallback_on_error='allow' - " - f"requests will proceed without scanning when API is unavailable." + "PANW Prisma AIRS Guardrail '%s': fallback_on_error='allow' - requests will proceed without scanning when API is unavailable.", + guardrail_name, ) verbose_proxy_logger.info( - f"Initialized PANW Prisma AIRS Guardrail: {guardrail_name} " - f"(profile={self.profile_name or 'API-key-linked'}, " - f"mask_request={self.mask_request_content}, mask_response={self.mask_response_content}, " - f"fallback_on_error={self.fallback_on_error}, timeout={self.timeout})" + "Initialized PANW Prisma AIRS Guardrail: %s (profile=%s, mask_request=%s, mask_response=%s, fallback_on_error=%s, timeout=%s)", + guardrail_name, + self.profile_name or "API-key-linked", + self.mask_request_content, + self.mask_response_content, + self.fallback_on_error, + self.timeout, ) # MCP event → base-call compatibility map. @@ -231,7 +232,7 @@ class PanwPrismaAirsHandler(CustomGuardrail): return " ".join(text_parts) if text_parts else "" except (AttributeError, IndexError) as e: - verbose_proxy_logger.error(f"PANW Prisma AIRS: Error extracting response text: {e}") + verbose_proxy_logger.error("PANW Prisma AIRS: Error extracting response text: %s", e) return "" async def _call_panw_api( @@ -355,7 +356,7 @@ class PanwPrismaAirsHandler(CustomGuardrail): # Validate response format if "action" not in result: - verbose_proxy_logger.error(f"PANW Prisma AIRS: Invalid API response format: {result}") + verbose_proxy_logger.error("PANW Prisma AIRS: Invalid API response format: %s", result) return {"action": "block", "category": "api_error"} # Check for profile-related errors from PANW API @@ -365,14 +366,14 @@ class PanwPrismaAirsHandler(CustomGuardrail): "not found" in error_msg or "required" in error_msg or "invalid" in error_msg ): verbose_proxy_logger.error( - f"PANW Prisma AIRS: Profile configuration error. " - f"Ensure your API key has a linked profile in Strata Cloud Manager, " - f"or provide 'profile_name' or 'profile_id' in config/metadata. " - f"PANW API response: {result}" + "PANW Prisma AIRS: Profile configuration error. Ensure your API key has a linked profile in Strata Cloud Manager, or provide 'profile_name' or 'profile_id' in config/metadata. PANW API response: %s", + result, ) verbose_proxy_logger.debug( - f"PANW Prisma AIRS: Scan result - Action: {result.get('action')}, Category: {result.get('category', 'unknown')}" + "PANW Prisma AIRS: Scan result - Action: %s, Category: %s", + result.get("action"), + result.get("category", "unknown"), ) return result @@ -406,8 +407,8 @@ class PanwPrismaAirsHandler(CustomGuardrail): if status in (401, 403) or is_profile_error: verbose_proxy_logger.error( - f"PANW Prisma AIRS: Authentication/config error (HTTP {status}). " - f"Check API key and profile configuration." + "PANW Prisma AIRS: Authentication/config error (HTTP %s). Check API key and profile configuration.", + status, ) return { "action": "block", @@ -416,7 +417,7 @@ class PanwPrismaAirsHandler(CustomGuardrail): } elif status == 429 or status >= 500: # Transient: rate-limit and server errors — safe to fail-open - verbose_proxy_logger.error(f"PANW Prisma AIRS: API error (HTTP {status}): {error_body[:500]}") + verbose_proxy_logger.error("PANW Prisma AIRS: API error (HTTP %s): %s", status, error_body[:500]) return { "action": "block", "category": f"http_{status}_error", @@ -425,7 +426,7 @@ class PanwPrismaAirsHandler(CustomGuardrail): else: # Permanent 4xx client errors (400, 404, etc.) — must not bypass scanning if status != 400: # 400 already logged with diagnostics above - verbose_proxy_logger.error(f"PANW Prisma AIRS: API error (HTTP {status}): {error_body[:500]}") + verbose_proxy_logger.error("PANW Prisma AIRS: API error (HTTP %s): %s", status, error_body[:500]) return { "action": "block", "category": f"http_{status}_error", @@ -433,7 +434,7 @@ class PanwPrismaAirsHandler(CustomGuardrail): } except httpx.TimeoutException as e: - verbose_proxy_logger.error(f"PANW Prisma AIRS: Timeout error: {e}") + verbose_proxy_logger.error("PANW Prisma AIRS: Timeout error: %s", e) return { "action": "block", "category": "timeout_error", @@ -441,7 +442,7 @@ class PanwPrismaAirsHandler(CustomGuardrail): } except httpx.RequestError as e: - verbose_proxy_logger.error(f"PANW Prisma AIRS: Network/request error: {e}") + verbose_proxy_logger.error("PANW Prisma AIRS: Network/request error: %s", e) return { "action": "block", "category": "network_error", @@ -449,7 +450,7 @@ class PanwPrismaAirsHandler(CustomGuardrail): } except Exception as e: - verbose_proxy_logger.error(f"PANW Prisma AIRS: Unexpected error: {e}") + verbose_proxy_logger.error("PANW Prisma AIRS: Unexpected error: %s", e) return {"action": "block", "category": "api_error", "_is_transient": True} @staticmethod @@ -713,8 +714,9 @@ class PanwPrismaAirsHandler(CustomGuardrail): if scan_result.get("_is_transient") and self.fallback_on_error == "allow": verbose_proxy_logger.warning( - f"PANW Prisma AIRS: Allowing {'response' if is_response else 'request'} " - f"without scanning (fallback_on_error='allow', error: {category})" + "PANW Prisma AIRS: Allowing %s without scanning (fallback_on_error='allow', error: %s)", + "response" if is_response else "request", + category, ) add_guardrail_to_applied_guardrails_header( request_data=data, guardrail_name=f"{self.guardrail_name}:unscanned" @@ -915,7 +917,7 @@ class PanwPrismaAirsHandler(CustomGuardrail): litellm_metadata = data.setdefault("litellm_metadata", {}) if litellm_metadata.get(scan_key): - verbose_proxy_logger.debug(f"PANW Prisma AIRS: Skipping duplicate {scan_type}-call scan") + verbose_proxy_logger.debug("PANW Prisma AIRS: Skipping duplicate %s-call scan", scan_type) return True # Already scanned litellm_metadata[scan_key] = True @@ -1030,9 +1032,9 @@ class PanwPrismaAirsHandler(CustomGuardrail): data["messages"] = self._apply_masking_to_messages(messages, masked_text) elif "prompt" in data: data["prompt"] = masked_text - verbose_proxy_logger.info(f"PANW Prisma AIRS: Prompt allowed with masking (Category: {category})") + verbose_proxy_logger.info("PANW Prisma AIRS: Prompt allowed with masking (Category: %s)", category) else: - verbose_proxy_logger.info(f"PANW Prisma AIRS: Prompt allowed (Category: {category})") + verbose_proxy_logger.info("PANW Prisma AIRS: Prompt allowed (Category: %s)", category) add_guardrail_to_applied_guardrails_header(request_data=data, guardrail_name=self.guardrail_name) return None @@ -1050,13 +1052,13 @@ class PanwPrismaAirsHandler(CustomGuardrail): # Block the request error_detail = self._build_error_detail(scan_result, is_response=False) - verbose_proxy_logger.warning(f"PANW Prisma AIRS: {error_detail['error']['message']}") + verbose_proxy_logger.warning("PANW Prisma AIRS: %s", error_detail["error"]["message"]) raise HTTPException(status_code=400, detail=error_detail) except HTTPException: raise except Exception as e: - verbose_proxy_logger.error(f"PANW Prisma AIRS scan failed: {e}") + verbose_proxy_logger.error("PANW Prisma AIRS scan failed: %s", e) raise HTTPException( status_code=500, detail={ @@ -1147,9 +1149,11 @@ class PanwPrismaAirsHandler(CustomGuardrail): if action == "allow": if masked_text: self._apply_masking_to_response(response, masked_text) - verbose_proxy_logger.info(f"PANW Prisma AIRS: Response allowed with masking (Category: {category})") + verbose_proxy_logger.info( + "PANW Prisma AIRS: Response allowed with masking (Category: %s)", category + ) else: - verbose_proxy_logger.info(f"PANW Prisma AIRS: Response allowed (Category: {category})") + verbose_proxy_logger.info("PANW Prisma AIRS: Response allowed (Category: %s)", category) add_guardrail_to_applied_guardrails_header(request_data=data, guardrail_name=self.guardrail_name) return response @@ -1164,13 +1168,13 @@ class PanwPrismaAirsHandler(CustomGuardrail): # Block the response error_detail = self._build_error_detail(scan_result, is_response=True) - verbose_proxy_logger.warning(f"PANW Prisma AIRS: {error_detail['error']['message']}") + verbose_proxy_logger.warning("PANW Prisma AIRS: %s", error_detail["error"]["message"]) raise HTTPException(status_code=400, detail=error_detail) except HTTPException: raise except Exception as e: - verbose_proxy_logger.error(f"PANW Prisma AIRS scan failed: {e}") + verbose_proxy_logger.error("PANW Prisma AIRS scan failed: %s", e) raise HTTPException( status_code=500, detail={ @@ -1229,10 +1233,10 @@ class PanwPrismaAirsHandler(CustomGuardrail): self._apply_masking_to_response(assembled_model_response, masked_text) content_was_modified = True verbose_proxy_logger.info( - f"PANW Prisma AIRS: Streaming response allowed with masking (Category: {category})" + "PANW Prisma AIRS: Streaming response allowed with masking (Category: %s)", category ) else: - verbose_proxy_logger.info(f"PANW Prisma AIRS: Streaming response allowed (Category: {category})") + verbose_proxy_logger.info("PANW Prisma AIRS: Streaming response allowed (Category: %s)", category) elif masked_text and self.mask_response_content: self._apply_masking_to_response(assembled_model_response, masked_text) content_was_modified = True @@ -1241,7 +1245,7 @@ class PanwPrismaAirsHandler(CustomGuardrail): ) else: error_detail = self._build_error_detail(scan_result, is_response=True) - verbose_proxy_logger.warning(f"PANW Prisma AIRS: {error_detail['error']['message']}") + verbose_proxy_logger.warning("PANW Prisma AIRS: %s", error_detail["error"]["message"]) raise HTTPException(status_code=400, detail=error_detail) return content_was_modified, assembled_model_response, scan_result @@ -1366,7 +1370,7 @@ class PanwPrismaAirsHandler(CustomGuardrail): error_obj["code"] = e.status_code yield f"data: {json.dumps({'error': error_obj})}\n\n" except Exception as e: - verbose_proxy_logger.error(f"PANW Prisma AIRS streaming error: {e}") + verbose_proxy_logger.error("PANW Prisma AIRS streaming error: %s", e) yield f"data: {json.dumps({'error': {'message': 'Security scan failed - streaming response blocked for safety', 'type': 'guardrail_scan_error', 'code': 500, 'guardrail': self.guardrail_name}})}\n\n" async def _scan_tool_calls_for_guardrail( diff --git a/litellm/proxy/guardrails/guardrail_hooks/pillar/pillar.py b/litellm/proxy/guardrails/guardrail_hooks/pillar/pillar.py index 77767c8c61b..058b0a2f23c 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/pillar/pillar.py +++ b/litellm/proxy/guardrails/guardrail_hooks/pillar/pillar.py @@ -209,10 +209,10 @@ class PillarGuardrail(CustomGuardrail): self.on_flagged_action = action else: if action: - verbose_proxy_logger.warning(f"Invalid action '{action}', using default") + verbose_proxy_logger.warning("Invalid action '%s', using default", action) self.on_flagged_action = self.DEFAULT_ON_FLAGGED_ACTION - verbose_proxy_logger.debug(f"Pillar Guardrail: Initialized with on_flagged_action: {self.on_flagged_action}") + verbose_proxy_logger.debug("Pillar Guardrail: Initialized with on_flagged_action: %s", self.on_flagged_action) self.async_mode = self._resolve_bool_config( provided_value=async_mode, @@ -246,11 +246,11 @@ class PillarGuardrail(CustomGuardrail): else: if action: verbose_proxy_logger.warning( - f"Invalid fallback action '{action}', using default '{self.DEFAULT_FALLBACK_ACTION}'" + "Invalid fallback action '%s', using default '%s'", action, self.DEFAULT_FALLBACK_ACTION ) self.fallback_on_error = self.DEFAULT_FALLBACK_ACTION - verbose_proxy_logger.debug(f"Pillar Guardrail: Initialized with fallback_on_error: {self.fallback_on_error}") + verbose_proxy_logger.debug("Pillar Guardrail: Initialized with fallback_on_error: %s", self.fallback_on_error) # Set timeout with graceful fallback on invalid configuration if timeout is not None: @@ -260,8 +260,9 @@ class PillarGuardrail(CustomGuardrail): self.timeout = float(os.environ.get("PILLAR_TIMEOUT", str(self.DEFAULT_TIMEOUT))) except (ValueError, TypeError): verbose_proxy_logger.warning( - f"Pillar Guardrail: Invalid PILLAR_TIMEOUT value '{os.environ.get('PILLAR_TIMEOUT')}', " - f"falling back to default {self.DEFAULT_TIMEOUT}s" + "Pillar Guardrail: Invalid PILLAR_TIMEOUT value '%s', falling back to default %ss", + os.environ.get("PILLAR_TIMEOUT"), + self.DEFAULT_TIMEOUT, ) self.timeout = self.DEFAULT_TIMEOUT @@ -311,7 +312,7 @@ class PillarGuardrail(CustomGuardrail): """ event_type = GuardrailEventHooks.pre_call if self.should_run_guardrail(data=data, event_type=event_type) is not True: - verbose_proxy_logger.debug(f"Pillar Guardrail: Pre-call scanning disabled for {self.guardrail_name}") + verbose_proxy_logger.debug("Pillar Guardrail: Pre-call scanning disabled for %s", self.guardrail_name) return data verbose_proxy_logger.debug("Pillar Guardrail: Pre-call hook") @@ -354,7 +355,7 @@ class PillarGuardrail(CustomGuardrail): """ event_type = GuardrailEventHooks.during_call if self.should_run_guardrail(data=data, event_type=event_type) is not True: - verbose_proxy_logger.debug(f"Pillar Guardrail: During-call scanning disabled for {self.guardrail_name}") + verbose_proxy_logger.debug("Pillar Guardrail: During-call scanning disabled for %s", self.guardrail_name) return data verbose_proxy_logger.debug("Pillar Guardrail: During-call moderation hook") @@ -388,7 +389,7 @@ class PillarGuardrail(CustomGuardrail): """ event_type = GuardrailEventHooks.post_call if self.should_run_guardrail(data=data, event_type=event_type) is not True: - verbose_proxy_logger.debug(f"Pillar Guardrail: Post-call scanning disabled for {self.guardrail_name}") + verbose_proxy_logger.debug("Pillar Guardrail: Post-call scanning disabled for %s", self.guardrail_name) return response verbose_proxy_logger.debug("Pillar Guardrail: Post-call hook") @@ -457,7 +458,7 @@ class PillarGuardrail(CustomGuardrail): raise e # Handle API communication errors based on fallback_on_error setting - verbose_proxy_logger.error(f"Pillar Guardrail: API communication failed - {e}") + verbose_proxy_logger.error("Pillar Guardrail: API communication failed - %s", e) return self._handle_api_error(e, data) @@ -677,8 +678,11 @@ class PillarGuardrail(CustomGuardrail): payload["provider"] = provider verbose_proxy_logger.debug( - f"Pillar Guardrail: Request context - user={user_id}, session={session_id}, " - f"model={model}, provider={provider}" + "Pillar Guardrail: Request context - user=%s, session=%s, model=%s, provider=%s", + user_id, + session_id, + model, + provider, ) return payload @@ -694,7 +698,7 @@ class PillarGuardrail(CustomGuardrail): Pillar API response as dictionary """ verbose_proxy_logger.debug( - f"Pillar Guardrail: Scanning {len(payload.get('messages', []))} messages for security threats" + "Pillar Guardrail: Scanning %s messages for security threats", len(payload.get("messages", [])) ) response = await self.async_handler.post( url=f"{self.api_base}/api/v1/protect", @@ -707,7 +711,7 @@ class PillarGuardrail(CustomGuardrail): flagged = res.get("flagged") session_id = res.get("session_id") - verbose_proxy_logger.debug(f"Pillar Guardrail: Analysis complete - flagged={flagged}, session={session_id}") + verbose_proxy_logger.debug("Pillar Guardrail: Analysis complete - flagged=%s, session=%s", flagged, session_id) return res def _process_pillar_response(self, pillar_response: dict[str, Any], original_data: dict) -> None: @@ -739,7 +743,7 @@ class PillarGuardrail(CustomGuardrail): # Store session_id from Pillar response for potential reuse pillar_session_id = pillar_response.get("session_id") if pillar_session_id: - verbose_proxy_logger.debug(f"Pillar Guardrail: Received session_id from server: {pillar_session_id}") + verbose_proxy_logger.debug("Pillar Guardrail: Received session_id from server: %s", pillar_session_id) # Store in request metadata for use in subsequent hooks if "pillar_session_id" not in metadata_store: metadata_store["pillar_session_id"] = pillar_session_id diff --git a/litellm/proxy/guardrails/guardrail_hooks/presidio.py b/litellm/proxy/guardrails/guardrail_hooks/presidio.py index 7a38c4087c6..56f08fe44ca 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/presidio.py +++ b/litellm/proxy/guardrails/guardrail_hooks/presidio.py @@ -740,7 +740,7 @@ class _OPTIONAL_PresidioPIIMasking(CustomGuardrail): elif isinstance(content, list) and content_idx_optional is not None: messages[msg_idx]["content"][content_idx_optional]["text"] = r - verbose_proxy_logger.debug(f"Presidio PII Masking: Redacted pii message: {data['messages']}") + verbose_proxy_logger.debug("Presidio PII Masking: Redacted pii message: %s", data["messages"]) data["messages"] = messages return data except Exception as e: @@ -832,7 +832,7 @@ class _OPTIONAL_PresidioPIIMasking(CustomGuardrail): elif isinstance(content, list) and content_idx_optional is not None: messages[msg_idx]["content"][content_idx_optional]["text"] = r - verbose_proxy_logger.debug(f"Presidio PII Masking: Redacted pii message: {messages}") + verbose_proxy_logger.debug("Presidio PII Masking: Redacted pii message: %s", messages) kwargs["messages"] = messages return kwargs, result @@ -847,7 +847,7 @@ class _OPTIONAL_PresidioPIIMasking(CustomGuardrail): Output parse the response object to replace the masked tokens with user sent values """ verbose_proxy_logger.debug( - f"PII Masking Args: self.output_parse_pii={self.output_parse_pii}; type of response={type(response)}" + "PII Masking Args: self.output_parse_pii=%s; type of response=%s", self.output_parse_pii, type(response) ) if self.apply_to_output is True: @@ -1124,7 +1124,7 @@ class _OPTIONAL_PresidioPIIMasking(CustomGuardrail): yield mock_response_stream except Exception as e: - verbose_proxy_logger.error(f"Error masking streaming PII output: {e}") + verbose_proxy_logger.error("Error masking streaming PII output: %s", e) for chunk in all_chunks: yield chunk @@ -1253,7 +1253,7 @@ class _OPTIONAL_PresidioPIIMasking(CustomGuardrail): yield mock_response_stream except Exception as e: - verbose_proxy_logger.error(f"Error in PII streaming processing: {e}") + verbose_proxy_logger.error("Error in PII streaming processing: %s", e) for chunk in remaining_chunks: yield chunk diff --git a/litellm/proxy/guardrails/guardrail_hooks/prompt_security/prompt_security.py b/litellm/proxy/guardrails/guardrail_hooks/prompt_security/prompt_security.py index 0f3a817b12c..a816ef3846e 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/prompt_security/prompt_security.py +++ b/litellm/proxy/guardrails/guardrail_hooks/prompt_security/prompt_security.py @@ -326,7 +326,7 @@ class PromptSecurityGuardrail(CustomGuardrail): except HTTPException: raise except Exception as e: - verbose_proxy_logger.error(f"Error processing image: {e}") + verbose_proxy_logger.error("Error processing image: %s", e) @staticmethod def _resolve_key_alias_from_request_data(request_data: dict) -> str | None: @@ -481,7 +481,7 @@ class PromptSecurityGuardrail(CustomGuardrail): except HTTPException: raise except Exception as e: - verbose_proxy_logger.error(f"Error sanitizing image file: {e}") + verbose_proxy_logger.error("Error sanitizing image file: %s", e) raise HTTPException(status_code=500, detail=f"File sanitization failed: {e}") async def _process_document_item(self, item: dict, user_api_key_alias: str | None) -> dict: @@ -520,7 +520,7 @@ class PromptSecurityGuardrail(CustomGuardrail): extension = mime_type.split("/")[-1] filename = f"document.{extension}" - verbose_proxy_logger.info(f"Sanitizing document: {filename}") + verbose_proxy_logger.info("Sanitizing document: %s", filename) sanitization_result = await self.sanitize_file_content( file_data, filename, user_api_key_alias=user_api_key_alias @@ -554,7 +554,7 @@ class PromptSecurityGuardrail(CustomGuardrail): except HTTPException: raise except Exception as e: - verbose_proxy_logger.error(f"Error sanitizing document: {e}") + verbose_proxy_logger.error("Error sanitizing document: %s", e) raise HTTPException(status_code=500, detail=f"Document sanitization failed: {e}") async def process_message_files(self, messages: list, user_api_key_alias: str | None = None) -> list: diff --git a/litellm/proxy/guardrails/guardrail_hooks/qualifire/qualifire.py b/litellm/proxy/guardrails/guardrail_hooks/qualifire/qualifire.py index fe2cc40074f..c93cc3f36f3 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/qualifire/qualifire.py +++ b/litellm/proxy/guardrails/guardrail_hooks/qualifire/qualifire.py @@ -344,7 +344,7 @@ class QualifireGuardrail(CustomGuardrail): ) url = f"{self.qualifire_api_base}/api/evaluation/evaluate" - verbose_proxy_logger.debug(f"Qualifire Guardrail: Making request to {url}") + verbose_proxy_logger.debug("Qualifire Guardrail: Making request to %s", url) # Make the API request response = await self.async_handler.post( @@ -373,8 +373,8 @@ class QualifireGuardrail(CustomGuardrail): if is_flagged: if on_flagged == "monitor": verbose_proxy_logger.warning( - "Qualifire Guardrail: Monitoring mode - violation detected but allowing request. " - f"Response: {qualifire_response}" + "Qualifire Guardrail: Monitoring mode - violation detected but allowing request. Response: %s", + qualifire_response, ) else: # Block the request @@ -389,7 +389,7 @@ class QualifireGuardrail(CustomGuardrail): except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Qualifire Guardrail error: {e}") + verbose_proxy_logger.exception("Qualifire Guardrail error: %s", e) raise @log_guardrail_information diff --git a/litellm/proxy/guardrails/guardrail_hooks/semantic_guard/route_loader.py b/litellm/proxy/guardrails/guardrail_hooks/semantic_guard/route_loader.py index c30b2b0910c..056489de70f 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/semantic_guard/route_loader.py +++ b/litellm/proxy/guardrails/guardrail_hooks/semantic_guard/route_loader.py @@ -112,7 +112,7 @@ class SemanticGuardRouteLoader: ) ) - verbose_logger.info(f"SemanticGuard: built {len(routes)} routes") + verbose_logger.info("SemanticGuard: built %s routes", len(routes)) return routes @classmethod diff --git a/litellm/proxy/guardrails/guardrail_hooks/semantic_guard/semantic_guard.py b/litellm/proxy/guardrails/guardrail_hooks/semantic_guard/semantic_guard.py index f57827d03c9..1657485ed78 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/semantic_guard/semantic_guard.py +++ b/litellm/proxy/guardrails/guardrail_hooks/semantic_guard/semantic_guard.py @@ -89,8 +89,11 @@ class SemanticGuardrail(CustomGuardrail): self.route_count = len(routes) verbose_logger.info( - f"SemanticGuardrail '{guardrail_name}' initialized with {self.route_count} routes, " - f"embedding_model={embedding_model}, threshold={similarity_threshold}" + "SemanticGuardrail '%s' initialized with %s routes, embedding_model=%s, threshold=%s", + guardrail_name, + self.route_count, + embedding_model, + similarity_threshold, ) @classmethod @@ -219,7 +222,7 @@ def _handle_match( } verbose_logger.warning( - f"SemanticGuard match: route={route_name}, score={similarity_score}, action={guardrail.on_flagged_action}" + "SemanticGuard match: route=%s, score=%s, action=%s", route_name, similarity_score, guardrail.on_flagged_action ) if guardrail.on_flagged_action == "passthrough": diff --git a/litellm/proxy/guardrails/guardrail_hooks/tool_permission.py b/litellm/proxy/guardrails/guardrail_hooks/tool_permission.py index b15e5b61243..b3cfa0ab4d9 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/tool_permission.py +++ b/litellm/proxy/guardrails/guardrail_hooks/tool_permission.py @@ -227,7 +227,7 @@ class ToolPermissionGuardrail(CustomGuardrail): Returns: Tuple of (is_allowed, rule_id, message) """ - verbose_proxy_logger.debug(f"Checking permission for tool: {tool_name or tool_type}") + verbose_proxy_logger.debug("Checking permission for tool: %s", tool_name or tool_type) # Check each rule in order for rule in self.rules: @@ -539,7 +539,7 @@ class ToolPermissionGuardrail(CustomGuardrail): if not denied_tool_names: return data - verbose_proxy_logger.info(f"Blocking {len(denied_tool_names)} unauthorized tool uses") + verbose_proxy_logger.info("Blocking %s unauthorized tool uses", len(denied_tool_names)) # Create a mapping of tool_use_id to error result error_tool_names = set() @@ -606,7 +606,7 @@ class ToolPermissionGuardrail(CustomGuardrail): if not denied_tools: return - verbose_proxy_logger.info(f"Blocking {len(denied_tools)} unauthorized tool uses") + verbose_proxy_logger.info("Blocking %s unauthorized tool uses", len(denied_tools)) # Create a mapping of tool_use_id to error result error_results = {} @@ -680,7 +680,7 @@ class ToolPermissionGuardrail(CustomGuardrail): is_allowed, _, message = self._check_tool_permission(tool_name, tool_type) if not is_allowed and message is not None: - verbose_proxy_logger.warning(f"Tool Permission Guardrail: {message}") + verbose_proxy_logger.warning("Tool Permission Guardrail: %s", message) if self.on_disallowed_action == "block": raise HTTPException( status_code=400, @@ -730,7 +730,7 @@ class ToolPermissionGuardrail(CustomGuardrail): verbose_proxy_logger.debug("Tool Permission Guardrail: No tool uses found") return response - verbose_proxy_logger.debug(f"Tool Permission Guardrail: Found {len(tool_calls)} tool calls") + verbose_proxy_logger.debug("Tool Permission Guardrail: Found %s tool calls", len(tool_calls)) # Check permissions for each tool use denied_tools = [] @@ -738,7 +738,7 @@ class ToolPermissionGuardrail(CustomGuardrail): is_allowed, rule_id, message = self._get_permission_for_tool_call(tool_call) if not is_allowed and message is not None: - verbose_proxy_logger.warning(f"Tool Permission Guardrail: {message}") + verbose_proxy_logger.warning("Tool Permission Guardrail: %s", message) if self.on_disallowed_action == "block": raise GuardrailRaisedException( @@ -809,7 +809,7 @@ class ToolPermissionGuardrail(CustomGuardrail): yield chunk return - verbose_proxy_logger.debug(f"Tool Permission Guardrail: Found {len(tool_calls)} tool calls") + verbose_proxy_logger.debug("Tool Permission Guardrail: Found %s tool calls", len(tool_calls)) # Check permissions for each tool use denied_tools = [] @@ -817,7 +817,7 @@ class ToolPermissionGuardrail(CustomGuardrail): is_allowed, rule_id, message = self._get_permission_for_tool_call(tool_call) if not is_allowed and message is not None: - verbose_proxy_logger.warning(f"Tool Permission Guardrail: {message}") + verbose_proxy_logger.warning("Tool Permission Guardrail: %s", message) if self.on_disallowed_action == "block": raise GuardrailRaisedException( diff --git a/litellm/proxy/guardrails/guardrail_hooks/zscaler_ai_guard/zscaler_ai_guard.py b/litellm/proxy/guardrails/guardrail_hooks/zscaler_ai_guard/zscaler_ai_guard.py index 9e16e9d5786..f28fd7975f2 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/zscaler_ai_guard/zscaler_ai_guard.py +++ b/litellm/proxy/guardrails/guardrail_hooks/zscaler_ai_guard/zscaler_ai_guard.py @@ -70,9 +70,10 @@ class ZscalerAIGuard(CustomGuardrail): ) verbose_proxy_logger.debug( - f"""send_user_api_key_alias: {self.send_user_api_key_alias}, - send_user_api_key_user_id:{self.send_user_api_key_user_id}, - send_user_api_key_team_id:{self.send_user_api_key_team_id}""" + "send_user_api_key_alias: %s, \n send_user_api_key_user_id:%s, \n send_user_api_key_team_id:%s", + self.send_user_api_key_alias, + self.send_user_api_key_user_id, + self.send_user_api_key_team_id, ) super().__init__(**kwargs) @@ -144,7 +145,7 @@ class ZscalerAIGuard(CustomGuardrail): texts = inputs.get("texts", []) try: - verbose_proxy_logger.debug(f"ZscalerAIGuard: Checking {len(texts)} text(s)") + verbose_proxy_logger.debug("ZscalerAIGuard: Checking %s text(s)", len(texts)) metadata = request_data.get("metadata", {}) user_api_key_metadata = metadata.get("user_api_key_metadata", {}) or {} @@ -166,7 +167,7 @@ class ZscalerAIGuard(CustomGuardrail): ) ) ) - verbose_proxy_logger.info(f"policy_id applied: {policy_id}") + verbose_proxy_logger.info("policy_id applied: %s", policy_id) kwargs = {} if self.send_user_api_key_alias: @@ -179,11 +180,11 @@ class ZscalerAIGuard(CustomGuardrail): kwargs["user_api_key_user_id"] = ( self._resolve_metadata_value(request_data, "user_api_key_user_id") or "N/A" ) - verbose_proxy_logger.debug(f"inside apply_guardrail kwargs: {kwargs}") + verbose_proxy_logger.debug("inside apply_guardrail kwargs: %s", kwargs) zscaler_ai_guard_result = None direction = "OUT" if input_type == "response" else "IN" - verbose_proxy_logger.debug(f"direction: {direction}") + verbose_proxy_logger.debug("direction: %s", direction) # Concatenate all texts and send to Zscaler AI Guard if texts: concatenated_text = " ".join(texts) @@ -195,7 +196,7 @@ class ZscalerAIGuard(CustomGuardrail): content=concatenated_text, **kwargs, ) - verbose_proxy_logger.debug(f"response from zscaler ai guards: {zscaler_ai_guard_result}") + verbose_proxy_logger.debug("response from zscaler ai guards: %s", zscaler_ai_guard_result) if zscaler_ai_guard_result and zscaler_ai_guard_result.get("action") == "BLOCK": blocking_info = zscaler_ai_guard_result.get("zscaler_ai_guard_response") error_message = f"Content blocked by Zscaler AI Guard: {self.extract_blocking_info(blocking_info)}" @@ -241,9 +242,9 @@ class ZscalerAIGuard(CustomGuardrail): } extra_headers = headers.copy() if self.send_user_api_key_alias: - verbose_proxy_logger.debug(f"kwargs: {kwargs}") + verbose_proxy_logger.debug("kwargs: %s", kwargs) user_api_key_alias = kwargs.get("user_api_key_alias", "N/A") - verbose_proxy_logger.debug(f"kwargs user_api_key_alias: {user_api_key_alias}") + verbose_proxy_logger.debug("kwargs user_api_key_alias: %s", user_api_key_alias) extra_headers.update({"user-api-key-alias": user_api_key_alias}) if self.send_user_api_key_team_id: @@ -254,7 +255,7 @@ class ZscalerAIGuard(CustomGuardrail): user_api_key_user_id = kwargs.get("user_api_key_user_id", "N/A") extra_headers.update({"user-api-key-user-id": user_api_key_user_id}) - verbose_proxy_logger.debug(f"extra_headers: {extra_headers}") + verbose_proxy_logger.debug("extra_headers: %s", extra_headers) return extra_headers async def _send_request(self, url, headers, data): @@ -279,7 +280,7 @@ class ZscalerAIGuard(CustomGuardrail): if response.status_code >= 500: # Server error verbose_proxy_logger.error( - f"Zscaler AI Guard service is unavailable (Status: {response.status_code}). Blocking request." + "Zscaler AI Guard service is unavailable (Status: %s). Blocking request.", response.status_code ) user_facing_error = self._create_user_facing_error(f"Service is unavailable (HTTP {response.status_code})") raise HTTPException(status_code=500, detail=user_facing_error) @@ -289,11 +290,11 @@ class ZscalerAIGuard(CustomGuardrail): statusCode_in_response = json_response.get("statusCode", None) if statusCode_in_response == 200: guardrail_result = json_response.get("action", None) - verbose_proxy_logger.info(f"Zscaler AI Guard response: {json_response}") + verbose_proxy_logger.info("Zscaler AI Guard response: %s", json_response) if guardrail_result == "BLOCK": verbose_proxy_logger.info( - f"Violated Zscaler AI Guard guardrail policy. zscaler_ai_guard_response: {json_response}" + "Violated Zscaler AI Guard guardrail policy. zscaler_ai_guard_response: %s", json_response ) return { "action": "BLOCK", @@ -301,7 +302,7 @@ class ZscalerAIGuard(CustomGuardrail): } elif guardrail_result == "ALLOW" or guardrail_result == "DETECT": verbose_proxy_logger.debug( - f"{direction} is allowed by Zscaler AI Guard. guardrail_result: {guardrail_result}" + "%s is allowed by Zscaler AI Guard. guardrail_result: %s", direction, guardrail_result ) return { "action": "ALLOW", @@ -310,7 +311,7 @@ class ZscalerAIGuard(CustomGuardrail): } else: verbose_proxy_logger.error( - f"Action field in response is {guardrail_result}, expecting 'ALLOW', 'BLOCK' or 'DETECT'" + "Action field in response is %s, expecting 'ALLOW', 'BLOCK' or 'DETECT'", guardrail_result ) user_facing_error = self._create_user_facing_error( f"Action field in response is {guardrail_result}, expecting 'ALLOW', 'BLOCK' or 'DETECT'" @@ -318,13 +319,13 @@ class ZscalerAIGuard(CustomGuardrail): raise HTTPException(status_code=500, detail=user_facing_error) else: errorMsg = json_response.get("errorMsg", None) - verbose_proxy_logger.error(f"statusCode in response: {statusCode_in_response}, errorMsg: {errorMsg}") + verbose_proxy_logger.error("statusCode in response: %s, errorMsg: %s", statusCode_in_response, errorMsg) user_facing_error = self._create_user_facing_error( f"statusCode in response: {statusCode_in_response}, errorMsg: {errorMsg}" ) raise HTTPException(status_code=500, detail=user_facing_error) else: - verbose_proxy_logger.error(f"Zscaler AI Guard status_code - {response.status_code}") + verbose_proxy_logger.error("Zscaler AI Guard status_code - %s", response.status_code) user_facing_error = self._create_user_facing_error(f"Response status code: {response.status_code}") raise HTTPException(status_code=response.status_code, detail=user_facing_error) @@ -350,7 +351,7 @@ class ZscalerAIGuard(CustomGuardrail): response = await self._send_request(zscaler_ai_guard_url, extra_headers, data) return self._handle_response(response, direction) except Exception as e: - verbose_proxy_logger.error(f"{e}. Blocking request.") + verbose_proxy_logger.error("%s. Blocking request.", e) user_facing_error = self._create_user_facing_error(f"{e}") raise HTTPException(status_code=500, detail=user_facing_error) diff --git a/litellm/proxy/guardrails/guardrail_registry.py b/litellm/proxy/guardrails/guardrail_registry.py index b0e16c0ed2e..bb8787ce72d 100644 --- a/litellm/proxy/guardrails/guardrail_registry.py +++ b/litellm/proxy/guardrails/guardrail_registry.py @@ -115,7 +115,7 @@ def get_guardrail_initializer_from_hooks(): module_path = f"litellm.proxy.guardrails.guardrail_hooks.{item}" try: # Import the module - verbose_proxy_logger.debug(f"Discovering guardrails in: {module_path}") + verbose_proxy_logger.debug("Discovering guardrails in: %s", module_path) module = importlib.import_module(module_path) @@ -125,7 +125,7 @@ def get_guardrail_initializer_from_hooks(): if isinstance(registry, dict): discovered_initializers.update(registry) verbose_proxy_logger.debug( - f"Found guardrail_initializer_registry in {module_path}: {list(registry.keys())}" + "Found guardrail_initializer_registry in %s: %s", module_path, list(registry.keys()) ) # Check for standalone initialize_guardrail function (fallback for directory-based guardrails) @@ -133,21 +133,23 @@ def get_guardrail_initializer_from_hooks(): # For directories with just initialize_guardrail, use the directory name as the key initialize_fn = getattr(module, "initialize_guardrail") discovered_initializers[item] = initialize_fn - verbose_proxy_logger.debug(f"Found initialize_guardrail function in {module_path}") + verbose_proxy_logger.debug("Found initialize_guardrail function in %s", module_path) except ImportError as e: - verbose_proxy_logger.error(f"Could not import {module_path}: {e}") + verbose_proxy_logger.error("Could not import %s: %s", module_path, e) continue except Exception as e: - verbose_proxy_logger.error(f"Error processing {module_path}: {e}") + verbose_proxy_logger.error("Error processing %s: %s", module_path, e) continue verbose_proxy_logger.debug( - f"Discovered {len(discovered_initializers)} guardrail initializers: {list(discovered_initializers.keys())}" + "Discovered %s guardrail initializers: %s", + len(discovered_initializers), + list(discovered_initializers.keys()), ) except Exception as e: - verbose_proxy_logger.error(f"Error discovering guardrail initializers: {e}") + verbose_proxy_logger.error("Error discovering guardrail initializers: %s", e) return discovered_initializers @@ -194,7 +196,7 @@ def get_guardrail_class_from_hooks(): try: # Import the module - verbose_proxy_logger.debug(f"Discovering guardrails in: {module_path}") + verbose_proxy_logger.debug("Discovering guardrails in: %s", module_path) module = importlib.import_module(module_path) @@ -205,14 +207,14 @@ def get_guardrail_class_from_hooks(): discovered_classes.update(registry) except ImportError as e: - verbose_proxy_logger.debug(f"Could not import {module_path}: {e}") + verbose_proxy_logger.debug("Could not import %s: %s", module_path, e) continue except Exception as e: - verbose_proxy_logger.exception(f"Error processing {module_path}: {e}") + verbose_proxy_logger.exception("Error processing %s: %s", module_path, e) continue except Exception as e: - verbose_proxy_logger.error(f"Error discovering guardrail initializers: {e}") + verbose_proxy_logger.error("Error discovering guardrail initializers: %s", e) return discovered_classes @@ -686,8 +688,8 @@ class InMemoryGuardrailHandler: return LitellmParams(**params).model_dump() except ValidationError as e: verbose_proxy_logger.warning( - f"Could not normalize guardrail litellm_params for comparison; " - f"treating the guardrail as changed. Error: {e}" + "Could not normalize guardrail litellm_params for comparison; treating the guardrail as changed. Error: %s", + e, ) return params return params @@ -723,7 +725,7 @@ class InMemoryGuardrailHandler: # Log differences if any found if changed_fields: - verbose_proxy_logger.debug(f"Guardrail params changed. Differences: {changed_fields}") + verbose_proxy_logger.debug("Guardrail params changed. Differences: %s", changed_fields) # Return True if any fields changed return len(changed_fields) > 0 @@ -763,7 +765,7 @@ class InMemoryGuardrailHandler: if self._has_guardrail_params_changed(guardrail_id, guardrail): guardrail_name = guardrail.get("guardrail_name", "Unknown") verbose_proxy_logger.info( - f"Guardrail '{guardrail_name}' (ID: {guardrail_id}) params changed, re-initializing..." + "Guardrail '%s' (ID: %s) params changed, re-initializing...", guardrail_name, guardrail_id ) return self.reinitialize_guardrail( guardrail=guardrail, diff --git a/litellm/proxy/guardrails/init_guardrails.py b/litellm/proxy/guardrails/init_guardrails.py index 036ee5dca78..183afb941cb 100644 --- a/litellm/proxy/guardrails/init_guardrails.py +++ b/litellm/proxy/guardrails/init_guardrails.py @@ -86,7 +86,7 @@ def _populate_router_guardrail_list(guardrail_list: list[Guardrail]) -> None: router_guardrail_list.append(router_guardrail) llm_router.guardrail_list = router_guardrail_list - verbose_proxy_logger.debug(f"Populated router guardrail_list with {len(router_guardrail_list)} guardrails") + verbose_proxy_logger.debug("Populated router guardrail_list with %s guardrails", len(router_guardrail_list)) ### LEGACY IMPLEMENTATION ### @@ -97,7 +97,7 @@ def initialize_guardrails( litellm_settings: dict, ) -> dict[str, GuardrailItem]: try: - verbose_proxy_logger.debug(f"validating guardrails passed {guardrails_config}") + verbose_proxy_logger.debug("validating guardrails passed %s", guardrails_config) global all_guardrails for item in guardrails_config: """ @@ -141,5 +141,5 @@ def initialize_guardrails( return litellm.guardrail_name_config_map except Exception as e: - verbose_proxy_logger.exception(f"error initializing guardrails {e}") + verbose_proxy_logger.exception("error initializing guardrails %s", e) raise e diff --git a/litellm/proxy/health_endpoints/_health_endpoints.py b/litellm/proxy/health_endpoints/_health_endpoints.py index c3bce5e8370..40b986f39e6 100644 --- a/litellm/proxy/health_endpoints/_health_endpoints.py +++ b/litellm/proxy/health_endpoints/_health_endpoints.py @@ -425,7 +425,7 @@ async def health_services_endpoint( } except Exception as e: - verbose_proxy_logger.error(f"litellm.proxy.proxy_server.health_services_endpoint(): Exception occured - {e}") + verbose_proxy_logger.error("litellm.proxy.proxy_server.health_services_endpoint(): Exception occured - %s", e) verbose_proxy_logger.debug(traceback.format_exc()) if isinstance(e, HTTPException): raise ProxyException( @@ -504,7 +504,7 @@ async def _save_health_check_to_db( checked_by=user_id, ) except Exception as db_error: - verbose_proxy_logger.warning(f"Failed to save health check to database for model {model_name}: {db_error}") + verbose_proxy_logger.warning("Failed to save health check to database for model %s: %s", model_name, db_error) # Continue execution - don't let database save failure break health checks @@ -708,7 +708,7 @@ async def _save_background_health_checks_to_db( checked_by, ) except Exception as db_error: - verbose_proxy_logger.warning(f"Failed to save background health checks to database: {db_error}") + verbose_proxy_logger.warning("Failed to save background health checks to database: %s", db_error) # Continue execution - don't let database save failure break health checks @@ -882,7 +882,7 @@ def _health_endpoint_resolve_target_model_name( try: deployment = llm_router.get_deployment(model_id=model_id) except Exception as e: - verbose_proxy_logger.error(f"Error getting deployment for model_id {model_id}: {e}") + verbose_proxy_logger.error("Error getting deployment for model_id %s: %s", model_id, e) raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail={"error": f"Model with ID {model_id} not found"}, @@ -1069,7 +1069,7 @@ async def health_endpoint( ) return _post_process(router_result) except Exception as e: - verbose_proxy_logger.error(f"litellm.proxy.proxy_server.py::health_endpoint(): Exception occured - {e}") + verbose_proxy_logger.error("litellm.proxy.proxy_server.py::health_endpoint(): Exception occured - %s", e) verbose_proxy_logger.debug(traceback.format_exc()) raise e @@ -1107,7 +1107,7 @@ async def health_check_history_endpoint( "offset": offset, } except Exception as e: - verbose_proxy_logger.error(f"Error getting health check history: {e}") + verbose_proxy_logger.error("Error getting health check history: %s", e) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail={"error": f"Failed to retrieve health check history: {e}"}, @@ -1139,7 +1139,7 @@ async def latest_health_checks_endpoint( "total_models": len(checks_data), } except Exception as e: - verbose_proxy_logger.error(f"Error getting latest health checks: {e}") + verbose_proxy_logger.error("Error getting latest health checks: %s", e) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail={"error": f"Failed to retrieve latest health checks: {e}"}, @@ -1182,7 +1182,7 @@ async def shared_health_check_status_endpoint( health_status = await shared_health_manager.get_health_check_status() return {"shared_health_check_enabled": True, "status": health_status} except Exception as e: - verbose_proxy_logger.error(f"Error getting shared health check status: {e}") + verbose_proxy_logger.error("Error getting shared health check status: %s", e) raise HTTPException( status_code=fastapi.status.HTTP_500_INTERNAL_SERVER_ERROR, detail={"error": f"Failed to retrieve shared health check status: {e}"}, @@ -1850,7 +1850,7 @@ async def test_model_connection( loaded_model_info = dict(deployments[0].get("model_info") or {}) except Exception as e: verbose_proxy_logger.debug( - f"Could not find model {model_name} in router: {e}. Proceeding with request params only." + "Could not find model %s in router: %s. Proceeding with request params only.", model_name, e ) # Merge: config params (from proxy config) as base, request params override @@ -1897,7 +1897,7 @@ async def test_model_connection( except HTTPException as e: raise e except Exception as e: - verbose_proxy_logger.debug(f"litellm.proxy.health_endpoints.test_model_connection(): Exception occurred - {e}") + verbose_proxy_logger.debug("litellm.proxy.health_endpoints.test_model_connection(): Exception occurred - %s", e) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail={"error": f"Failed to test connection: {e}"}, diff --git a/litellm/proxy/hooks/azure_content_safety.py b/litellm/proxy/hooks/azure_content_safety.py index 3c7713b2819..8195cc87a1f 100644 --- a/litellm/proxy/hooks/azure_content_safety.py +++ b/litellm/proxy/hooks/azure_content_safety.py @@ -123,7 +123,7 @@ class _PROXY_AzureContentSafety( raise e except Exception as e: verbose_proxy_logger.error( - f"litellm.proxy.hooks.azure_content_safety.py::async_pre_call_hook(): Exception occured - {e}" + "litellm.proxy.hooks.azure_content_safety.py::async_pre_call_hook(): Exception occured - %s", e ) verbose_proxy_logger.debug(traceback.format_exc()) diff --git a/litellm/proxy/hooks/batch_rate_limiter.py b/litellm/proxy/hooks/batch_rate_limiter.py index ce4ff2cb370..afaf0ebf392 100644 --- a/litellm/proxy/hooks/batch_rate_limiter.py +++ b/litellm/proxy/hooks/batch_rate_limiter.py @@ -256,7 +256,7 @@ class _PROXY_BatchRateLimiter(CustomLogger): if skip_providers: batch_provider = self._resolve_batch_provider(self._get_batch_routing_model(data)) if batch_provider and batch_provider in skip_providers: - verbose_proxy_logger.debug(f"Skipping batch input file processing for provider={batch_provider}") + verbose_proxy_logger.debug("Skipping batch input file processing for provider=%s", batch_provider) return True, None descriptors = self._create_batch_rate_limit_descriptors( @@ -592,15 +592,15 @@ class _PROXY_BatchRateLimiter(CustomLogger): # in the access log instead of getting buried in error noise. if e.status_code == 403: verbose_proxy_logger.warning( - f"Batch rejected: caller not authorized for a model named in {file_id}: {e.detail}" + "Batch rejected: caller not authorized for a model named in %s: %s", file_id, e.detail ) else: verbose_proxy_logger.error( - f"Batch input file rejected for {file_id}: status={e.status_code} detail={e.detail}" + "Batch input file rejected for %s: status=%s detail=%s", file_id, e.status_code, e.detail ) raise except Exception as e: - verbose_proxy_logger.error(f"Error counting input file usage for {file_id}: {e}") + verbose_proxy_logger.error("Error counting input file usage for %s: %s", file_id, e) raise async def _enforce_batch_file_model_access( @@ -791,7 +791,7 @@ class _PROXY_BatchRateLimiter(CustomLogger): # Only handle batch creation if call_type != "acreate_batch": verbose_proxy_logger.debug( - f"Batch rate limiter: Not handling batch creation rate limiting for call type: {call_type}" + "Batch rate limiter: Not handling batch creation rate limiting for call type: %s", call_type ) return data @@ -814,7 +814,7 @@ class _PROXY_BatchRateLimiter(CustomLogger): custom_llm_provider = data.get("custom_llm_provider", "openai") # Count tokens and requests from input file - verbose_proxy_logger.debug(f"Counting tokens from batch input file: {input_file_id}") + verbose_proxy_logger.debug("Counting tokens from batch input file: %s", input_file_id) batch_usage = await self.count_input_file_usage( file_id=input_file_id, custom_llm_provider=custom_llm_provider, @@ -823,7 +823,7 @@ class _PROXY_BatchRateLimiter(CustomLogger): ) verbose_proxy_logger.debug( - f"Batch input file usage - Tokens: {batch_usage.total_tokens}, Requests: {batch_usage.request_count}" + "Batch input file usage - Tokens: %s, Requests: %s", batch_usage.total_tokens, batch_usage.request_count ) # Store batch usage in data for later reference @@ -846,6 +846,6 @@ class _PROXY_BatchRateLimiter(CustomLogger): # Re-raise HTTP exceptions (rate limit exceeded) raise except Exception as e: - verbose_proxy_logger.error(f"Error in batch rate limiting: {e}", exc_info=True) + verbose_proxy_logger.error("Error in batch rate limiting: %s", e, exc_info=True) # Don't block the request if rate limiting fails return data diff --git a/litellm/proxy/hooks/batch_redis_get.py b/litellm/proxy/hooks/batch_redis_get.py index 377cd8d3d45..e2e7c1a3d27 100644 --- a/litellm/proxy/hooks/batch_redis_get.py +++ b/litellm/proxy/hooks/batch_redis_get.py @@ -84,7 +84,7 @@ class _PROXY_BatchRedisRequests(CustomLogger): raise e except Exception as e: verbose_proxy_logger.error( - f"litellm.proxy.hooks.batch_redis_get.py::async_pre_call_hook(): Exception occured - {e}" + "litellm.proxy.hooks.batch_redis_get.py::async_pre_call_hook(): Exception occured - %s", e ) verbose_proxy_logger.debug(traceback.format_exc()) diff --git a/litellm/proxy/hooks/cache_control_check.py b/litellm/proxy/hooks/cache_control_check.py index f2a0f06b95b..7f486200c2d 100644 --- a/litellm/proxy/hooks/cache_control_check.py +++ b/litellm/proxy/hooks/cache_control_check.py @@ -52,5 +52,5 @@ class _PROXY_CacheControlCheck(CustomLogger): raise e except Exception as e: verbose_logger.exception( - f"litellm.proxy.hooks.cache_control_check.py::async_pre_call_hook(): Exception occured - {e}" + "litellm.proxy.hooks.cache_control_check.py::async_pre_call_hook(): Exception occured - %s", e ) diff --git a/litellm/proxy/hooks/dynamic_rate_limiter.py b/litellm/proxy/hooks/dynamic_rate_limiter.py index 5d890b6787c..c0adcfd1b75 100644 --- a/litellm/proxy/hooks/dynamic_rate_limiter.py +++ b/litellm/proxy/hooks/dynamic_rate_limiter.py @@ -68,7 +68,7 @@ class DynamicRateLimiterCache: await self.cache.async_set_cache_sadd(key=key_name, value=value, ttl=self.ttl) except Exception as e: verbose_proxy_logger.exception( - f"litellm.proxy.hooks.dynamic_rate_limiter.py::async_set_cache_sadd(): Exception occured - {e}" + "litellm.proxy.hooks.dynamic_rate_limiter.py::async_set_cache_sadd(): Exception occured - %s", e ) raise e @@ -106,7 +106,9 @@ class _PROXY_DynamicRateLimitHandler(CustomLogger): weight: float = 1 if litellm.priority_reservation is None or priority not in litellm.priority_reservation: verbose_proxy_logger.error( - f"Priority Reservation not set. priority={priority}, but litellm.priority_reservation is {litellm.priority_reservation}." + "Priority Reservation not set. priority=%s, but litellm.priority_reservation is %s.", + priority, + litellm.priority_reservation, ) elif priority is not None and litellm.priority_reservation is not None: if os.getenv("LITELLM_LICENSE", None) is None: @@ -172,7 +174,7 @@ class _PROXY_DynamicRateLimitHandler(CustomLogger): ) except Exception as e: verbose_proxy_logger.exception( - f"litellm.proxy.hooks.dynamic_rate_limiter.py::check_available_usage: Exception occurred - {e}" + "litellm.proxy.hooks.dynamic_rate_limiter.py::check_available_usage: Exception occurred - %s", e ) return None, None, None, None, None @@ -263,6 +265,6 @@ class _PROXY_DynamicRateLimitHandler(CustomLogger): ) except Exception as e: verbose_proxy_logger.exception( - f"litellm.proxy.hooks.dynamic_rate_limiter.py::async_post_call_success_hook(): Exception occured - {e}" + "litellm.proxy.hooks.dynamic_rate_limiter.py::async_post_call_success_hook(): Exception occured - %s", e ) return response diff --git a/litellm/proxy/hooks/dynamic_rate_limiter_v3.py b/litellm/proxy/hooks/dynamic_rate_limiter_v3.py index 773abed1785..326a8e01407 100644 --- a/litellm/proxy/hooks/dynamic_rate_limiter_v3.py +++ b/litellm/proxy/hooks/dynamic_rate_limiter_v3.py @@ -173,7 +173,7 @@ class _PROXY_DynamicRateLimitHandlerV3(CustomLogger): if total_weight > 1.0: normalized = {k: v / total_weight for k, v in weights.items()} - verbose_proxy_logger.debug(f"Normalized over-allocated priorities: {weights} -> {normalized}") + verbose_proxy_logger.debug("Normalized over-allocated priorities: %s -> %s", weights, normalized) return normalized return weights @@ -282,7 +282,7 @@ class _PROXY_DynamicRateLimitHandlerV3(CustomLogger): return max_saturation except Exception as e: - verbose_proxy_logger.error(f"Error checking saturation for {model}: {e}") + verbose_proxy_logger.error("Error checking saturation for %s: %s", model, e) # Fail open: assume not saturated on error return 0.0 @@ -454,7 +454,7 @@ class _PROXY_DynamicRateLimitHandlerV3(CustomLogger): parent_otel_span=user_api_key_dict.parent_otel_span, ) - verbose_proxy_logger.debug(f"Atomic check+increment response: {json.dumps(atomic_response, indent=2)}") + verbose_proxy_logger.debug("Atomic check+increment response: %s", json.dumps(atomic_response, indent=2)) if atomic_response["overall_code"] == "OVER_LIMIT": resolved_model, llm_provider = resolve_llm_provider_for_rate_limit(model) @@ -518,8 +518,8 @@ class _PROXY_DynamicRateLimitHandlerV3(CustomLogger): None, ) verbose_proxy_logger.error( - f"Dynamic rate limiter: OVER_LIMIT response with unknown " - f"descriptor_key(s) — refusing request. response={atomic_response}" + "Dynamic rate limiter: OVER_LIMIT response with unknown descriptor_key(s) — refusing request. response=%s", + atomic_response, ) raise ProxyRateLimitError( detail={ @@ -610,7 +610,7 @@ class _PROXY_DynamicRateLimitHandlerV3(CustomLogger): # Get model configuration model_group_info: ModelGroupInfo | None = self.llm_router.get_model_group_info(model_group=model) if model_group_info is None: - verbose_proxy_logger.debug(f"No model group info for {model}, allowing request") + verbose_proxy_logger.debug("No model group info for %s, allowing request", model) return None try: @@ -640,7 +640,7 @@ class _PROXY_DynamicRateLimitHandlerV3(CustomLogger): except HTTPException: raise except Exception as e: - verbose_proxy_logger.error(f"Error in dynamic rate limiter: {e}, allowing request") + verbose_proxy_logger.error("Error in dynamic rate limiter: %s, allowing request", e) # Fail open on unexpected errors return None @@ -676,7 +676,7 @@ class _PROXY_DynamicRateLimitHandlerV3(CustomLogger): return response except Exception as e: - verbose_proxy_logger.exception(f"Error in dynamic rate limiter v3 post-call hook: {e}") + verbose_proxy_logger.exception("Error in dynamic rate limiter v3 post-call hook: %s", e) return response async def async_log_success_event(self, kwargs, response_obj, start_time, end_time): @@ -786,9 +786,11 @@ class _PROXY_DynamicRateLimitHandlerV3(CustomLogger): SAFE_PRIORITIES = {"low", "medium", "high", "default"} logged_priority = key_priority if key_priority in SAFE_PRIORITIES else "REDACTED" verbose_proxy_logger.debug( - f"[Dynamic Rate Limiter] Incremented tokens by {total_tokens} for " - f"model={model_group}, priority={logged_priority}" + "[Dynamic Rate Limiter] Incremented tokens by %s for model=%s, priority=%s", + total_tokens, + model_group, + logged_priority, ) except Exception as e: - verbose_proxy_logger.exception(f"Error in dynamic rate limiter success event: {e}") + verbose_proxy_logger.exception("Error in dynamic rate limiter success event: %s", e) diff --git a/litellm/proxy/hooks/key_management_event_hooks.py b/litellm/proxy/hooks/key_management_event_hooks.py index 7ef1341a168..800d4874a98 100644 --- a/litellm/proxy/hooks/key_management_event_hooks.py +++ b/litellm/proxy/hooks/key_management_event_hooks.py @@ -51,7 +51,7 @@ class KeyManagementEventHooks: try: await KeyManagementEventHooks._send_key_created_email(response.model_dump(exclude_none=True)) except Exception as e: - verbose_proxy_logger.warning(f"Failed to send key created email: {e}") + verbose_proxy_logger.warning("Failed to send key created email: %s", e) # Enterprise Feature - Audit Logging. Enable with litellm.store_audit_logs = True if litellm.store_audit_logs is True: @@ -84,7 +84,7 @@ class KeyManagementEventHooks: team_id=data.team_id, ) except Exception as e: - verbose_proxy_logger.warning(f"Failed to store virtual key in secret manager: {e}") + verbose_proxy_logger.warning("Failed to store virtual key in secret manager: %s", e) @staticmethod async def async_key_updated_hook( @@ -168,7 +168,7 @@ class KeyManagementEventHooks: new_secret_name, ) except Exception as e: - verbose_proxy_logger.warning(f"Failed to rotate virtual key in secret manager: {e}") + verbose_proxy_logger.warning("Failed to rotate virtual key in secret manager: %s", e) # Send key rotated email if configured - non-blocking, independent operation try: @@ -177,7 +177,7 @@ class KeyManagementEventHooks: existing_key_alias=existing_key_row.key_alias, ) except Exception as e: - verbose_proxy_logger.warning(f"Failed to send key rotated email: {e}") + verbose_proxy_logger.warning("Failed to send key rotated email: %s", e) # store the audit log if litellm.store_audit_logs is True and existing_key_row.token is not None: @@ -273,7 +273,7 @@ class KeyManagementEventHooks: description = getattr(litellm._key_management_settings, "description", None) optional_params = await KeyManagementEventHooks._get_secret_manager_optional_params(team_id) verbose_proxy_logger.debug( - f"Creating secret with {secret_name} and tags={tags} and description={description}" + "Creating secret with %s and tags=%s and description=%s", secret_name, tags, description ) await litellm.secret_manager_client.async_write_secret( @@ -355,7 +355,8 @@ class KeyManagementEventHooks: ) else: verbose_proxy_logger.warning( - f"KeyManagementEventHooks._delete_virtual_key_from_secret_manager: Key alias not found for key {key.token}. Skipping deletion from secret manager." + "KeyManagementEventHooks._delete_virtual_key_from_secret_manager: Key alias not found for key %s. Skipping deletion from secret manager.", + key.token, ) @staticmethod @@ -385,7 +386,7 @@ class KeyManagementEventHooks: user_api_key_cache=user_api_key_cache, ) except Exception as exc: # pragma: no cover - defensive logging - verbose_proxy_logger.debug(f"Unable to load team metadata for team_id={team_id}: {exc}") + verbose_proxy_logger.debug("Unable to load team metadata for team_id=%s: %s", team_id, exc) return None metadata = getattr(team_obj, "metadata", None) diff --git a/litellm/proxy/hooks/litellm_skills/main.py b/litellm/proxy/hooks/litellm_skills/main.py index 983a59657ce..770578d988b 100644 --- a/litellm/proxy/hooks/litellm_skills/main.py +++ b/litellm/proxy/hooks/litellm_skills/main.py @@ -96,7 +96,7 @@ class SkillsInjectionHook(CustomLogger): if not skills or not isinstance(skills, list): return data - verbose_proxy_logger.debug(f"SkillsInjectionHook: Processing {len(skills)} skills") + verbose_proxy_logger.debug("SkillsInjectionHook: Processing %s skills", len(skills)) litellm_skills: list[LiteLLM_SkillsTable] = [] anthropic_skills: list[dict[str, Any]] = [] @@ -116,7 +116,7 @@ class SkillsInjectionHook(CustomLogger): if db_skill: litellm_skills.append(db_skill) else: - verbose_proxy_logger.warning(f"SkillsInjectionHook: Skill '{skill_id}' not found in LiteLLM DB") + verbose_proxy_logger.warning("SkillsInjectionHook: Skill '%s' not found in LiteLLM DB", skill_id) else: # Native Anthropic skill - pass through anthropic_skills.append(skill) @@ -198,9 +198,10 @@ class SkillsInjectionHook(CustomLogger): data.pop("container", None) verbose_proxy_logger.debug( - f"SkillsInjectionHook: Messages API - converted {len(litellm_skills)} skills to Anthropic tools, " - f"injected {len(skill_contents)} skill contents, " - f"added litellm_code_execution tool with {len(all_module_paths)} modules" + "SkillsInjectionHook: Messages API - converted %s skills to Anthropic tools, injected %s skill contents, added litellm_code_execution tool with %s modules", + len(litellm_skills), + len(skill_contents), + len(all_module_paths), ) return data @@ -266,9 +267,10 @@ class SkillsInjectionHook(CustomLogger): data.pop("container", None) verbose_proxy_logger.debug( - f"SkillsInjectionHook: Non-Anthropic model - converted {len(litellm_skills)} skills to tools, " - f"injected {len(skill_contents)} skill contents, " - f"added execute_code tool with {len(all_module_paths)} modules" + "SkillsInjectionHook: Non-Anthropic model - converted %s skills to tools, injected %s skill contents, added execute_code tool with %s modules", + len(litellm_skills), + len(skill_contents), + len(all_module_paths), ) return data @@ -295,7 +297,7 @@ class SkillsInjectionHook(CustomLogger): user_api_key_dict=user_api_key_dict, ) except Exception as e: - verbose_proxy_logger.warning(f"SkillsInjectionHook: Error fetching skill {skill_id}: {e}") + verbose_proxy_logger.warning("SkillsInjectionHook: Error fetching skill %s: %s", skill_id, e) return None def _is_anthropic_model(self, model: str) -> bool: @@ -500,8 +502,9 @@ class SkillsInjectionHook(CustomLogger): # Check if we're done (no tool calls) if stop_reason != "tool_use" or not tool_calls: verbose_proxy_logger.debug( - f"SkillsInjectionHook: Loop completed after {iteration + 1} iterations, " - f"{len(generated_files)} files generated" + "SkillsInjectionHook: Loop completed after %s iterations, %s files generated", + iteration + 1, + len(generated_files), ) return self._attach_files_to_response(current_response, generated_files) @@ -536,7 +539,7 @@ class SkillsInjectionHook(CustomLogger): messages.append({"role": "user", "content": tool_results}) # Make next LLM call - verbose_proxy_logger.debug(f"SkillsInjectionHook: Making LLM call iteration {iteration + 2}") + verbose_proxy_logger.debug("SkillsInjectionHook: Making LLM call iteration %s", iteration + 2) try: current_response = await litellm.anthropic.acreate( model=model, @@ -548,10 +551,10 @@ class SkillsInjectionHook(CustomLogger): verbose_proxy_logger.error("SkillsInjectionHook: LLM call returned None") return self._attach_files_to_response(response, generated_files) except Exception as e: - verbose_proxy_logger.error(f"SkillsInjectionHook: LLM call failed: {e}") + verbose_proxy_logger.error("SkillsInjectionHook: LLM call failed: %s", e) return self._attach_files_to_response(response, generated_files) - verbose_proxy_logger.warning(f"SkillsInjectionHook: Max iterations ({self.max_iterations}) reached") + verbose_proxy_logger.warning("SkillsInjectionHook: Max iterations (%s) reached", self.max_iterations) return self._attach_files_to_response(current_response, generated_files) async def _execute_code( @@ -563,7 +566,7 @@ class SkillsInjectionHook(CustomLogger): ) -> str: """Execute code in sandbox and return result string.""" try: - verbose_proxy_logger.debug(f"SkillsInjectionHook: Executing code ({len(code)} chars)") + verbose_proxy_logger.debug("SkillsInjectionHook: Executing code (%s chars)", len(code)) exec_result = executor.execute(code=code, skill_files=skill_files) @@ -731,8 +734,9 @@ print('No executable skill module found') # Check if we're done (no tool calls) if stop_reason != "tool_calls" or not assistant_message.tool_calls: verbose_proxy_logger.debug( - f"SkillsInjectionHook: Code execution loop completed after " - f"{iteration + 1} iterations, {len(generated_files)} files generated" + "SkillsInjectionHook: Code execution loop completed after %s iterations, %s files generated", + iteration + 1, + len(generated_files), ) # Attach generated files to response return self._attach_files_to_response(current_response, generated_files) @@ -761,7 +765,7 @@ print('No executable skill module found') ) # Make next LLM call using the messages API - verbose_proxy_logger.debug(f"SkillsInjectionHook: Making LLM call iteration {iteration + 2}") + verbose_proxy_logger.debug("SkillsInjectionHook: Making LLM call iteration %s", iteration + 2) current_response = await litellm.anthropic.acreate( model=model, messages=messages, @@ -770,7 +774,7 @@ print('No executable skill module found') ) # Max iterations reached - verbose_proxy_logger.warning(f"SkillsInjectionHook: Max iterations ({self.max_iterations}) reached") + verbose_proxy_logger.warning("SkillsInjectionHook: Max iterations (%s) reached", self.max_iterations) return self._attach_files_to_response(current_response, generated_files) async def _execute_code_tool( @@ -785,7 +789,7 @@ print('No executable skill module found') args = json.loads(tool_call.function.arguments) code = args.get("code", "") - verbose_proxy_logger.debug(f"SkillsInjectionHook: Executing code ({len(code)} chars)") + verbose_proxy_logger.debug("SkillsInjectionHook: Executing code (%s chars)", len(code)) exec_result = executor.execute( code=code, @@ -811,7 +815,7 @@ print('No executable skill module found') tool_result += f"\n- {f['name']} ({len(file_content)} bytes)" verbose_proxy_logger.debug( - f"SkillsInjectionHook: Generated file {f['name']} ({len(file_content)} bytes)" + "SkillsInjectionHook: Generated file %s (%s bytes)", f["name"], len(file_content) ) if exec_result.get("error"): @@ -820,7 +824,7 @@ print('No executable skill module found') return tool_result except Exception as e: - verbose_proxy_logger.error(f"SkillsInjectionHook: Code execution failed: {e}") + verbose_proxy_logger.error("SkillsInjectionHook: Code execution failed: %s", e) return f"Code execution failed: {e}" def _attach_files_to_response( @@ -840,7 +844,7 @@ print('No executable skill module found') # Handle dict response (Anthropic/messages API format) if isinstance(response, dict): response["_litellm_generated_files"] = generated_files - verbose_proxy_logger.debug(f"SkillsInjectionHook: Attached {len(generated_files)} files to dict response") + verbose_proxy_logger.debug("SkillsInjectionHook: Attached %s files to dict response", len(generated_files)) return response # Handle object response (OpenAI format) @@ -855,7 +859,7 @@ print('No executable skill module found') response.model_extra = {} response.model_extra["_litellm_generated_files"] = generated_files - verbose_proxy_logger.debug(f"SkillsInjectionHook: Attached {len(generated_files)} files to response") + verbose_proxy_logger.debug("SkillsInjectionHook: Attached %s files to response", len(generated_files)) return response diff --git a/litellm/proxy/hooks/max_budget_limiter.py b/litellm/proxy/hooks/max_budget_limiter.py index 4a768b4e7de..7790dd8e175 100644 --- a/litellm/proxy/hooks/max_budget_limiter.py +++ b/litellm/proxy/hooks/max_budget_limiter.py @@ -75,5 +75,5 @@ class _PROXY_MaxBudgetLimiter(CustomLogger): raise e except Exception as e: verbose_logger.exception( - f"litellm.proxy.hooks.max_budget_limiter.py::async_pre_call_hook(): Exception occured - {e}" + "litellm.proxy.hooks.max_budget_limiter.py::async_pre_call_hook(): Exception occured - %s", e ) diff --git a/litellm/proxy/hooks/mcp_semantic_filter/hook.py b/litellm/proxy/hooks/mcp_semantic_filter/hook.py index 10293bc5e5f..0356cbfa702 100644 --- a/litellm/proxy/hooks/mcp_semantic_filter/hook.py +++ b/litellm/proxy/hooks/mcp_semantic_filter/hook.py @@ -62,8 +62,9 @@ class SemanticToolFilterHook(CustomLogger): self.filter = semantic_filter verbose_proxy_logger.debug( - f"Initialized SemanticToolFilterHook with filter: " - f"enabled={semantic_filter.enabled}, top_k={semantic_filter.top_k}" + "Initialized SemanticToolFilterHook with filter: enabled=%s, top_k=%s", + semantic_filter.enabled, + semantic_filter.top_k, ) def _should_expand_mcp_tools(self, tools: list[Any]) -> bool: @@ -114,22 +115,24 @@ class SemanticToolFilterHook(CustomLogger): if hasattr(tool, "model_dump"): tool_dict = tool.model_dump(exclude_none=True) verbose_proxy_logger.debug( - f"Converted Pydantic tool to dict: {type(tool).__name__} -> dict with keys: {list(tool_dict.keys())}" + "Converted Pydantic tool to dict: %s -> dict with keys: %s", + type(tool).__name__, + list(tool_dict.keys()), ) openai_tools_as_dicts.append(tool_dict) elif hasattr(tool, "dict"): tool_dict = tool.dict(exclude_none=True) - verbose_proxy_logger.debug(f"Converted Pydantic tool (v1) to dict: {type(tool).__name__} -> dict") + verbose_proxy_logger.debug("Converted Pydantic tool (v1) to dict: %s -> dict", type(tool).__name__) openai_tools_as_dicts.append(tool_dict) elif isinstance(tool, dict): - verbose_proxy_logger.debug(f"Tool is already a dict with keys: {list(tool.keys())}") + verbose_proxy_logger.debug("Tool is already a dict with keys: %s", list(tool.keys())) openai_tools_as_dicts.append(tool) else: - verbose_proxy_logger.warning(f"Tool is unknown type: {type(tool)}, passing as-is") + verbose_proxy_logger.warning("Tool is unknown type: %s, passing as-is", type(tool)) openai_tools_as_dicts.append(tool) verbose_proxy_logger.debug( - f"Expanded {len(mcp_tools)} MCP reference(s) to {len(openai_tools_as_dicts)} tools (all as dicts)" + "Expanded %s MCP reference(s) to %s tools (all as dicts)", len(mcp_tools), len(openai_tools_as_dicts) ) return openai_tools_as_dicts @@ -235,13 +238,14 @@ class SemanticToolFilterHook(CustomLogger): metadata["litellm_semantic_filter_tools"] = tool_names_csv verbose_proxy_logger.info( - f"Semantic tool filter: {filter_stats} MCP tools " - f"({len(native_tools)} native preserved, " - f"{len(filtered_tools)} total)" + "Semantic tool filter: %s MCP tools (%s native preserved, %s total)", + filter_stats, + len(native_tools), + len(filtered_tools), ) else: verbose_proxy_logger.info( - f"Semantic tool filter: all {len(native_tools)} tools are native, no MCP filtering applied" + "Semantic tool filter: all %s tools are native, no MCP filtering applied", len(native_tools) ) def _emit_filter_metadata_safe( @@ -266,7 +270,8 @@ class SemanticToolFilterHook(CustomLogger): ) except Exception as e: verbose_proxy_logger.warning( - f"Failed to emit semantic filter metadata: {e}", + "Failed to emit semantic filter metadata: %s", + e, exc_info=True, ) @@ -284,7 +289,7 @@ class SemanticToolFilterHook(CustomLogger): tools list to only include semantically relevant tools. """ if call_type not in ("completion", "acompletion", "aresponses"): - verbose_proxy_logger.debug(f"Skipping semantic filter for call_type={call_type}") + verbose_proxy_logger.debug("Skipping semantic filter for call_type=%s", call_type) return None tools = data.get("tools") @@ -321,16 +326,17 @@ class SemanticToolFilterHook(CustomLogger): filtered_tools=narrowed_tools, ) verbose_proxy_logger.info( - f"Expanded MCP references to {len(expanded_tools)} tools " - f"({len(native_tools_before_expand)} native preserved), " - f"semantic filter selected {len(filtered_expanded_tools)}" + "Expanded MCP references to %s tools (%s native preserved), semantic filter selected %s", + len(expanded_tools), + len(native_tools_before_expand), + len(filtered_expanded_tools), ) return data except SemanticToolFilterContextWindowError as e: raise HTTPException(status_code=400, detail={"error": str(e)}) from e except Exception as e: - verbose_proxy_logger.error(f"Failed to expand MCP references: {e}", exc_info=True) + verbose_proxy_logger.error("Failed to expand MCP references: %s", e, exc_info=True) return None messages = data.get("messages", []) @@ -361,9 +367,10 @@ class SemanticToolFilterHook(CustomLogger): native_tools.append(t) verbose_proxy_logger.debug( - f"Applying semantic filter: {len(mcp_tools)} MCP tools, " - f"{len(native_tools)} native tools, " - f"query: '{user_query[:50]}...'" + "Applying semantic filter: %s MCP tools, %s native tools, query: '%s...'", + len(mcp_tools), + len(native_tools), + user_query[:50], ) if mcp_tools: @@ -404,7 +411,7 @@ class SemanticToolFilterHook(CustomLogger): except SemanticToolFilterContextWindowError as e: raise HTTPException(status_code=400, detail={"error": str(e)}) from e except Exception as e: - verbose_proxy_logger.warning(f"Semantic tool filter hook failed: {e}. Proceeding with all tools.") + verbose_proxy_logger.warning("Semantic tool filter hook failed: %s. Proceeding with all tools.", e) return None async def async_post_call_response_headers_hook( @@ -497,18 +504,19 @@ class SemanticToolFilterHook(CustomLogger): hook = SemanticToolFilterHook(semantic_filter) verbose_proxy_logger.info( - f"✅ MCP Semantic Tool Filter enabled: " - f"embedding_model={embedding_model}, top_k={top_k}, " - f"similarity_threshold={similarity_threshold}" + "✅ MCP Semantic Tool Filter enabled: embedding_model=%s, top_k=%s, similarity_threshold=%s", + embedding_model, + top_k, + similarity_threshold, ) return hook except ImportError as e: verbose_proxy_logger.warning( - f"semantic-router not installed. Install with: pip install 'litellm[semantic-router]'. Error: {e}" + "semantic-router not installed. Install with: pip install 'litellm[semantic-router]'. Error: %s", e ) return None except Exception as e: - verbose_proxy_logger.exception(f"Failed to initialize MCP semantic tool filter: {e}") + verbose_proxy_logger.exception("Failed to initialize MCP semantic tool filter: %s", e) return None diff --git a/litellm/proxy/hooks/model_max_budget_limiter.py b/litellm/proxy/hooks/model_max_budget_limiter.py index 2aeb505bd97..630fcdb8fe7 100644 --- a/litellm/proxy/hooks/model_max_budget_limiter.py +++ b/litellm/proxy/hooks/model_max_budget_limiter.py @@ -56,7 +56,7 @@ class _PROXY_VirtualKeyModelMaxBudgetLimiter(RouterBudgetLimiting): model=model, internal_model_max_budget=internal_model_max_budget ) if _current_model_budget_info is None: - verbose_proxy_logger.debug(f"Model {model} not found in internal_model_max_budget") + verbose_proxy_logger.debug("Model %s not found in internal_model_max_budget", model) return True # check if current model is within budget @@ -122,7 +122,7 @@ class _PROXY_VirtualKeyModelMaxBudgetLimiter(RouterBudgetLimiting): model=model, internal_model_max_budget=internal_model_max_budget ) if _current_model_budget_info is None: - verbose_proxy_logger.debug(f"Model {model} not found in end_user_model_max_budget") + verbose_proxy_logger.debug("Model %s not found in end_user_model_max_budget", model) return True # check if current model is within budget diff --git a/litellm/proxy/hooks/parallel_request_limiter.py b/litellm/proxy/hooks/parallel_request_limiter.py index 04f34d0e9cf..081200366d6 100644 --- a/litellm/proxy/hooks/parallel_request_limiter.py +++ b/litellm/proxy/hooks/parallel_request_limiter.py @@ -69,7 +69,7 @@ class _PROXY_MaxParallelRequestsHandler(CustomLogger): rate_limit_type: Literal["key", "model_per_key", "user", "customer", "team"], values_to_update_in_cache: list[tuple[Any, Any]], ) -> dict: - verbose_proxy_logger.info(f"Current Usage of {rate_limit_type} in this minute: {current}") + verbose_proxy_logger.info("Current Usage of %s in this minute: %s", rate_limit_type, current) if current is None: if max_parallel_requests == 0 or tpm_limit == 0 or rpm_limit == 0: # base case — at least one dimension is set to 0 (effectively @@ -776,7 +776,7 @@ class _PROXY_MaxParallelRequestsHandler(CustomLogger): litellm_parent_otel_span=litellm_parent_otel_span, ) # save in cache for up to 1 min. except Exception as e: - verbose_proxy_logger.exception(f"Inside Parallel Request Limiter: An exception occurred - {e}") + verbose_proxy_logger.exception("Inside Parallel Request Limiter: An exception occurred - %s", e) async def get_internal_user_object( self, diff --git a/litellm/proxy/hooks/parallel_request_limiter_v3.py b/litellm/proxy/hooks/parallel_request_limiter_v3.py index 98f1e650845..af4818dec02 100644 --- a/litellm/proxy/hooks/parallel_request_limiter_v3.py +++ b/litellm/proxy/hooks/parallel_request_limiter_v3.py @@ -490,7 +490,7 @@ class _PROXY_MaxParallelRequestsHandler_v3(CustomLogger): parallel_request_limiter=self, ) except Exception as e: - verbose_proxy_logger.debug(f"Could not load batch rate limiter: {e}") + verbose_proxy_logger.debug("Could not load batch rate limiter: %s", e) return self._batch_rate_limiter def _get_current_time(self) -> datetime: @@ -579,9 +579,11 @@ class _PROXY_MaxParallelRequestsHandler_v3(CustomLogger): total_estimated = estimated_input_tokens + max_tokens_estimate verbose_proxy_logger.debug( - f"TPM reservation estimate: input={estimated_input_tokens}, " - f"max_tokens={max_tokens_estimate} (explicit={explicit_max_tokens is not None}), " - f"total={total_estimated}" + "TPM reservation estimate: input=%s, max_tokens=%s (explicit=%s), total=%s", + estimated_input_tokens, + max_tokens_estimate, + explicit_max_tokens is not None, + total_estimated, ) return total_estimated @@ -808,7 +810,7 @@ class _PROXY_MaxParallelRequestsHandler_v3(CustomLogger): ) all_cache_values.extend(group_cache_values) except Exception as e: - verbose_proxy_logger.warning(f"Redis Lua script failed for hash tag {hash_tag}: {e}") + verbose_proxy_logger.warning("Redis Lua script failed for hash tag %s: %s", hash_tag, e) # Fallback to in-memory cache for this group group_cache_values = await self.in_memory_cache_sliding_window( keys=group_keys, @@ -1055,7 +1057,7 @@ class _PROXY_MaxParallelRequestsHandler_v3(CustomLogger): ) counts = [max(0, int(value)) for value in raw_counts] except Exception as e: # noqa: BLE001 - any Redis/Lua failure degrades to the local mirror, never a 500 - verbose_proxy_logger.warning(f"parallel_count_script failed, using local mirror: {e}") + verbose_proxy_logger.warning("parallel_count_script failed, using local mirror: %s", e) counts = await self._read_local_gauge_counts(gauge_keys, parent_otel_span) else: counts = await self._read_local_gauge_counts(gauge_keys, parent_otel_span) @@ -1085,7 +1087,7 @@ class _PROXY_MaxParallelRequestsHandler_v3(CustomLogger): ], ) except Exception as e: # noqa: BLE001 - any Redis/Lua failure degrades to in-memory enforcement, never a 500 - verbose_proxy_logger.warning(f"parallel_acquire_script failed, falling back to in-memory gauge: {e}") + verbose_proxy_logger.warning("parallel_acquire_script failed, falling back to in-memory gauge: %s", e) async with self._check_and_increment_lock: return await self._acquire_parallel_slots_in_memory(gauges, slot_id, parent_otel_span) if int(raw[0]) == 1: @@ -1212,7 +1214,7 @@ class _PROXY_MaxParallelRequestsHandler_v3(CustomLogger): ) return except Exception as e: # noqa: BLE001 - any Redis/Lua failure degrades to the in-memory release, never a 500 - verbose_proxy_logger.warning(f"parallel_release_script failed, falling back to in-memory release: {e}") + verbose_proxy_logger.warning("parallel_release_script failed, falling back to in-memory release: %s", e) async with self._check_and_increment_lock: for counter_key in counter_keys: @@ -1387,12 +1389,11 @@ class _PROXY_MaxParallelRequestsHandler_v3(CustomLogger): # to its pre-call state, then fall back to in-memory for the # whole call (counters there are independent of Redis). verbose_proxy_logger.error( - f"atomic_check_and_increment_by_n: Redis Lua execution " - f"failed ({type(e).__name__}: {e}). Refunding " - f"{len(applied)} prior descriptors and falling back to " - f"in-memory enforcement — counters will diverge from " - f"Redis until window expires (window_size=" - f"{self.window_size}s)." + "atomic_check_and_increment_by_n: Redis Lua execution failed (%s: %s). Refunding %s prior descriptors and falling back to in-memory enforcement — counters will diverge from Redis until window expires (window_size=%ss).", + type(e).__name__, + e, + len(applied), + self.window_size, ) await self._refund_applied_descriptor_groups(applied) flat_meta: list[dict[str, Any]] = [m for _k, _a, group_meta in descriptor_groups for m in group_meta] @@ -1434,7 +1435,7 @@ class _PROXY_MaxParallelRequestsHandler_v3(CustomLogger): ) except Exception as e: verbose_proxy_logger.warning( - f"Failed to refund {entry['counter_key']} on cross-descriptor rollback: {e}" + "Failed to refund %s on cross-descriptor rollback: %s", entry["counter_key"], e ) def _build_atomic_response( @@ -2227,18 +2228,20 @@ class _PROXY_MaxParallelRequestsHandler_v3(CustomLogger): if failure_count > DYNAMIC_RATE_LIMIT_ERROR_THRESHOLD_PER_MINUTE: verbose_proxy_logger.debug( - f"[Dynamic Rate Limit] Deployment {deployment_id} has {failure_count} failures " - f"in current minute - enforcing rate limits for model {model}" + "[Dynamic Rate Limit] Deployment %s has %s failures in current minute - enforcing rate limits for model %s", + deployment_id, + failure_count, + model, ) return True verbose_proxy_logger.debug( - f"[Dynamic Rate Limit] No failures detected for model {model} - allowing dynamic exceeding" + "[Dynamic Rate Limit] No failures detected for model %s - allowing dynamic exceeding", model ) return False except Exception as e: - verbose_proxy_logger.debug(f"Error checking model failure status: {e}, defaulting to enforce limits") + verbose_proxy_logger.debug("Error checking model failure status: %s, defaulting to enforce limits", e) # Fail safe: enforce limits if we can't check return True @@ -2573,7 +2576,9 @@ class _PROXY_MaxParallelRequestsHandler_v3(CustomLogger): if stored_response is not None: stored_response["statuses"].extend(tpm_response["statuses"]) - verbose_proxy_logger.debug(f"TPM tokens reserved: {estimated_tokens} for model {requested_model}") + verbose_proxy_logger.debug( + "TPM tokens reserved: %s for model %s", estimated_tokens, requested_model + ) def _create_pipeline_operations( self, @@ -2704,8 +2709,10 @@ class _PROXY_MaxParallelRequestsHandler_v3(CustomLogger): ttl_value = op["ttl"] if op["ttl"] is not None else 0 verbose_proxy_logger.debug( - f"Executing TTL-preserving increment for key={op['key']}, " - f"increment={op['increment_value']}, ttl={ttl_value}" + "Executing TTL-preserving increment for key=%s, increment=%s, ttl=%s", + op["key"], + op["increment_value"], + ttl_value, ) keys.append(op["key"]) args.extend([op["increment_value"], ttl_value]) @@ -2740,11 +2747,11 @@ class _PROXY_MaxParallelRequestsHandler_v3(CustomLogger): await self._execute_token_increment_script(pipeline_operations) verbose_proxy_logger.debug( - f"Successfully executed TTL-preserving increment for {len(pipeline_operations)} keys" + "Successfully executed TTL-preserving increment for %s keys", len(pipeline_operations) ) except Exception as e: - verbose_proxy_logger.warning(f"TTL preservation failed, falling back to regular pipeline: {e}") + verbose_proxy_logger.warning("TTL preservation failed, falling back to regular pipeline: %s", e) # Fallback to regular pipeline on error await self.internal_usage_cache.dual_cache.async_increment_cache_pipeline( increment_list=pipeline_operations, @@ -2950,9 +2957,10 @@ class _PROXY_MaxParallelRequestsHandler_v3(CustomLogger): ) if reserved_tokens > 0 and total_tokens < reserved_tokens: verbose_proxy_logger.debug( - f"Releasing unused TPM budget on success: " - f"reserved={reserved_tokens}, actual={total_tokens}, " - f"release={reserved_tokens - total_tokens}" + "Releasing unused TPM budget on success: reserved=%s, actual=%s, release=%s", + reserved_tokens, + total_tokens, + reserved_tokens - total_tokens, ) pipeline_operations.extend( self._build_reservation_aware_tpm_ops( @@ -3001,7 +3009,7 @@ class _PROXY_MaxParallelRequestsHandler_v3(CustomLogger): ) except Exception as e: - verbose_proxy_logger.exception(f"Error in rate limit success event: {e}") + verbose_proxy_logger.exception("Error in rate limit success event: %s", e) async def async_logging_hook( self, @@ -3095,7 +3103,7 @@ class _PROXY_MaxParallelRequestsHandler_v3(CustomLogger): if stash is not None and not stash.reservation_released: reserved_tokens = stash.reserved_tokens if stash is not None and reserved_tokens > 0: - verbose_proxy_logger.debug(f"Releasing reserved TPM tokens on failure: {reserved_tokens}") + verbose_proxy_logger.debug("Releasing reserved TPM tokens on failure: %s", reserved_tokens) # Refund only against the scopes the reservation actually # charged. _build_reservation_aware_tpm_ops with # actual_tokens=0 emits -reserved on reserved scopes and 0 @@ -3118,7 +3126,7 @@ class _PROXY_MaxParallelRequestsHandler_v3(CustomLogger): if stash is not None and reserved_tokens > 0: stash.reservation_released = True except Exception as e: - verbose_proxy_logger.exception(f"Error in rate limit failure event: {e}") + verbose_proxy_logger.exception("Error in rate limit failure event: %s", e) async def async_release_max_parallel_requests_on_disconnect( self, @@ -3183,7 +3191,7 @@ class _PROXY_MaxParallelRequestsHandler_v3(CustomLogger): ) except Exception as e: - verbose_proxy_logger.exception(f"Error in rate limit post-call hook: {e}") + verbose_proxy_logger.exception("Error in rate limit post-call hook: %s", e) async def async_post_call_failure_hook( self, @@ -3231,12 +3239,14 @@ class _PROXY_MaxParallelRequestsHandler_v3(CustomLogger): reserved_tokens=reserved_tokens, ) if ops: - verbose_proxy_logger.debug(f"Releasing reserved TPM tokens on proxy-level rejection: {reserved_tokens}") + verbose_proxy_logger.debug( + "Releasing reserved TPM tokens on proxy-level rejection: %s", reserved_tokens + ) await self.internal_usage_cache.dual_cache.async_increment_cache_pipeline( increment_list=ops, litellm_parent_otel_span=user_api_key_dict.parent_otel_span, ) stash.reservation_released = True except Exception as e: - verbose_proxy_logger.exception(f"Error releasing TPM reservation on post-call failure: {e}") + verbose_proxy_logger.exception("Error releasing TPM reservation on post-call failure: %s", e) return diff --git a/litellm/proxy/hooks/prompt_injection_detection.py b/litellm/proxy/hooks/prompt_injection_detection.py index e7192b9b063..1cb80bc37f6 100644 --- a/litellm/proxy/hooks/prompt_injection_detection.py +++ b/litellm/proxy/hooks/prompt_injection_detection.py @@ -197,7 +197,7 @@ class _OPTIONAL_PromptInjectionDetection(CustomLogger): raise e except Exception as e: verbose_proxy_logger.exception( - f"litellm.proxy.hooks.prompt_injection_detection.py::async_pre_call_hook(): Exception occured - {e}" + "litellm.proxy.hooks.prompt_injection_detection.py::async_pre_call_hook(): Exception occured - %s", e ) async def async_moderation_hook( # type: ignore diff --git a/litellm/proxy/hooks/proxy_track_cost_callback.py b/litellm/proxy/hooks/proxy_track_cost_callback.py index 0319a680714..e58923fa416 100644 --- a/litellm/proxy/hooks/proxy_track_cost_callback.py +++ b/litellm/proxy/hooks/proxy_track_cost_callback.py @@ -195,7 +195,9 @@ class _ProxyDBLogger(CustomLogger): verbose_proxy_logger.debug("INSIDE _PROXY_track_cost_callback") try: verbose_proxy_logger.debug( - f"kwargs stream: {kwargs.get('stream', None)} + complete streaming response: {kwargs.get('complete_streaming_response', None)}" + "kwargs stream: %s + complete streaming response: %s", + kwargs.get("stream", None), + kwargs.get("complete_streaming_response", None), ) parent_otel_span = _get_parent_otel_span_from_kwargs(kwargs=kwargs) litellm_params = kwargs.get("litellm_params", {}) or {} @@ -225,10 +227,14 @@ class _ProxyDBLogger(CustomLogger): user_api_key = metadata.get("user_api_key", None) if kwargs.get("cache_hit", False) is True: response_cost = 0.0 - verbose_proxy_logger.debug(f"Cache Hit: response_cost {response_cost}, for user_id {user_id}") + verbose_proxy_logger.debug("Cache Hit: response_cost %s, for user_id %s", response_cost, user_id) verbose_proxy_logger.debug( - f"user_api_key {user_api_key}, user_id {user_id}, team_id {team_id}, end_user_id {end_user_id}" + "user_api_key %s, user_id %s, team_id %s, end_user_id %s", + user_api_key, + user_id, + team_id, + end_user_id, ) call_type: str | None = kwargs.get("call_type") if _should_track_cost_callback( diff --git a/litellm/proxy/hooks/responses_id_security.py b/litellm/proxy/hooks/responses_id_security.py index 8b6bfd95892..5a8abcc9324 100644 --- a/litellm/proxy/hooks/responses_id_security.py +++ b/litellm/proxy/hooks/responses_id_security.py @@ -83,7 +83,9 @@ class ResponsesIDSecurity(CustomLogger): if response_id_user_id and response_id_user_id != user_api_key_dict.user_id: if general_settings.get("disable_responses_id_security", False): verbose_proxy_logger.debug( - f"Responses ID Security is disabled. User {user_api_key_dict.user_id} is accessing response id {response_id_user_id} which is not associated with them." + "Responses ID Security is disabled. User %s is accessing response id %s which is not associated with them.", + user_api_key_dict.user_id, + response_id_user_id, ) return True raise HTTPException( @@ -94,7 +96,10 @@ class ResponsesIDSecurity(CustomLogger): if response_id_team_id and response_id_team_id != user_api_key_dict.team_id: if general_settings.get("disable_responses_id_security", False): verbose_proxy_logger.debug( - f"Responses ID Security is disabled. Response belongs to team {response_id_team_id} but user {user_api_key_dict.user_id} is accessing it with team id {user_api_key_dict.team_id}." + "Responses ID Security is disabled. Response belongs to team %s but user %s is accessing it with team id %s.", + response_id_team_id, + user_api_key_dict.user_id, + user_api_key_dict.team_id, ) return True raise HTTPException( diff --git a/litellm/proxy/hooks/user_management_event_hooks.py b/litellm/proxy/hooks/user_management_event_hooks.py index b242f763fcb..b434bc001b9 100644 --- a/litellm/proxy/hooks/user_management_event_hooks.py +++ b/litellm/proxy/hooks/user_management_event_hooks.py @@ -71,7 +71,7 @@ class UserManagementEventHooks: ) ) except Exception as e: - verbose_proxy_logger.warning(f"Unable to create audit log for user on `/user/new` - {e}") + verbose_proxy_logger.warning("Unable to create audit log for user on `/user/new` - %s", e) @staticmethod async def async_send_user_invitation_email( diff --git a/litellm/proxy/image_endpoints/endpoints.py b/litellm/proxy/image_endpoints/endpoints.py index 36f702e1b4b..04e3982b412 100644 --- a/litellm/proxy/image_endpoints/endpoints.py +++ b/litellm/proxy/image_endpoints/endpoints.py @@ -185,7 +185,7 @@ async def image_generation( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.error(f"litellm.proxy.proxy_server.image_generation(): Exception occured - {e}") + verbose_proxy_logger.error("litellm.proxy.proxy_server.image_generation(): Exception occured - %s", e) verbose_proxy_logger.debug(traceback.format_exc()) if isinstance(e, HTTPException): raise ProxyException( diff --git a/litellm/proxy/litellm_pre_call_utils.py b/litellm/proxy/litellm_pre_call_utils.py index 6864caccea2..5b9a9c9a202 100644 --- a/litellm/proxy/litellm_pre_call_utils.py +++ b/litellm/proxy/litellm_pre_call_utils.py @@ -905,7 +905,7 @@ class LiteLLMProxyRequestSetup: user = LiteLLMProxyRequestSetup._get_case_insensitive_header(headers, header_name) if user is not None: - verbose_logger.info(f'found user "{user}" in header "{header_name}"') + verbose_logger.info('found user "%s" in header "%s"', user, header_name) return user @@ -918,7 +918,7 @@ class LiteLLMProxyRequestSetup: return None for header, value in headers.items(): if header.lower() == "openai-organization": - verbose_logger.info(f"found openai org id: {value}, sending to llm") + verbose_logger.info("found openai org id: %s, sending to llm", value) return value return None @@ -1059,14 +1059,14 @@ class LiteLLMProxyRequestSetup: if agent_id_from_header: metadata_from_headers["agent_id"] = agent_id_from_header - verbose_proxy_logger.debug(f"Extracted agent_id from header: {agent_id_from_header}") + verbose_proxy_logger.debug("Extracted agent_id from header: %s", agent_id_from_header) if chain_id: metadata_from_headers["trace_id"] = chain_id metadata_from_headers["session_id"] = chain_id data["litellm_session_id"] = chain_id data["litellm_trace_id"] = chain_id - verbose_proxy_logger.debug(f"Extracted chain_id from header (trace-id/session-id): {chain_id}") + verbose_proxy_logger.debug("Extracted chain_id from header (trace-id/session-id): %s", chain_id) else: body_metadata = data.get("metadata") session_id = _get_anthropic_session_id_from_metadata(body_metadata) @@ -1475,8 +1475,8 @@ async def add_litellm_data_to_request( allow_client_message_redaction_opt_out=_allow_client_message_redaction_opt_out, ) _logging_safe_headers = redact_credential_headers(_headers) - verbose_proxy_logger.debug(f"Request Headers: {_logging_safe_headers}") - verbose_proxy_logger.debug(f"Raw Headers: {_raw_headers}") + verbose_proxy_logger.debug("Request Headers: %s", _logging_safe_headers) + verbose_proxy_logger.debug("Raw Headers: %s", _raw_headers) if forward_llm_auth and "x-api-key" in _headers: data["api_key"] = _headers["x-api-key"] @@ -1579,7 +1579,7 @@ async def add_litellm_data_to_request( data["metadata"] = safe_json_loads(data["metadata"]) if not isinstance(data["metadata"], dict): verbose_proxy_logger.warning( - f"Failed to parse 'metadata' as JSON dict. Received value: {data['metadata']}" + "Failed to parse 'metadata' as JSON dict. Received value: %s", data["metadata"] ) # requester_metadata is snapshotted AFTER the strip below so # downstream consumers (e.g. PANW guardrail reading user_ip / @@ -1592,7 +1592,7 @@ async def add_litellm_data_to_request( parsed_litellm_metadata = safe_json_loads(data["litellm_metadata"]) if not isinstance(parsed_litellm_metadata, dict): verbose_proxy_logger.warning( - f"Failed to parse 'litellm_metadata' as JSON dict. Received value: {data['litellm_metadata']}" + "Failed to parse 'litellm_metadata' as JSON dict. Received value: %s", data["litellm_metadata"] ) else: data["litellm_metadata"] = parsed_litellm_metadata @@ -2409,7 +2409,7 @@ def _add_guardrails_from_policies_in_metadata( if not policy_names: return - verbose_proxy_logger.debug(f"Policy engine: resolving guardrails from key/team policies: {policy_names}") + verbose_proxy_logger.debug("Policy engine: resolving guardrails from key/team policies: %s", policy_names) # Check if policy registry is initialized registry = get_policy_registry() @@ -2434,10 +2434,10 @@ def _add_guardrails_from_policies_in_metadata( ) resolved_guardrails.update(resolved_policy.guardrails) verbose_proxy_logger.debug( - f"Policy engine: resolved guardrails from policy '{policy_name}': {resolved_policy.guardrails}" + "Policy engine: resolved guardrails from policy '%s': %s", policy_name, resolved_policy.guardrails ) else: - verbose_proxy_logger.warning(f"Policy engine: policy '{policy_name}' not found in registry") + verbose_proxy_logger.warning("Policy engine: policy '%s' not found in registry", policy_name) if not resolved_guardrails: return @@ -2461,7 +2461,7 @@ def _add_guardrails_from_policies_in_metadata( data[metadata_variable_name]["applied_policies"].extend(list(policy_names)) verbose_proxy_logger.debug( - f"Policy engine: added guardrails from key/team policies to request metadata: {list(resolved_guardrails)}" + "Policy engine: added guardrails from key/team policies to request metadata: %s", list(resolved_guardrails) ) @@ -2592,13 +2592,13 @@ def _match_and_track_policies( matching_policy_names = [m["policy_name"] for m in matches_with_reasons] policy_reasons = {m["policy_name"]: m["matched_via"] for m in matches_with_reasons} - verbose_proxy_logger.debug(f"Policy engine: matched policies via attachments: {matching_policy_names}") + verbose_proxy_logger.debug("Policy engine: matched policies via attachments: %s", matching_policy_names) # Combine attachment-based policies with dynamic request body policies all_policy_names = set(matching_policy_names) if request_body_policies and isinstance(request_body_policies, list): all_policy_names.update(request_body_policies) - verbose_proxy_logger.debug(f"Policy engine: added dynamic policies from request body: {request_body_policies}") + verbose_proxy_logger.debug("Policy engine: added dynamic policies from request body: %s", request_body_policies) if not all_policy_names: return [], {} @@ -2610,7 +2610,7 @@ def _match_and_track_policies( policies=policies_override, ) - verbose_proxy_logger.debug(f"Policy engine: applied policies (conditions matched): {applied_policy_names}") + verbose_proxy_logger.debug("Policy engine: applied policies (conditions matched): %s", applied_policy_names) # Track applied policies in metadata for response headers for policy_name in applied_policy_names: @@ -2641,7 +2641,7 @@ def _apply_resolved_guardrails_to_metadata( policy_names=policy_names, ) - verbose_proxy_logger.debug(f"Policy engine: resolved guardrails: {resolved_guardrails}") + verbose_proxy_logger.debug("Policy engine: resolved guardrails: %s", resolved_guardrails) # Resolve pipelines from matching policies pipelines = PolicyResolver.resolve_pipelines_for_context( @@ -2661,7 +2661,9 @@ def _apply_resolved_guardrails_to_metadata( data[metadata_variable_name]["_guardrail_pipelines"] = pipelines data[metadata_variable_name]["_pipeline_managed_guardrails"] = pipeline_managed_guardrails verbose_proxy_logger.debug( - f"Policy engine: resolved {len(pipelines)} pipeline(s), managed guardrails: {pipeline_managed_guardrails}" + "Policy engine: resolved %s pipeline(s), managed guardrails: %s", + len(pipelines), + pipeline_managed_guardrails, ) if not resolved_guardrails and not pipelines: @@ -2678,7 +2680,7 @@ def _apply_resolved_guardrails_to_metadata( combined -= pipeline_managed_guardrails data[metadata_variable_name]["guardrails"] = list(combined) - verbose_proxy_logger.debug(f"Policy engine: added guardrails to request metadata: {list(combined)}") + verbose_proxy_logger.debug("Policy engine: added guardrails to request metadata: %s", list(combined)) async def add_guardrails_from_policy_engine( @@ -2714,8 +2716,9 @@ async def add_guardrails_from_policy_engine( registry = get_policy_registry() verbose_proxy_logger.debug( - f"Policy engine: registry initialized={registry.is_initialized()}, " - f"policy_count={len(registry.get_all_policies())}" + "Policy engine: registry initialized=%s, policy_count=%s", + registry.is_initialized(), + len(registry.get_all_policies()), ) if not registry.is_initialized(): verbose_proxy_logger.debug("Policy engine not initialized, skipping policy matching") @@ -2733,8 +2736,11 @@ async def add_guardrails_from_policy_engine( ) verbose_proxy_logger.debug( - f"Policy engine: matching policies for context team_alias={context.team_alias}, " - f"key_alias={context.key_alias}, model={context.model}, tags={context.tags}" + "Policy engine: matching policies for context team_alias=%s, key_alias=%s, model=%s, tags=%s", + context.team_alias, + context.key_alias, + context.model, + context.tags, ) # Separate policy names from policy version IDs (policy_) @@ -2760,9 +2766,9 @@ async def add_guardrails_from_policy_engine( pname, policy = result merged_policies[pname] = policy fetched_policy_names.append(pname) - verbose_proxy_logger.debug(f"Policy engine: loaded version by ID policy_{policy_id} -> {pname}") + verbose_proxy_logger.debug("Policy engine: loaded version by ID policy_%s -> %s", policy_id, pname) else: - verbose_proxy_logger.debug(f"Policy engine: policy version {policy_id} not found in cache, skipping") + verbose_proxy_logger.debug("Policy engine: policy version %s not found in cache, skipping", policy_id) # Build request body list: names + policy names from fetched versions request_body_policies = request_body_names + fetched_policy_names diff --git a/litellm/proxy/management_endpoints/cache_settings_endpoints.py b/litellm/proxy/management_endpoints/cache_settings_endpoints.py index 14a42811b07..12810553891 100644 --- a/litellm/proxy/management_endpoints/cache_settings_endpoints.py +++ b/litellm/proxy/management_endpoints/cache_settings_endpoints.py @@ -386,7 +386,8 @@ class CacheSettingsManager: verbose_proxy_logger.info("Cache settings initialized from database") except Exception as e: verbose_proxy_logger.exception( - f"litellm.proxy.management_endpoints.cache_settings_endpoints.py::CacheSettingsManager::init_cache_settings_in_db - {e}" + "litellm.proxy.management_endpoints.cache_settings_endpoints.py::CacheSettingsManager::init_cache_settings_in_db - %s", + e, ) @staticmethod @@ -480,7 +481,7 @@ async def get_cache_settings( redis_type_descriptions=REDIS_TYPE_DESCRIPTIONS, ) except Exception as e: - verbose_proxy_logger.error(f"Error fetching cache settings: {e}") + verbose_proxy_logger.error("Error fetching cache settings: %s", e) raise HTTPException(status_code=500, detail=f"Error fetching cache settings: {e}") @@ -539,7 +540,7 @@ async def test_cache_connection( return CacheTestResponse(**result) except Exception as e: - verbose_proxy_logger.error(f"Error testing cache connection: {e}") + verbose_proxy_logger.error("Error testing cache connection: %s", e) return CacheTestResponse( status="failed", message=f"Cache connection test failed: {e}", @@ -652,5 +653,5 @@ async def update_cache_settings( "settings": _redact_credentials(cache_settings), } except Exception as e: - verbose_proxy_logger.error(f"Error updating cache settings: {e}") + verbose_proxy_logger.error("Error updating cache settings: %s", e) raise HTTPException(status_code=500, detail=f"Error updating cache settings: {e}") diff --git a/litellm/proxy/management_endpoints/common_daily_activity.py b/litellm/proxy/management_endpoints/common_daily_activity.py index 0dc85f98786..ac20ad44d06 100644 --- a/litellm/proxy/management_endpoints/common_daily_activity.py +++ b/litellm/proxy/management_endpoints/common_daily_activity.py @@ -993,7 +993,7 @@ async def get_daily_activity( ) except Exception as e: - verbose_proxy_logger.exception(f"Error fetching daily activity: {e}") + verbose_proxy_logger.exception("Error fetching daily activity: %s", e) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail={"error": f"Failed to fetch analytics: {e}"}, @@ -1082,7 +1082,7 @@ async def get_daily_activity_aggregated( ) except Exception as e: - verbose_proxy_logger.exception(f"Error fetching aggregated daily activity: {e}") + verbose_proxy_logger.exception("Error fetching aggregated daily activity: %s", e) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail={"error": f"Failed to fetch analytics: {e}"}, diff --git a/litellm/proxy/management_endpoints/common_utils.py b/litellm/proxy/management_endpoints/common_utils.py index abb1b686d1d..387d4421188 100644 --- a/litellm/proxy/management_endpoints/common_utils.py +++ b/litellm/proxy/management_endpoints/common_utils.py @@ -222,7 +222,7 @@ async def _user_has_admin_privileges( except Exception as e: # If there's an error checking, default to False for security - verbose_proxy_logger.debug(f"Error checking admin privileges for user {user_api_key_dict.user_id}: {e}") + verbose_proxy_logger.debug("Error checking admin privileges for user %s: %s", user_api_key_dict.user_id, e) return False return False @@ -366,7 +366,7 @@ async def admin_can_invite_user( return False except Exception as e: - verbose_proxy_logger.debug(f"Error checking invite permission for user {user_api_key_dict.user_id}: {e}") + verbose_proxy_logger.debug("Error checking invite permission for user %s: %s", user_api_key_dict.user_id, e) return False diff --git a/litellm/proxy/management_endpoints/cost_tracking_settings.py b/litellm/proxy/management_endpoints/cost_tracking_settings.py index f2295452f4d..d199cea5fd3 100644 --- a/litellm/proxy/management_endpoints/cost_tracking_settings.py +++ b/litellm/proxy/management_endpoints/cost_tracking_settings.py @@ -59,7 +59,7 @@ def _resolve_model_for_cost_lookup(model: str) -> tuple[str, str | None]: # Check base_model first (needed for Azure custom deployment names) base_model = model_info.get("base_model") or litellm_params.get("base_model") if base_model: - verbose_proxy_logger.debug(f"Resolved model '{model}' to base_model '{base_model}' from router") + verbose_proxy_logger.debug("Resolved model '%s' to base_model '%s' from router", model, base_model) custom_llm_provider = litellm_params.get("custom_llm_provider") return ( str(base_model), @@ -69,14 +69,14 @@ def _resolve_model_for_cost_lookup(model: str) -> tuple[str, str | None]: resolved_model = litellm_params.get("model") if resolved_model: - verbose_proxy_logger.debug(f"Resolved model '{model}' to '{resolved_model}' from router") + verbose_proxy_logger.debug("Resolved model '%s' to '%s' from router", model, resolved_model) custom_llm_provider = litellm_params.get("custom_llm_provider") return ( str(resolved_model), (str(custom_llm_provider) if custom_llm_provider is not None else None), ) except Exception as e: - verbose_proxy_logger.debug(f"Could not resolve model '{model}' from router: {e}") + verbose_proxy_logger.debug("Could not resolve model '%s' from router: %s", model, e) # Return original model if not resolved return model, custom_llm_provider @@ -129,7 +129,7 @@ async def get_cost_discount_config( return {"values": cost_discount_config} except Exception as e: - verbose_proxy_logger.error(f"Error fetching cost discount config: {e}") + verbose_proxy_logger.error("Error fetching cost discount config: %s", e) return {"values": {}} @@ -216,7 +216,7 @@ async def update_cost_discount_config( # Update in-memory litellm.cost_discount_config litellm.cost_discount_config = cost_discount_config - verbose_proxy_logger.info(f"Updated cost_discount_config: {cost_discount_config}") + verbose_proxy_logger.info("Updated cost_discount_config: %s", cost_discount_config) return { "message": "Cost discount configuration updated successfully", @@ -224,7 +224,7 @@ async def update_cost_discount_config( "values": cost_discount_config, } except Exception as e: - verbose_proxy_logger.error(f"Error updating cost discount config: {e}") + verbose_proxy_logger.error("Error updating cost discount config: %s", e) raise HTTPException( status_code=500, detail={"error": f"Failed to update cost discount config: {e}"}, @@ -262,7 +262,7 @@ async def get_cost_margin_config( return {"values": cost_margin_config} except Exception as e: - verbose_proxy_logger.error(f"Error fetching cost margin config: {e}") + verbose_proxy_logger.error("Error fetching cost margin config: %s", e) return {"values": {}} @@ -390,7 +390,7 @@ async def update_cost_margin_config( # Update in-memory litellm.cost_margin_config litellm.cost_margin_config = cost_margin_config - verbose_proxy_logger.info(f"Updated cost_margin_config: {cost_margin_config}") + verbose_proxy_logger.info("Updated cost_margin_config: %s", cost_margin_config) return { "message": "Cost margin configuration updated successfully", @@ -398,7 +398,7 @@ async def update_cost_margin_config( "values": cost_margin_config, } except Exception as e: - verbose_proxy_logger.error(f"Error updating cost margin config: {e}") + verbose_proxy_logger.error("Error updating cost margin config: %s", e) raise HTTPException( status_code=500, detail={"error": f"Failed to update cost margin config: {e}"}, @@ -450,7 +450,7 @@ async def estimate_cost( # Resolve model name (handles router aliases like 'e-model-router' -> 'azure_ai/gpt-4') resolved_model, resolved_provider = _resolve_model_for_cost_lookup(request.model) - verbose_proxy_logger.debug(f"Cost estimate: request.model='{request.model}' resolved to '{resolved_model}'") + verbose_proxy_logger.debug("Cost estimate: request.model='%s' resolved to '%s'", request.model, resolved_model) # Create a mock response with usage for completion_cost mock_response = ModelResponse( diff --git a/litellm/proxy/management_endpoints/customer_endpoints.py b/litellm/proxy/management_endpoints/customer_endpoints.py index ff384190d31..ab59ee65a0a 100644 --- a/litellm/proxy/management_endpoints/customer_endpoints.py +++ b/litellm/proxy/management_endpoints/customer_endpoints.py @@ -103,7 +103,7 @@ async def block_user(data: BlockUsers): return {"blocked_users": records} except Exception as e: - verbose_proxy_logger.error(f"An error occurred - {e}") + verbose_proxy_logger.error("An error occurred - %s", e) raise HTTPException(status_code=500, detail={"error": str(e)}) @@ -377,7 +377,8 @@ async def new_end_user( # It should have been converted to object_permission_id by _set_object_permission if "object_permission" in new_end_user_obj: verbose_proxy_logger.warning( - f"object_permission still in new_end_user_obj after _set_object_permission: {new_end_user_obj.get('object_permission')}" + "object_permission still in new_end_user_obj after _set_object_permission: %s", + new_end_user_obj.get("object_permission"), ) new_end_user_obj.pop("object_permission", None) @@ -390,7 +391,7 @@ async def new_end_user( return _to_customer_response(end_user_record) except Exception as e: verbose_proxy_logger.exception( - f"litellm.proxy.management_endpoints.customer_endpoints.new_end_user(): Exception occured - {e}" + "litellm.proxy.management_endpoints.customer_endpoints.new_end_user(): Exception occured - %s", e ) if "Unique constraint failed on the fields: (`user_id`)" in str(e): raise ProxyException( @@ -455,7 +456,7 @@ async def end_user_info( except Exception as e: verbose_proxy_logger.exception( - f"litellm.proxy.management_endpoints.customer_endpoints.end_user_info(): Exception occured - {e}" + "litellm.proxy.management_endpoints.customer_endpoints.end_user_info(): Exception occured - %s", e ) raise handle_exception_on_proxy(e) @@ -613,7 +614,8 @@ async def update_end_user( # It should have been converted to object_permission_id by handle_update_object_permission_common if "object_permission" in update_end_user_table_data: verbose_proxy_logger.warning( - f"object_permission still in update_end_user_table_data: {update_end_user_table_data.get('object_permission')}" + "object_permission still in update_end_user_table_data: %s", + update_end_user_table_data.get("object_permission"), ) update_end_user_table_data.pop("object_permission", None) @@ -627,7 +629,7 @@ async def update_end_user( ) if response is None: raise ValueError(f"Failed updating customer data. User ID does not exist passed user_id={data.user_id}") - verbose_proxy_logger.debug(f"received response from updating prisma client. response={response}") + verbose_proxy_logger.debug("received response from updating prisma client. response=%s", response) return _to_customer_response(response) else: @@ -636,7 +638,7 @@ async def update_end_user( # update based on remaining passed in values except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.update_end_user(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.update_end_user(): Exception occured - %s", e) raise handle_exception_on_proxy(e) @@ -701,7 +703,7 @@ async def delete_end_user( response = await EndUserRepository(prisma_client).table.delete_many( where={"user_id": {"in": data.user_ids}} ) - verbose_proxy_logger.debug(f"received response from updating prisma client. response={response}") + verbose_proxy_logger.debug("received response from updating prisma client. response=%s", response) return DeleteCustomersResponse( deleted_customers=response, message="Successfully deleted customers with ids: " + str(data.user_ids), @@ -711,7 +713,7 @@ async def delete_end_user( # update based on remaining passed in values except Exception as e: - verbose_proxy_logger.error(f"litellm.proxy.proxy_server.delete_end_user(): Exception occured - {e}") + verbose_proxy_logger.error("litellm.proxy.proxy_server.delete_end_user(): Exception occured - %s", e) raise handle_exception_on_proxy(e) @@ -767,7 +769,7 @@ async def list_end_user( except Exception as e: verbose_proxy_logger.exception( - f"litellm.proxy.management_endpoints.customer_endpoints.list_end_user(): Exception occured - {e}" + "litellm.proxy.management_endpoints.customer_endpoints.list_end_user(): Exception occured - %s", e ) raise handle_exception_on_proxy(e) diff --git a/litellm/proxy/management_endpoints/fallback_management_endpoints.py b/litellm/proxy/management_endpoints/fallback_management_endpoints.py index 3df5384b551..00dc4f0f23b 100644 --- a/litellm/proxy/management_endpoints/fallback_management_endpoints.py +++ b/litellm/proxy/management_endpoints/fallback_management_endpoints.py @@ -169,7 +169,7 @@ async def create_fallback( setattr(llm_router, fallback_key, existing_fallbacks) verbose_proxy_logger.info( - f"Fallback configured: {data.model} -> {data.fallback_models} (type: {data.fallback_type})" + "Fallback configured: %s -> %s (type: %s)", data.model, data.fallback_models, data.fallback_type ) return FallbackResponse( @@ -182,7 +182,7 @@ async def create_fallback( except HTTPException: raise except Exception as e: - verbose_proxy_logger.error(f"Error creating fallback: {e}", exc_info=True) + verbose_proxy_logger.error("Error creating fallback: %s", e, exc_info=True) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail={"error": f"Failed to create fallback: {e}"}, @@ -239,7 +239,7 @@ async def get_fallback( except HTTPException: raise except Exception as e: - verbose_proxy_logger.error(f"Error getting fallback: {e}", exc_info=True) + verbose_proxy_logger.error("Error getting fallback: %s", e, exc_info=True) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail={"error": f"Failed to get fallback: {e}"}, @@ -339,7 +339,7 @@ async def delete_fallback( # Update the in-memory router configuration setattr(llm_router, fallback_key, updated_fallbacks) - verbose_proxy_logger.info(f"Fallback deleted: {model} (type: {fallback_type})") + verbose_proxy_logger.info("Fallback deleted: %s (type: %s)", model, fallback_type) return FallbackDeleteResponse( model=model, @@ -350,7 +350,7 @@ async def delete_fallback( except HTTPException: raise except Exception as e: - verbose_proxy_logger.error(f"Error deleting fallback: {e}", exc_info=True) + verbose_proxy_logger.error("Error deleting fallback: %s", e, exc_info=True) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail={"error": f"Failed to delete fallback: {e}"}, diff --git a/litellm/proxy/management_endpoints/internal_user_endpoints.py b/litellm/proxy/management_endpoints/internal_user_endpoints.py index 8e31b1f6e62..0f159000fb2 100644 --- a/litellm/proxy/management_endpoints/internal_user_endpoints.py +++ b/litellm/proxy/management_endpoints/internal_user_endpoints.py @@ -330,7 +330,8 @@ async def _add_user_to_team( except HTTPException as e: if e.status_code == 400 and ("already exists" in str(e) or "doesn't exist" in str(e)): verbose_proxy_logger.debug( - f"litellm.proxy.management_endpoints.internal_user_endpoints.new_user(): User already exists in team - {e}" + "litellm.proxy.management_endpoints.internal_user_endpoints.new_user(): User already exists in team - %s", + e, ) else: verbose_proxy_logger.error( @@ -348,7 +349,8 @@ async def _add_user_to_team( and ProxyErrorTypes.team_member_already_in_team in e.type ): verbose_proxy_logger.debug( - f"litellm.proxy.management_endpoints.internal_user_endpoints.new_user(): User already exists in team - {e}" + "litellm.proxy.management_endpoints.internal_user_endpoints.new_user(): User already exists in team - %s", + e, ) else: verbose_proxy_logger.error( @@ -605,7 +607,7 @@ async def new_user( return new_user_response except Exception as e: - verbose_proxy_logger.exception(f"/user/new: Exception occured - {e}") + verbose_proxy_logger.exception("/user/new: Exception occured - %s", e) raise handle_exception_on_proxy(e) @@ -900,7 +902,7 @@ async def user_info( return response_data except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.user_info(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.user_info(): Exception occured - %s", e) raise handle_exception_on_proxy(e) @@ -1050,7 +1052,7 @@ async def user_info_v2( object_permission=user_data.get("object_permission"), ) except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.user_info_v2(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.user_info_v2(): Exception occured - %s", e) raise handle_exception_on_proxy(e) @@ -1233,7 +1235,7 @@ async def _schedule_user_update_audit_log( ) ) except Exception as audit_error: - verbose_proxy_logger.warning(f"Failed to create audit log for user {response.get('user_id')}: {audit_error}") + verbose_proxy_logger.warning("Failed to create audit log for user %s: %s", response.get("user_id"), audit_error) def _check_user_update_authz( @@ -1320,7 +1322,7 @@ async def _invalidate_cached_user_entitlement(user_id: str | None, object_permis try: await user_api_key_cache.async_delete_cache(key=key) except Exception as e: # noqa: BLE001 # a cache we cannot clear still expires; never fail the write - verbose_proxy_logger.warning(f"Failed to invalidate cached entitlement key {key!r}: {e}") + verbose_proxy_logger.warning("Failed to invalidate cached entitlement key %r: %s", key, e) async def _update_single_user_helper( @@ -1569,7 +1571,7 @@ async def user_update( ) return response except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.user_update(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.user_update(): Exception occured - %s", e) verbose_proxy_logger.debug(traceback.format_exc()) if isinstance(e, HTTPException): raise ProxyException( @@ -1618,12 +1620,12 @@ async def bulk_update_processed_users( successful_updates += 1 except Exception as e: verbose_proxy_logger.exception( - f"Failed to update user {user_request.user_id or user_request.user_email}: {e}" + "Failed to update user %s: %s", user_request.user_id or user_request.user_email, e ) # Record failure error_message = str(e) verbose_proxy_logger.error( - f"Failed to update user {user_request.user_id or user_request.user_email}: {error_message}" + "Failed to update user %s: %s", user_request.user_id or user_request.user_email, error_message ) results.append( @@ -1643,7 +1645,7 @@ async def bulk_update_processed_users( failed_updates=failed_updates, ) except Exception as e: - verbose_proxy_logger.exception(f"Failed to update users: {e}") + verbose_proxy_logger.exception("Failed to update users: %s", e) raise HTTPException(status_code=500, detail={"error": str(e)}) @@ -1806,10 +1808,10 @@ async def bulk_user_update( ) ) except Exception as audit_error: - verbose_proxy_logger.warning(f"Failed to create bulk audit log: {audit_error}") + verbose_proxy_logger.warning("Failed to create bulk audit log: %s", audit_error) except Exception as e: - verbose_proxy_logger.exception(f"Failed to perform bulk update: {e}") + verbose_proxy_logger.exception("Failed to perform bulk update: %s", e) # Fall back to individual updates if bulk update fails for user in all_users_in_db: user_update_request = data.user_updates.model_copy() @@ -2133,7 +2135,7 @@ async def get_users( else: user_key_counts = {} - verbose_proxy_logger.debug(f"Total count of users: {total_count}") + verbose_proxy_logger.debug("Total count of users: %s", total_count) # Calculate total pages total_pages = -(-total_count // page_size) # Ceiling division @@ -2593,7 +2595,7 @@ async def ui_view_users( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error searching users: {e}") + verbose_proxy_logger.exception("Error searching users: %s", e) raise HTTPException(status_code=500, detail=f"Error searching users: {e}") @@ -2716,7 +2718,7 @@ async def get_user_daily_activity( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"/spend/daily/analytics: Exception occured - {e}") + verbose_proxy_logger.exception("/spend/daily/analytics: Exception occured - %s", e) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail={"error": f"Failed to fetch analytics: {e}"}, @@ -2808,7 +2810,7 @@ async def get_user_daily_activity_aggregated( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"/user/daily/activity/aggregated: Exception occured - {e}") + verbose_proxy_logger.exception("/user/daily/activity/aggregated: Exception occured - %s", e) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail={"error": f"Failed to fetch analytics: {e}"}, diff --git a/litellm/proxy/management_endpoints/key_management_endpoints.py b/litellm/proxy/management_endpoints/key_management_endpoints.py index d4403b3f5db..f37bc6da23e 100644 --- a/litellm/proxy/management_endpoints/key_management_endpoints.py +++ b/litellm/proxy/management_endpoints/key_management_endpoints.py @@ -940,7 +940,7 @@ async def _common_key_generation_helper( data = apply_enterprise_key_management_params(data, team_table) except Exception as e: verbose_proxy_logger.debug( - f"litellm.proxy.proxy_server.generate_key_fn(): Enterprise key management params not applied - {e}" + "litellm.proxy.proxy_server.generate_key_fn(): Enterprise key management params not applied - %s", e ) # TODO: @ishaan-jaff: Migrate all budget tracking to use LiteLLM_BudgetTable @@ -1693,7 +1693,7 @@ async def generate_key_fn( check_db_only=True, ) except Exception as e: - verbose_proxy_logger.debug(f"Error getting team object in `/key/generate`: {e}") + verbose_proxy_logger.debug("Error getting team object in `/key/generate`: %s", e) # For non-admin callers, team must exist (LIT-1884) if not _is_proxy_admin: raise HTTPException( @@ -1732,7 +1732,7 @@ async def generate_key_fn( ) except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.generate_key_fn(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.generate_key_fn(): Exception occured - %s", e) raise handle_exception_on_proxy(e) @@ -1866,7 +1866,7 @@ async def generate_service_account_key_fn( check_db_only=True, ) except Exception as e: - verbose_proxy_logger.debug(f"Error getting team object in `/key/generate`: {e}") + verbose_proxy_logger.debug("Error getting team object in `/key/generate`: %s", e) team_table = None if team_table is not None: @@ -1934,7 +1934,9 @@ def prepare_metadata_fields(data: BaseModel, non_default_values: dict, existing_ casted_metadata[k] = v except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.prepare_metadata_fields(): Exception occured - {e}") + verbose_proxy_logger.exception( + "litellm.proxy.proxy_server.prepare_metadata_fields(): Exception occured - %s", e + ) non_default_values["metadata"] = encrypt_callback_vars(casted_metadata) return non_default_values @@ -2052,7 +2054,7 @@ async def _handle_update_object_permission( # Add the object_permission_id to data_json if one was created/updated if object_permission_id is not None: data_json["object_permission_id"] = object_permission_id - verbose_proxy_logger.debug(f"updated object_permission_id: {object_permission_id}") + verbose_proxy_logger.debug("updated object_permission_id: %s", object_permission_id) return data_json @@ -2797,7 +2799,7 @@ async def update_key_fn( return {"key": key, **response["data"]} # update based on remaining passed in values except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.update_key_fn(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.update_key_fn(): Exception occured - %s", e) if isinstance(e, HTTPException): raise ProxyException( message=getattr(e, "detail", f"Authentication Error({e})"), @@ -2935,7 +2937,7 @@ async def bulk_update_keys( ) except Exception as e: - verbose_proxy_logger.exception(f"Failed to update key {key_update_item.key}: {e}") + verbose_proxy_logger.exception("Failed to update key %s: %s", key_update_item.key, e) if isinstance(e, HTTPException): error_detail = e.detail @@ -3175,7 +3177,7 @@ async def bulk_update_team_keys( except Exception as e: # Log the hashed prefix — `token` may be a raw sk-... and ERROR logs persist. - verbose_proxy_logger.exception(f"Failed to update key {db_token[:12]}... in team {data.team_id}: {e}") + verbose_proxy_logger.exception("Failed to update key %s... in team %s: %s", db_token[:12], data.team_id, e) failed_updates.append( _build_failed_team_key_update( token=token, @@ -3305,7 +3307,7 @@ async def delete_key_fn( litellm_changed_by = None ## only allow user to delete keys they own - verbose_proxy_logger.debug(f"user_api_key_dict.user_role: {user_api_key_dict.user_role}") + verbose_proxy_logger.debug("user_api_key_dict.user_role: %s", user_api_key_dict.user_role) num_keys_to_be_deleted = 0 deleted_keys = [] @@ -3338,7 +3340,7 @@ async def delete_key_fn( param="keys", code=status.HTTP_500_INTERNAL_SERVER_ERROR, ) - verbose_proxy_logger.debug(f"/key/delete - deleted_keys={number_deleted_keys}") + verbose_proxy_logger.debug("/key/delete - deleted_keys=%s", number_deleted_keys) try: assert num_keys_to_be_deleted == len(deleted_keys) @@ -3351,7 +3353,7 @@ async def delete_key_fn( ) verbose_proxy_logger.debug( - f"/keys/delete - cache after delete: {user_api_key_cache.in_memory_cache.cache_dict}" + "/keys/delete - cache after delete: %s", user_api_key_cache.in_memory_cache.cache_dict ) asyncio.create_task( @@ -3366,7 +3368,7 @@ async def delete_key_fn( return {"deleted_keys": deleted_keys} except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.delete_key_fn(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.delete_key_fn(): Exception occured - %s", e) raise handle_exception_on_proxy(e) @@ -3906,7 +3908,7 @@ async def generate_key_helper_fn( # If it's not valid JSON/YAML, keep as is or set to empty dict key_data["router_settings"] = {} except Exception as e: - verbose_proxy_logger.error(f"litellm.proxy.proxy_server.generate_key_helper_fn(): Exception occured - {e}") + verbose_proxy_logger.error("litellm.proxy.proxy_server.generate_key_helper_fn(): Exception occured - %s", e) verbose_proxy_logger.debug(traceback.format_exc()) if isinstance(e, HTTPException): raise e @@ -4113,7 +4115,7 @@ async def delete_verification_tokens( raise Exception("DB not connected. prisma_client is None") except Exception as e: verbose_proxy_logger.exception( - f"litellm.proxy.proxy_server.delete_verification_tokens(): Exception occured - {e}" + "litellm.proxy.proxy_server.delete_verification_tokens(): Exception occured - %s", e ) verbose_proxy_logger.debug(traceback.format_exc()) raise e @@ -4385,10 +4387,10 @@ async def _rotate_master_key( }, ) except Exception as e: - verbose_proxy_logger.error(f"Failed to re-encrypt credential {cred.credential_name}: {e}") + verbose_proxy_logger.error("Failed to re-encrypt credential %s: %s", cred.credential_name, e) # Continue with next credential instead of failing entire rotation continue - verbose_proxy_logger.debug(f"Successfully re-encrypted {len(credentials)} credentials with new master key") + verbose_proxy_logger.debug("Successfully re-encrypted %s credentials with new master key", len(credentials)) def _require_proxy_admin(user_api_key_dict: UserAPIKeyAuth) -> None: @@ -5446,7 +5448,7 @@ async def list_keys( return response except Exception as e: - verbose_proxy_logger.exception(f"Error in list_keys: {e}") + verbose_proxy_logger.exception("Error in list_keys: %s", e) if isinstance(e, HTTPException): raise ProxyException( message=getattr(e, "detail", f"error({e})"), @@ -5585,8 +5587,12 @@ async def key_aliases( total_pages = -(-total_count // size) if total_count > 0 else 0 verbose_proxy_logger.debug( - f"key_aliases: page={page}, size={size}, search={search!r}, " - f"total_count={total_count}, total_pages={total_pages}" + "key_aliases: page=%s, size=%s, search=%r, total_count=%s, total_pages=%s", + page, + size, + search, + total_count, + total_pages, ) return { @@ -5598,7 +5604,7 @@ async def key_aliases( } except Exception as e: - verbose_proxy_logger.exception(f"Error in key_aliases: {e}") + verbose_proxy_logger.exception("Error in key_aliases: %s", e) if isinstance(e, HTTPException): raise ProxyException( message=getattr(e, "detail", f"error({e})"), @@ -5779,7 +5785,7 @@ def _build_key_filter_conditions( if expires_filter is not None and expires_filter in VALID_EXPIRES_FILTER_VALUES: where = {"AND": [where, _build_expires_where_clause(expires_filter, datetime.now(timezone.utc))]} - verbose_proxy_logger.debug(f"Filter conditions: {where}") + verbose_proxy_logger.debug("Filter conditions: %s", where) return where @@ -5850,7 +5856,7 @@ async def _list_key_helper( # Calculate skip for pagination skip = (page - 1) * size - verbose_proxy_logger.debug(f"Pagination: skip={skip}, take={size}") + verbose_proxy_logger.debug("Pagination: skip=%s, take=%s", skip, size) order_by: dict[str, str] | None = ( _validate_sort_params(sort_by, sort_order) if sort_by is not None and isinstance(sort_by, str) else None @@ -5890,7 +5896,7 @@ async def _list_key_helper( include={"object_permission": True}, ) - verbose_proxy_logger.debug(f"Fetched {len(keys)} keys") + verbose_proxy_logger.debug("Fetched %s keys", len(keys)) # Get total count of keys if use_deleted_table: @@ -5902,7 +5908,7 @@ async def _list_key_helper( where=where # type: ignore ) - verbose_proxy_logger.debug(f"Total count of keys: {total_count}") + verbose_proxy_logger.debug("Total count of keys: %s", total_count) # Calculate total pages total_pages = -(-total_count // size) # Ceiling division diff --git a/litellm/proxy/management_endpoints/management_v1/budgets.py b/litellm/proxy/management_endpoints/management_v1/budgets.py index 1bd47a940be..a0afcdc56cc 100644 --- a/litellm/proxy/management_endpoints/management_v1/budgets.py +++ b/litellm/proxy/management_endpoints/management_v1/budgets.py @@ -191,7 +191,7 @@ async def list_budgets( raise except Exception as e: # noqa: BLE001 # a driver error answers as a problem document, not the OpenAI error shape verbose_proxy_logger.exception( - f"litellm.proxy.management_endpoints.management_v1.budgets.list_budgets(): Exception occured - {e}" + "litellm.proxy.management_endpoints.management_v1.budgets.list_budgets(): Exception occured - %s", e ) raise ManagementProblem( ProblemDetail( diff --git a/litellm/proxy/management_endpoints/management_v1/spend_logs.py b/litellm/proxy/management_endpoints/management_v1/spend_logs.py index 403e2760fb9..3614a598393 100644 --- a/litellm/proxy/management_endpoints/management_v1/spend_logs.py +++ b/litellm/proxy/management_endpoints/management_v1/spend_logs.py @@ -187,8 +187,8 @@ async def list_spend_log_end_users( raise except Exception as e: verbose_proxy_logger.exception( - "litellm.proxy.management_endpoints.management_v1.spend_logs.list_spend_log_end_users(): " - f"Exception occured - {e}" + "litellm.proxy.management_endpoints.management_v1.spend_logs.list_spend_log_end_users(): Exception occured - %s", + e, ) raise ManagementProblem( ProblemDetail( diff --git a/litellm/proxy/management_endpoints/mcp_management_endpoints.py b/litellm/proxy/management_endpoints/mcp_management_endpoints.py index da86a7f06f2..6a212dd3bf9 100644 --- a/litellm/proxy/management_endpoints/mcp_management_endpoints.py +++ b/litellm/proxy/management_endpoints/mcp_management_endpoints.py @@ -94,7 +94,7 @@ DEFAULT_MCP_REGISTRY_VERSION = "1.0.0" try: importlib.import_module("mcp") except ImportError as e: - verbose_logger.debug(f"MCP module not found: {e}") + verbose_logger.debug("MCP module not found: %s", e) MCP_AVAILABLE = False if MCP_AVAILABLE: @@ -399,7 +399,7 @@ if MCP_AVAILABLE: try: encrypted_payload = encrypt_value_helper(payload_json) except Exception as e: - verbose_proxy_logger.debug(f"Failed to encrypt temporary MCP server payload for Redis cache: {e}") + verbose_proxy_logger.debug("Failed to encrypt temporary MCP server payload for Redis cache: %s", e) return if not isinstance(encrypted_payload, str): @@ -413,7 +413,7 @@ if MCP_AVAILABLE: ttl=max(1, ttl_seconds), ) except Exception as e: - verbose_proxy_logger.debug(f"Failed to write temporary MCP server to Redis cache: {e}") + verbose_proxy_logger.debug("Failed to write temporary MCP server to Redis cache: %s", e) async def _get_temporary_mcp_server_from_redis( server_id: str, @@ -435,7 +435,7 @@ if MCP_AVAILABLE: key=f"{TEMPORARY_MCP_SERVER_REDIS_KEY_PREFIX}:{server_id}" ) except Exception as e: - verbose_proxy_logger.debug(f"Failed reading temporary MCP server from Redis cache: {e}") + verbose_proxy_logger.debug("Failed reading temporary MCP server from Redis cache: %s", e) return None if not isinstance(cached_server, str): @@ -454,7 +454,7 @@ if MCP_AVAILABLE: try: loaded = json.loads(decrypted_json) except Exception as e: - verbose_proxy_logger.debug(f"Invalid decrypted temporary MCP payload in Redis cache: {e}") + verbose_proxy_logger.debug("Invalid decrypted temporary MCP payload in Redis cache: %s", e) return None if not isinstance(loaded, dict): return None @@ -463,7 +463,7 @@ if MCP_AVAILABLE: try: return MCPServer.model_validate(payload_dict) except Exception as e: - verbose_proxy_logger.debug(f"Invalid temporary MCP server payload in Redis cache: {e}") + verbose_proxy_logger.debug("Invalid temporary MCP server payload in Redis cache: %s", e) return None async def get_cached_temporary_mcp_server( @@ -814,7 +814,7 @@ if MCP_AVAILABLE: if hasattr(server, "mcp_access_groups") and server.mcp_access_groups: access_groups.update(server.mcp_access_groups) except Exception as e: - verbose_proxy_logger.debug(f"Error getting MCP access groups: {e}") + verbose_proxy_logger.debug("Error getting MCP access groups: %s", e) # Convert to sorted list access_groups_list = sorted(list(access_groups)) @@ -864,7 +864,7 @@ if MCP_AVAILABLE: entry = _build_mcp_registry_entry_for_server(server, base_url) except Exception as e: verbose_proxy_logger.debug( - f"Skipping MCP server {getattr(server, 'server_id', 'unknown')} in registry: {e}" + "Skipping MCP server %s in registry: %s", getattr(server, "server_id", "unknown"), e ) continue registry_servers.append({"server": entry}) @@ -1183,7 +1183,7 @@ if MCP_AVAILABLE: touched_by=user_api_key_dict.user_id or user_api_key_dict.team_id, ) except Exception as e: - verbose_proxy_logger.exception(f"Error registering mcp server: {e}") + verbose_proxy_logger.exception("Error registering mcp server: %s", e) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail={"error": f"Error registering mcp server: {e}"}, @@ -1398,7 +1398,7 @@ if MCP_AVAILABLE: mcp_server.last_health_check = health_result.last_health_check mcp_server.health_check_error = health_result.health_check_error except Exception as e: - verbose_proxy_logger.debug(f"Error performing health check on server {server_id}: {e}") + verbose_proxy_logger.debug("Error performing health check on server %s: %s", server_id, e) mcp_server.status = "unknown" mcp_server.last_health_check = datetime.now() mcp_server.health_check_error = str(e) @@ -1483,7 +1483,7 @@ if MCP_AVAILABLE: touched_by=user_api_key_dict.user_id or LITELLM_PROXY_ADMIN_NAME, ) except Exception as e: - verbose_proxy_logger.exception(f"Error creating mcp server: {e}") + verbose_proxy_logger.exception("Error creating mcp server: %s", e) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail={"error": f"Error creating mcp server: {e}"}, @@ -1498,7 +1498,7 @@ if MCP_AVAILABLE: await global_mcp_server_manager.reload_servers_from_database() except Exception as e: verbose_proxy_logger.exception( - f"MCP server {new_mcp_server.server_id} created but in-memory registry refresh failed: {e}" + "MCP server %s created but in-memory registry refresh failed: %s", new_mcp_server.server_id, e ) return _redact_mcp_credentials(new_mcp_server) @@ -1559,7 +1559,7 @@ if MCP_AVAILABLE: ttl_seconds=TEMPORARY_MCP_SERVER_TTL_SECONDS, ) except Exception as e: - verbose_proxy_logger.exception(f"Error caching temporary mcp server: {e}") + verbose_proxy_logger.exception("Error caching temporary mcp server: %s", e) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail={"error": f"Error caching temporary mcp server: {e}"}, @@ -2566,7 +2566,7 @@ if MCP_AVAILABLE: await proxy_config.save_config(new_config=config) verbose_proxy_logger.debug( - f"Updated public mcp servers to: {litellm.public_mcp_servers} by user: {user_api_key_dict.user_id}" + "Updated public mcp servers to: %s by user: %s", litellm.public_mcp_servers, user_api_key_dict.user_id ) return { @@ -2577,7 +2577,7 @@ if MCP_AVAILABLE: except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error making agent public: {e}") + verbose_proxy_logger.exception("Error making agent public: %s", e) raise HTTPException(status_code=500, detail=str(e)) # --- MCP Discovery --- @@ -2598,7 +2598,7 @@ if MCP_AVAILABLE: with open(_MCP_REGISTRY_PATH, "r") as f: data: dict[str, Any] = json.load(f) except Exception as e: - verbose_proxy_logger.warning(f"Failed to load MCP registry from {_MCP_REGISTRY_PATH}: {e}") + verbose_proxy_logger.warning("Failed to load MCP registry from %s: %s", _MCP_REGISTRY_PATH, e) data = {"servers": []} _mcp_registry_cache = data return data @@ -2685,7 +2685,7 @@ if MCP_AVAILABLE: try: return _load_openapi_registry() except Exception as e: - verbose_proxy_logger.warning(f"Failed to load OpenAPI registry from {_OPENAPI_REGISTRY_PATH}: {e}") + verbose_proxy_logger.warning("Failed to load OpenAPI registry from %s: %s", _OPENAPI_REGISTRY_PATH, e) return {"apis": []} # --------------------------------------------------------------------------- diff --git a/litellm/proxy/management_endpoints/model_access_group_management_endpoints.py b/litellm/proxy/management_endpoints/model_access_group_management_endpoints.py index b294b2674e4..65a6e3639ec 100644 --- a/litellm/proxy/management_endpoints/model_access_group_management_endpoints.py +++ b/litellm/proxy/management_endpoints/model_access_group_management_endpoints.py @@ -121,7 +121,7 @@ async def _tag_deployment_with_access_group( where={"model_id": model_id}, data={"model_info": json.dumps(updated_model_info)}, ) - verbose_proxy_logger.debug(f"Updated deployment {model_id} with access group: {access_group}") + verbose_proxy_logger.debug("Updated deployment %s with access group: %s", model_id, access_group) return (model_id, updated_model_info) @@ -175,7 +175,7 @@ async def update_deployments_with_access_group( so callers can verify each one survived the post-write reload """ deployments = await ModelRepository(prisma_client).table.find_many(where={"model_name": {"in": model_names}}) - verbose_proxy_logger.debug(f"Found {len(deployments)} deployments for model_names: {model_names}") + verbose_proxy_logger.debug("Found %s deployments for model_names: %s", len(deployments), model_names) found_names = {deployment.model_name for deployment in deployments} for model_name in model_names: @@ -212,7 +212,7 @@ async def update_specific_deployments_with_access_group( their unique model_id. Returns the (model_id, updated model_info) pair of every deployment actually written. """ - verbose_proxy_logger.debug(f"Updating specific deployment model_ids: {model_ids}") + verbose_proxy_logger.debug("Updating specific deployment model_ids: %s", model_ids) tagged = [ await _tag_deployment_with_access_group( model_id=model_id, @@ -344,7 +344,7 @@ async def create_model_group( prisma_client, ) - verbose_proxy_logger.debug(f"Creating access group: {data.access_group} with models: {data.model_names}") + verbose_proxy_logger.debug("Creating access group: %s with models: %s", data.access_group, data.model_names) # Validation: Check if access_group is provided if not data.access_group or not data.access_group.strip(): @@ -426,7 +426,7 @@ async def create_model_group( ) verbose_proxy_logger.info( - f"Successfully created access group '{data.access_group}' with {models_updated} models updated" + "Successfully created access group '%s' with %s models updated", data.access_group, models_updated ) return NewModelGroupResponse( @@ -439,7 +439,7 @@ async def create_model_group( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error creating access group '{data.access_group}': {e}") + verbose_proxy_logger.exception("Error creating access group '%s': %s", data.access_group, e) raise HTTPException( status_code=500, detail={"error": f"Failed to create access group: {e}"}, @@ -489,7 +489,7 @@ async def list_access_groups( return ListAccessGroupsResponse(access_groups=access_groups_list) except Exception as e: - verbose_proxy_logger.exception(f"Error listing access groups: {e}") + verbose_proxy_logger.exception("Error listing access groups: %s", e) raise HTTPException( status_code=500, detail={"error": f"Failed to list access groups: {e}"}, @@ -546,7 +546,7 @@ async def get_access_group_info( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error getting access group info for '{access_group}': {e}") + verbose_proxy_logger.exception("Error getting access group info for '%s': %s", access_group, e) raise HTTPException( status_code=500, detail={"error": f"Failed to get access group info: {e}"}, @@ -600,7 +600,7 @@ async def update_access_group( detail={"error": "Database not connected."}, ) - verbose_proxy_logger.debug(f"Updating access group: {access_group} with models: {data.model_names}") + verbose_proxy_logger.debug("Updating access group: %s with models: %s", access_group, data.model_names) # Validation: Check that at least one of model_names or model_ids is provided has_model_names = data.model_names and len(data.model_names) > 0 @@ -686,7 +686,7 @@ async def update_access_group( ) verbose_proxy_logger.info( - f"Successfully updated access group '{access_group}' with {models_updated} models updated" + "Successfully updated access group '%s' with %s models updated", access_group, models_updated ) return NewModelGroupResponse( @@ -699,7 +699,7 @@ async def update_access_group( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error updating access group '{access_group}': {e}") + verbose_proxy_logger.exception("Error updating access group '%s': %s", access_group, e) raise HTTPException( status_code=500, detail={"error": f"Failed to update access group: {e}"}, @@ -744,7 +744,7 @@ async def delete_access_group( detail={"error": "Database not connected."}, ) - verbose_proxy_logger.debug(f"Deleting access group: {access_group}") + verbose_proxy_logger.debug("Deleting access group: %s", access_group) # Validation: Check if access group exists try: @@ -788,7 +788,7 @@ async def delete_access_group( ) verbose_proxy_logger.info( - f"Successfully deleted access group '{access_group}' from {models_updated} deployments" + "Successfully deleted access group '%s' from %s deployments", access_group, models_updated ) return DeleteModelGroupResponse( @@ -800,7 +800,7 @@ async def delete_access_group( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error deleting access group '{access_group}': {e}") + verbose_proxy_logger.exception("Error deleting access group '%s': %s", access_group, e) raise HTTPException( status_code=500, detail={"error": f"Failed to delete access group: {e}"}, diff --git a/litellm/proxy/management_endpoints/model_management_endpoints.py b/litellm/proxy/management_endpoints/model_management_endpoints.py index 50109b02189..f43989b29cd 100644 --- a/litellm/proxy/management_endpoints/model_management_endpoints.py +++ b/litellm/proxy/management_endpoints/model_management_endpoints.py @@ -355,7 +355,7 @@ async def patch_model( return updated_model except Exception as e: - verbose_proxy_logger.exception(f"Error in patch_model: {e}") + verbose_proxy_logger.exception("Error in patch_model: %s", e) if isinstance(e, (HTTPException, ProxyException)): raise e @@ -462,7 +462,7 @@ async def _set_model_blocked_status( return updated_model except Exception as e: - verbose_proxy_logger.exception(f"Error in model {action}: {e}") + verbose_proxy_logger.exception("Error in model %s: %s", action, e) if isinstance(e, (HTTPException, ProxyException)): raise e @@ -1223,7 +1223,7 @@ async def delete_model( ) except Exception as e: - verbose_proxy_logger.exception(f"Failed to delete model. Due to error - {e}") + verbose_proxy_logger.exception("Failed to delete model. Due to error - %s", e) if isinstance(e, HTTPException): raise ProxyException( message=getattr(e, "detail", f"Authentication Error({e})"), @@ -1389,7 +1389,7 @@ async def add_new_model( passed_model_info=model_params.model_info, ) except Exception as e: - verbose_proxy_logger.exception(f"Exception in add_new_model: {e}") + verbose_proxy_logger.exception("Exception in add_new_model: %s", e) else: raise HTTPException( @@ -1429,7 +1429,7 @@ async def add_new_model( return model_response except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.add_new_model(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.add_new_model(): Exception occured - %s", e) if isinstance(e, HTTPException): raise ProxyException( message=getattr(e, "detail", f"Authentication Error({e})"), @@ -1582,7 +1582,7 @@ async def update_model( return model_response except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.update_model(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.update_model(): Exception occured - %s", e) if isinstance(e, HTTPException): raise ProxyException( message=getattr(e, "detail", f"Authentication Error({e})"), @@ -1665,7 +1665,7 @@ async def update_public_model_groups( litellm.public_model_groups = request.model_groups verbose_proxy_logger.debug( - f"Updated public model groups to: {request.model_groups} by user: {user_api_key_dict.user_id}" + "Updated public model groups to: %s by user: %s", request.model_groups, user_api_key_dict.user_id ) return { @@ -1675,7 +1675,7 @@ async def update_public_model_groups( } except Exception as e: - verbose_proxy_logger.exception(f"Error updating public model groups: {e}") + verbose_proxy_logger.exception("Error updating public model groups: %s", e) if isinstance(e, HTTPException): raise e @@ -1733,7 +1733,7 @@ async def update_useful_links( litellm.public_model_groups_links = request.useful_links verbose_proxy_logger.debug( - f"Updated useful links to: {request.useful_links} by user: {user_api_key_dict.user_id}" + "Updated useful links to: %s by user: %s", request.useful_links, user_api_key_dict.user_id ) return { @@ -1743,7 +1743,7 @@ async def update_useful_links( } except Exception as e: - verbose_proxy_logger.exception(f"Error updating public model groups: {e}") + verbose_proxy_logger.exception("Error updating public model groups: %s", e) if isinstance(e, HTTPException): raise e @@ -1966,9 +1966,9 @@ async def clear_cache() -> frozenset[str] | None: ) verbose_proxy_logger.debug( - f"Cleared {len(db_model_ids)} DB models, preserved {len(config_models)} config models" + "Cleared %s DB models, preserved %s config models", len(db_model_ids), len(config_models) ) return still_desired_ids except Exception as e: - verbose_proxy_logger.exception(f"Failed to clear cache and reload models. Due to error - {e}") + verbose_proxy_logger.exception("Failed to clear cache and reload models. Due to error - %s", e) return None diff --git a/litellm/proxy/management_endpoints/organization_endpoints.py b/litellm/proxy/management_endpoints/organization_endpoints.py index 949c35e4182..66cf111324a 100644 --- a/litellm/proxy/management_endpoints/organization_endpoints.py +++ b/litellm/proxy/management_endpoints/organization_endpoints.py @@ -498,7 +498,7 @@ async def new_organization( new_organization_row = _STR_OBJECT_DICT_ADAPTER.validate_python( prisma_client.jsonify_object(organization_row.json(exclude_none=True)) ) - verbose_proxy_logger.info(f"new_organization_row: {json.dumps(new_organization_row, indent=2)}") + verbose_proxy_logger.info("new_organization_row: %s", json.dumps(new_organization_row, indent=2)) response = await _table(OrganizationRepository(prisma_client)).create( data={ **new_organization_row, @@ -1258,7 +1258,7 @@ async def organization_member_add( updated_organization_memberships=updated_organization_memberships, ) except Exception as e: - verbose_proxy_logger.exception(f"Error adding member to organization: {e}") + verbose_proxy_logger.exception("Error adding member to organization: %s", e) if isinstance(e, HTTPException): raise ProxyException( message=getattr(e, "detail", f"Authentication Error({e})"), @@ -1444,7 +1444,7 @@ async def organization_member_update( ) return final_organization_membership_pydantic except Exception as e: - verbose_proxy_logger.exception(f"Error updating member in organization: {e}") + verbose_proxy_logger.exception("Error updating member in organization: %s", e) raise e @@ -1493,7 +1493,7 @@ async def organization_member_delete( return member_to_delete except Exception as e: - verbose_proxy_logger.exception(f"Error deleting member from organization: {e}") + verbose_proxy_logger.exception("Error deleting member from organization: %s", e) raise e diff --git a/litellm/proxy/management_endpoints/policy_endpoints/endpoints.py b/litellm/proxy/management_endpoints/policy_endpoints/endpoints.py index fb139902978..a55e32446f5 100644 --- a/litellm/proxy/management_endpoints/policy_endpoints/endpoints.py +++ b/litellm/proxy/management_endpoints/policy_endpoints/endpoints.py @@ -432,7 +432,7 @@ async def validate_policy( from litellm.proxy.policy_engine.policy_validator import PolicyValidator from litellm.proxy.proxy_server import prisma_client - verbose_proxy_logger.debug(f"Validating policy configuration with {len(data.policies)} policies") + verbose_proxy_logger.debug("Validating policy configuration with %s policies", len(data.policies)) validator = PolicyValidator(prisma_client=prisma_client) diff --git a/litellm/proxy/management_endpoints/router_settings_endpoints.py b/litellm/proxy/management_endpoints/router_settings_endpoints.py index 0adc0610c60..a4d4e2fe5cb 100644 --- a/litellm/proxy/management_endpoints/router_settings_endpoints.py +++ b/litellm/proxy/management_endpoints/router_settings_endpoints.py @@ -120,7 +120,7 @@ async def get_router_settings( routing_strategy_descriptions=ROUTING_STRATEGY_DESCRIPTIONS, ) except Exception as e: - verbose_proxy_logger.error(f"Error fetching router settings: {e}") + verbose_proxy_logger.error("Error fetching router settings: %s", e) raise @@ -168,5 +168,5 @@ async def get_router_fields( routing_strategy_descriptions=ROUTING_STRATEGY_DESCRIPTIONS, ) except Exception as e: - verbose_proxy_logger.error(f"Error fetching router fields: {e}") + verbose_proxy_logger.error("Error fetching router fields: %s", e) raise diff --git a/litellm/proxy/management_endpoints/scim/scim_v2.py b/litellm/proxy/management_endpoints/scim/scim_v2.py index b3140ec911e..4437bfcbb1c 100644 --- a/litellm/proxy/management_endpoints/scim/scim_v2.py +++ b/litellm/proxy/management_endpoints/scim/scim_v2.py @@ -365,7 +365,7 @@ async def _get_scim_upsert_user_setting() -> bool: # Default to True if not set (backward compatibility) return bool(scim_upsert_user) except Exception as e: - verbose_proxy_logger.warning(f"Error reading scim_upsert_user setting, defaulting to True: {e}") + verbose_proxy_logger.warning("Error reading scim_upsert_user setting, defaulting to True: %s", e) # Default to True for backward compatibility return True @@ -401,7 +401,7 @@ async def _get_scim_admin_group() -> str | None: litellm_settings = config.get("litellm_settings", {}) or {} return litellm_settings.get("scim_admin_group") or None except Exception as e: - verbose_proxy_logger.warning(f"Error reading scim_admin_group setting, defaulting to None: {e}") + verbose_proxy_logger.warning("Error reading scim_admin_group setting, defaulting to None: %s", e) return None @@ -882,11 +882,11 @@ async def _create_user_if_not_exists(user_id: str, created_via: str = "scim_grou ) created_user = await new_user(data=new_user_request) - verbose_proxy_logger.info(f"Created user {user_id} via {created_via}") + verbose_proxy_logger.info("Created user %s via %s", user_id, created_via) return created_user except Exception as e: - verbose_proxy_logger.exception(f"Failed to create user {user_id}: {e}") + verbose_proxy_logger.exception("Failed to create user %s: %s", user_id, e) return None @@ -1886,15 +1886,15 @@ async def patch_team_membership( except ProxyException as e: # Handle duplicate membership gracefully - this is idempotent if e.type == ProxyErrorTypes.team_member_already_in_team: - verbose_proxy_logger.debug(f"User {user_id} is already in team {_team_id}, skipping add") + verbose_proxy_logger.debug("User %s is already in team %s, skipping add", user_id, _team_id) elif raise_on_error: raise else: - verbose_proxy_logger.exception(f"Error adding user to team {_team_id}: {e}") + verbose_proxy_logger.exception("Error adding user to team %s: %s", _team_id, e) except Exception as e: if raise_on_error: raise - verbose_proxy_logger.exception(f"Error adding user to team {_team_id}: {e}") + verbose_proxy_logger.exception("Error adding user to team %s: %s", _team_id, e) for _team_id in teams_ids_to_remove_user_from: try: @@ -1904,15 +1904,15 @@ async def patch_team_membership( ) except HTTPException as e: if _is_user_not_in_team_error(e): - verbose_proxy_logger.debug(f"User {user_id} is not in team {_team_id}, skipping remove") + verbose_proxy_logger.debug("User %s is not in team %s, skipping remove", user_id, _team_id) elif raise_on_error: raise else: - verbose_proxy_logger.exception(f"Error removing user from team {_team_id}: {e}") + verbose_proxy_logger.exception("Error removing user from team %s: %s", _team_id, e) except Exception as e: if raise_on_error: raise - verbose_proxy_logger.exception(f"Error removing user from team {_team_id}: {e}") + verbose_proxy_logger.exception("Error removing user from team %s: %s", _team_id, e) return True @@ -2045,7 +2045,7 @@ async def get_groups( # team creation, so reading it here would report an empty member # list to the IdP and trigger repeated re-provisioning. members = await _get_team_members_display(await _get_team_member_user_ids_from_team(team)) - verbose_proxy_logger.debug(f"SCIM GET GROUPS members: {members}") + verbose_proxy_logger.debug("SCIM GET GROUPS members: %s", members) team_alias = getattr(team, "team_alias", team.team_id) team_created_at = team.created_at.isoformat() if team.created_at else None team_updated_at = team.updated_at.isoformat() if team.updated_at else None @@ -2063,7 +2063,7 @@ async def get_groups( ) scim_groups.append(scim_group) - verbose_proxy_logger.debug(f"SCIM GET GROUPS response: {scim_groups}") + verbose_proxy_logger.debug("SCIM GET GROUPS response: %s", scim_groups) return SCIMListResponse( totalResults=total_count, startIndex=startIndex, @@ -2092,7 +2092,7 @@ async def get_group( team = await _check_team_exists(group_id) scim_group = await ScimTransformations.transform_litellm_team_to_scim_group(team) - verbose_proxy_logger.debug(f"SCIM GET GROUP response: {scim_group}") + verbose_proxy_logger.debug("SCIM GET GROUP response: %s", scim_group) return scim_group except Exception as e: @@ -2178,8 +2178,8 @@ async def update_group( # Extract and validate group members (all users must exist) member_result = await _extract_group_member_ids(group) - verbose_proxy_logger.debug(f"SCIM PUT GROUP all_member_ids: {member_result.all_member_ids}") - verbose_proxy_logger.debug(f"SCIM PUT GROUP created_users: {len(member_result.created_users)}") + verbose_proxy_logger.debug("SCIM PUT GROUP all_member_ids: %s", member_result.all_member_ids) + verbose_proxy_logger.debug("SCIM PUT GROUP created_users: %s", len(member_result.created_users)) # Prepare update data existing_metadata = existing_team.metadata if existing_team.metadata else {} @@ -2202,9 +2202,9 @@ async def update_group( # Handle user-team relationship changes current_members = set(await _get_team_member_user_ids_from_team(existing_team)) - verbose_proxy_logger.debug(f"SCIM PUT GROUP current_members: {current_members}") + verbose_proxy_logger.debug("SCIM PUT GROUP current_members: %s", current_members) final_members = set(member_result.all_member_ids) - verbose_proxy_logger.debug(f"SCIM PUT GROUP final_members: {final_members}") + verbose_proxy_logger.debug("SCIM PUT GROUP final_members: %s", final_members) await _handle_group_membership_changes( group_id=group_id, @@ -2380,8 +2380,8 @@ async def _handle_group_membership_changes(group_id: str, current_members: set[s members_to_add = final_members - current_members members_to_remove = current_members - final_members - verbose_proxy_logger.debug(f"members_to_add: {members_to_add}") - verbose_proxy_logger.debug(f"members_to_remove: {members_to_remove}") + verbose_proxy_logger.debug("members_to_add: %s", members_to_add) + verbose_proxy_logger.debug("members_to_remove: %s", members_to_remove) # Use existing helper functions for team membership changes for member_id in members_to_add: diff --git a/litellm/proxy/management_endpoints/sso/custom_microsoft_sso.py b/litellm/proxy/management_endpoints/sso/custom_microsoft_sso.py index 2f900f9b6b6..07108712dbb 100644 --- a/litellm/proxy/management_endpoints/sso/custom_microsoft_sso.py +++ b/litellm/proxy/management_endpoints/sso/custom_microsoft_sso.py @@ -68,10 +68,10 @@ class CustomMicrosoftSSO(MicrosoftSSO): if custom_authorization_endpoint or custom_token_endpoint or custom_userinfo_endpoint: verbose_proxy_logger.debug( - f"Using custom Microsoft SSO endpoints - " - f"authorization: {authorization_endpoint}, " - f"token: {token_endpoint}, " - f"userinfo: {userinfo_endpoint}" + "Using custom Microsoft SSO endpoints - authorization: %s, token: %s, userinfo: %s", + authorization_endpoint, + token_endpoint, + userinfo_endpoint, ) return DiscoveryDocument( diff --git a/litellm/proxy/management_endpoints/sso/saml_sso.py b/litellm/proxy/management_endpoints/sso/saml_sso.py index 37b641ca123..c73c57702e6 100644 --- a/litellm/proxy/management_endpoints/sso/saml_sso.py +++ b/litellm/proxy/management_endpoints/sso/saml_sso.py @@ -449,7 +449,9 @@ class SAMLAuthHandler: display_name = " ".join(part for part in (first_name, last_name) if part) or email - verbose_proxy_logger.info(f"SAML login: subject={user_id}, email={email}, attributes={list(attributes.keys())}") + verbose_proxy_logger.info( + "SAML login: subject=%s, email=%s, attributes=%s", user_id, email, list(attributes.keys()) + ) try: return CustomOpenID( diff --git a/litellm/proxy/management_endpoints/tag_management_endpoints.py b/litellm/proxy/management_endpoints/tag_management_endpoints.py index 8e701fa9e20..d6db8dc05cd 100644 --- a/litellm/proxy/management_endpoints/tag_management_endpoints.py +++ b/litellm/proxy/management_endpoints/tag_management_endpoints.py @@ -201,7 +201,7 @@ async def _get_model_names(prisma_client: "PrismaClient", model_ids: Sequence[st models = await _table(ModelRepository(prisma_client)).find_many(where={"model_id": {"in": model_ids}}) return {model.model_id: model.model_name for model in models} except Exception as e: - verbose_proxy_logger.error(f"Error getting model names: {e}") + verbose_proxy_logger.error("Error getting model names: %s", e) return {} @@ -331,7 +331,7 @@ async def new_tag( "tag": tag_config, } except Exception as e: - verbose_proxy_logger.exception(f"Error creating tag: {e}") + verbose_proxy_logger.exception("Error creating tag: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -372,7 +372,7 @@ async def _add_tag_to_deployment(deployment: "Deployment", tag: str): data={"litellm_params": json.dumps(existing_params)}, ) except Exception as e: - verbose_proxy_logger.exception(f"Error adding tag to deployment: {e}") + verbose_proxy_logger.exception("Error adding tag to deployment: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -461,7 +461,7 @@ async def update_tag( "tag": tag_config, } except Exception as e: - verbose_proxy_logger.exception(f"Error updating tag: {e}") + verbose_proxy_logger.exception("Error updating tag: %s", e) raise HTTPException(status_code=500, detail=str(e)) diff --git a/litellm/proxy/management_endpoints/team_callback_endpoints.py b/litellm/proxy/management_endpoints/team_callback_endpoints.py index 32b22dd6ade..dd20dd97e00 100644 --- a/litellm/proxy/management_endpoints/team_callback_endpoints.py +++ b/litellm/proxy/management_endpoints/team_callback_endpoints.py @@ -354,7 +354,7 @@ async def add_team_callbacks( except ProxyException as e: raise e except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.add_team_callbacks(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.add_team_callbacks(): Exception occured - %s", e) raise ProxyException( message="Internal Server Error, " + str(e), type=ProxyErrorTypes.internal_server_error.value, @@ -492,7 +492,7 @@ async def disable_team_logging( except ProxyException: raise except Exception as e: - verbose_proxy_logger.error(f"litellm.proxy.proxy_server.disable_team_logging(): Exception occurred - {e}") + verbose_proxy_logger.error("litellm.proxy.proxy_server.disable_team_logging(): Exception occurred - %s", e) verbose_proxy_logger.debug(traceback.format_exc()) raise ProxyException( message="Internal Server Error, " + str(e), @@ -585,7 +585,7 @@ async def get_team_callbacks( except ProxyException: raise except Exception as e: - verbose_proxy_logger.error(f"litellm.proxy.proxy_server.get_team_callbacks(): Exception occurred - {e}") + verbose_proxy_logger.error("litellm.proxy.proxy_server.get_team_callbacks(): Exception occurred - %s", e) verbose_proxy_logger.debug(traceback.format_exc()) if isinstance(e, HTTPException): raise ProxyException( diff --git a/litellm/proxy/management_endpoints/team_endpoints.py b/litellm/proxy/management_endpoints/team_endpoints.py index 4dd86e5769d..15b755660f3 100644 --- a/litellm/proxy/management_endpoints/team_endpoints.py +++ b/litellm/proxy/management_endpoints/team_endpoints.py @@ -460,7 +460,11 @@ class TeamMemberBudgetHandler: user_api_key_dict=user_api_key_dict, ) verbose_proxy_logger.info( - f"Updated team member budget table: {budget_row.budget_id}, with team_member_budget={team_member_budget}, team_member_rpm_limit={team_member_rpm_limit}, team_member_tpm_limit={team_member_tpm_limit}" + "Updated team member budget table: %s, with team_member_budget=%s, team_member_rpm_limit=%s, team_member_tpm_limit=%s", + budget_row.budget_id, + team_member_budget, + team_member_rpm_limit, + team_member_tpm_limit, ) if updated_kv.get("metadata") is None: updated_kv["metadata"] = {} @@ -2208,7 +2212,7 @@ async def handle_update_object_permission(data_json: dict, existing_team_row: Li # Add the object_permission_id to data_json if one was created/updated if object_permission_id is not None: data_json["object_permission_id"] = object_permission_id - verbose_proxy_logger.debug(f"updated object_permission_id: {object_permission_id}") + verbose_proxy_logger.debug("updated object_permission_id: %s", object_permission_id) return data_json @@ -2300,7 +2304,9 @@ def team_member_add_duplication_check( ) elif len(invalid_team_members) > 0: verbose_proxy_logger.info( - f"Some users are already in team. Existing members={existing_team_row.members_with_roles}. Duplicate members={invalid_team_members}", + "Some users are already in team. Existing members=%s. Duplicate members=%s", + existing_team_row.members_with_roles, + invalid_team_members, ) @@ -3804,7 +3810,7 @@ async def _add_team_member_budget_table( team_info_response_object.team_member_budget_table = team_budget except Exception: verbose_proxy_logger.info( - f"Team member budget table not found, passed team_member_budget_id={team_member_budget_id}" + "Team member budget table not found, passed team_member_budget_id=%s", team_member_budget_id ) return team_info_response_object @@ -3942,7 +3948,9 @@ async def team_info( except Exception as e: verbose_proxy_logger.error( - f"litellm.proxy.management_endpoints.team_endpoints.py::team_info - Exception occurred - {e}\n{traceback.format_exc()}" + "litellm.proxy.management_endpoints.team_endpoints.py::team_info - Exception occurred - %s\n%s", + e, + traceback.format_exc(), ) if isinstance(e, HTTPException): raise ProxyException( @@ -4864,7 +4872,7 @@ async def get_paginated_teams( ) return teams, total_count except Exception as e: - verbose_proxy_logger.exception(f"[Non-Blocking] Error getting paginated teams: {e}") + verbose_proxy_logger.exception("[Non-Blocking] Error getting paginated teams: %s", e) return [], 0 diff --git a/litellm/proxy/management_endpoints/ui_sso.py b/litellm/proxy/management_endpoints/ui_sso.py index bc05f72ae14..a2e880eab5f 100644 --- a/litellm/proxy/management_endpoints/ui_sso.py +++ b/litellm/proxy/management_endpoints/ui_sso.py @@ -443,7 +443,7 @@ def build_cli_sso_attribution_metadata( metadata: dict[str, Any] = {} for source_claim, dest_key in claim_map: if not _is_safe_cli_sso_metadata_dest_key(dest_key): - verbose_proxy_logger.debug(f"Skipping unsafe CLI SSO metadata destination key: {dest_key}") + verbose_proxy_logger.debug("Skipping unsafe CLI SSO metadata destination key: %s", dest_key) continue raw_value = _extract_sso_claim_value(result=result, claim_path=source_claim) @@ -504,11 +504,12 @@ async def _persist_cli_sso_user_metadata( data={"metadata": merged_metadata}, ) verbose_proxy_logger.info( - f"Persisted CLI SSO attribution metadata for user {user_id}: " - f"{list(_flatten_cli_sso_metadata_for_poll(attribution_metadata).keys())}" + "Persisted CLI SSO attribution metadata for user %s: %s", + user_id, + list(_flatten_cli_sso_metadata_for_poll(attribution_metadata).keys()), ) except Exception as e: - verbose_proxy_logger.error(f"Failed to persist CLI SSO attribution metadata for user {user_id}: {e}") + verbose_proxy_logger.error("Failed to persist CLI SSO attribution metadata for user %s: %s", user_id, e) def _cli_poll_attribution_metadata_from_session( @@ -745,13 +746,15 @@ def determine_role_from_groups( role_groups = role_mappings.roles[role] if isinstance(role_groups, list) and user_groups_set.intersection(set(role_groups)): verbose_proxy_logger.debug( - f"User groups {user_groups} matched role '{role.value}' via groups: {role_groups}" + "User groups %s matched role '%s' via groups: %s", user_groups, role.value, role_groups ) return role # No matching groups found, return default_role verbose_proxy_logger.debug( - f"User groups {user_groups} did not match any role mappings, using default_role: {role_mappings.default_role}" + "User groups %s did not match any role mappings, using default_role: %s", + user_groups, + role_mappings.default_role, ) return role_mappings.default_role @@ -827,7 +830,7 @@ def process_sso_jwt_access_token( if user_groups: user_role = determine_role_from_groups(user_groups, role_mappings) verbose_proxy_logger.debug( - f"Determined role '{user_role}' from access token groups '{user_groups}' using role_mappings" + "Determined role '%s' from access token groups '%s' using role_mappings", user_role, user_groups ) elif role_mappings.default_role: user_role = role_mappings.default_role @@ -839,7 +842,7 @@ def process_sso_jwt_access_token( if user_role_from_token is not None: user_role = get_litellm_user_role(user_role_from_token) verbose_proxy_logger.debug( - f"Extracted role '{user_role}' from access token field '{generic_user_role_attribute_name}'" + "Extracted role '%s' from access token field '%s'", user_role, generic_user_role_attribute_name ) if user_role is not None: @@ -847,7 +850,7 @@ def process_sso_jwt_access_token( result["user_role"] = user_role else: setattr(result, "user_role", user_role) - verbose_proxy_logger.debug(f"Set user_role='{user_role}' from JWT access token") + verbose_proxy_logger.debug("Set user_role='%s' from JWT access token", user_role) return access_token_payload @@ -976,7 +979,7 @@ async def google_login( ) is True ): - verbose_proxy_logger.info(f"Redirecting to SSO login for {redirect_url}") + verbose_proxy_logger.info("Redirecting to SSO login for %s", redirect_url) sso_redirect = await SSOAuthenticationHandler.get_sso_login_redirect( redirect_url=redirect_url, microsoft_client_id=microsoft_client_id, @@ -1031,7 +1034,9 @@ def generic_response_convertor( generic_user_extra_attributes = os.getenv("GENERIC_USER_EXTRA_ATTRIBUTES", None) verbose_proxy_logger.debug( - f" generic_user_id_attribute_name: {generic_user_id_attribute_name}\n generic_user_email_attribute_name: {generic_user_email_attribute_name}" + " generic_user_id_attribute_name: %s\n generic_user_email_attribute_name: %s", + generic_user_id_attribute_name, + generic_user_email_attribute_name, ) all_teams = [] @@ -1048,7 +1053,9 @@ def generic_response_convertor( if team_ids_from_db_mapping: all_teams.extend(team_ids_from_db_mapping) verbose_proxy_logger.debug( - f"Loaded team_ids from DB team_mappings.team_ids_jwt_field='{team_mappings.team_ids_jwt_field}': {team_ids_from_db_mapping}" + "Loaded team_ids from DB team_mappings.team_ids_jwt_field='%s': %s", + team_mappings.team_ids_jwt_field, + team_ids_from_db_mapping, ) else: team_ids = jwt_handler.get_all_jwt_team_ids(cast(dict, response)) @@ -1080,13 +1087,15 @@ def generic_response_convertor( if user_groups: user_role = determine_role_from_groups(user_groups, role_mappings) verbose_proxy_logger.debug( - f"Determined role '{user_role.value if user_role else None}' from groups '{user_groups}' using role_mappings" + "Determined role '%s' from groups '%s' using role_mappings", + user_role.value if user_role else None, + user_groups, ) else: # No groups found, use default_role user_role = role_mappings.default_role verbose_proxy_logger.debug( - f"No groups found in '{group_claim}', using default_role: {role_mappings.default_role}" + "No groups found in '%s', using default_role: %s", group_claim, role_mappings.default_role ) # Fallback to existing logic if role_mappings not used @@ -1097,7 +1106,9 @@ def generic_response_convertor( if role is not None: user_role = role verbose_proxy_logger.debug( - f"Found valid LitellmUserRoles '{role.value}' from SSO attribute '{generic_user_role_attribute_name}'" + "Found valid LitellmUserRoles '%s' from SSO attribute '%s'", + role.value, + generic_user_role_attribute_name, ) # Build extra_fields dict from GENERIC_USER_EXTRA_ATTRIBUTES if specified @@ -1163,9 +1174,12 @@ def _setup_generic_sso_env_vars( ) verbose_proxy_logger.debug( - f"authorization_endpoint: {generic_authorization_endpoint}\ntoken_endpoint: {generic_token_endpoint}\nuserinfo_endpoint: {generic_userinfo_endpoint}" + "authorization_endpoint: %s\ntoken_endpoint: %s\nuserinfo_endpoint: %s", + generic_authorization_endpoint, + generic_token_endpoint, + generic_userinfo_endpoint, ) - verbose_proxy_logger.debug(f"GENERIC_REDIRECT_URI: {redirect_url}\nGENERIC_CLIENT_ID: {generic_client_id}\n") + verbose_proxy_logger.debug("GENERIC_REDIRECT_URI: %s\nGENERIC_CLIENT_ID: %s\n", redirect_url, generic_client_id) return ( generic_client_secret, @@ -1201,11 +1215,11 @@ async def _setup_team_mappings() -> Optional["TeamMappings"]: if team_mappings and team_mappings.team_ids_jwt_field: verbose_proxy_logger.debug( - f"Loaded team_mappings with team_ids_jwt_field: '{team_mappings.team_ids_jwt_field}'" + "Loaded team_mappings with team_ids_jwt_field: '%s'", team_mappings.team_ids_jwt_field ) except Exception as e: verbose_proxy_logger.debug( - f"Could not load team_mappings from database: {e}. Continuing with config-based team mapping." + "Could not load team_mappings from database: %s. Continuing with config-based team mapping.", e ) return team_mappings @@ -1232,10 +1246,10 @@ async def _setup_role_mappings() -> Optional["RoleMappings"]: role_mappings = role_mappings_data if role_mappings: - verbose_proxy_logger.debug(f"Loaded role_mappings for provider '{role_mappings.provider}'") + verbose_proxy_logger.debug("Loaded role_mappings for provider '%s'", role_mappings.provider) except Exception as e: verbose_proxy_logger.debug( - f"Could not load role_mappings from database: {e}. Continuing with existing role logic." + "Could not load role_mappings from database: %s. Continuing with existing role logic.", e ) generic_role_mappings = os.getenv("GENERIC_ROLE_MAPPINGS_ROLES", None) @@ -1257,12 +1271,12 @@ async def _setup_role_mappings() -> Optional["RoleMappings"]: role_mappings = RoleMappings(**role_mappings_data) verbose_proxy_logger.debug( - f"Loaded role_mappings from environments for provider '{role_mappings.provider}'." + "Loaded role_mappings from environments for provider '%s'.", role_mappings.provider ) return role_mappings except TypeError as e: verbose_proxy_logger.warning( - f"Error decoding role mappings from environment variables: {e}. Continuing with existing role logic." + "Error decoding role mappings from environment variables: %s. Continuing with existing role logic.", e ) return role_mappings @@ -1534,7 +1548,7 @@ async def create_team_member_add_task(team_id, user_info): user_api_key_dict=UserAPIKeyAuth(user_role=LitellmUserRoles.PROXY_ADMIN), ) except Exception as e: - verbose_proxy_logger.debug(f"[Non-Blocking] Error trying to add sso user to db: {e}") + verbose_proxy_logger.debug("[Non-Blocking] Error trying to add sso user to db: %s", e) async def add_missing_team_member(user_info: NewUserResponse | LiteLLM_UserTable, sso_teams: list[str]): @@ -1552,7 +1566,7 @@ async def add_missing_team_member(user_info: NewUserResponse | LiteLLM_UserTable try: await asyncio.gather(*tasks) except Exception as e: - verbose_proxy_logger.debug(f"[Non-Blocking] Error trying to add sso user to db: {e}") + verbose_proxy_logger.debug("[Non-Blocking] Error trying to add sso user to db: %s", e) def get_disabled_non_admin_personal_key_creation(): @@ -1583,7 +1597,7 @@ async def get_existing_user_info_from_db( sso_user_id=user_id, ) except Exception as e: - verbose_proxy_logger.debug(f"Error getting user object: {e}") + verbose_proxy_logger.debug("Error getting user object: %s", e) user_info = None return user_info @@ -1629,7 +1643,7 @@ async def get_user_info_from_db( break verbose_proxy_logger.debug( - f"user_info: {user_info}; litellm.default_internal_user_params: {litellm.default_internal_user_params}" + "user_info: %s; litellm.default_internal_user_params: %s", user_info, litellm.default_internal_user_params ) # Upsert SSO User to LiteLLM DB @@ -1648,7 +1662,7 @@ async def get_user_info_from_db( return user_info except Exception as e: - verbose_proxy_logger.exception(f"[Non-Blocking] Error trying to add sso user to db: {e}") + verbose_proxy_logger.exception("[Non-Blocking] Error trying to add sso user to db: %s", e) return None @@ -1660,8 +1674,8 @@ def _should_use_role_from_sso_response(sso_role: str | None) -> bool: if not is_valid_litellm_user_role(sso_role): verbose_proxy_logger.debug( - f"SSO role '{sso_role}' is not a valid LiteLLM user role. " - "Ignoring role from SSO response. See LitellmUserRoles enum for valid roles." + "SSO role '%s' is not a valid LiteLLM user role. Ignoring role from SSO response. See LitellmUserRoles enum for valid roles.", + sso_role, ) return False return True @@ -1694,7 +1708,7 @@ def _build_sso_user_update_data( # Only include if it's a valid LiteLLM role if _should_use_role_from_sso_response(sso_role_str): update_data["user_role"] = sso_role_str - verbose_proxy_logger.info(f"Updating user {user_id} role from SSO: {sso_role_str}") + verbose_proxy_logger.info("Updating user %s role from SSO: %s", user_id, sso_role_str) return update_data @@ -1726,7 +1740,7 @@ async def _sync_user_role_from_jwt_role_map( if mapped_role is None: return - verbose_proxy_logger.info(f"SSO jwt_litellm_role_map matched role: {mapped_role.value}") + verbose_proxy_logger.info("SSO jwt_litellm_role_map matched role: %s", mapped_role.value) # Update user_defined_values so downstream code uses the mapped role if user_defined_values is not None: @@ -1762,7 +1776,7 @@ def apply_user_info_values_to_sso_user_defined_values( if _should_use_role_from_sso_response(sso_role): # SSO provided a valid role, keep it and log that we're using it - verbose_proxy_logger.info(f"Using SSO role: {sso_role} (DB role was: {db_role})") + verbose_proxy_logger.info("Using SSO role: %s (DB role was: %s)", sso_role, db_role) else: # SSO didn't provide a valid role, fall back to DB role or default if user_info is None or user_info.user_role is None: @@ -1770,7 +1784,7 @@ def apply_user_info_values_to_sso_user_defined_values( verbose_proxy_logger.debug("No SSO or DB role found, using default: INTERNAL_USER_VIEW_ONLY") else: user_defined_values["user_role"] = user_info.user_role - verbose_proxy_logger.debug(f"Using DB role: {user_info.user_role}") + verbose_proxy_logger.debug("Using DB role: %s", user_info.user_role) # Preserve the user's existing models from the database if user_info is not None and hasattr(user_info, "models") and user_info.models: @@ -1803,13 +1817,13 @@ async def check_and_update_if_proxy_admin_id(user_role: str, user_id: str, prism @router.get("/sso/callback", tags=["experimental"], include_in_schema=False) async def auth_callback(request: Request, state: str | None = None): """Verify login""" - verbose_proxy_logger.info(f"Starting SSO callback with state: {state}") + verbose_proxy_logger.info("Starting SSO callback with state: %s", state) oauth_error = request.query_params.get("error") if oauth_error: oauth_error_description = request.query_params.get("error_description") verbose_proxy_logger.warning( - f"SSO callback received OAuth error: {oauth_error}, description: {oauth_error_description}" + "SSO callback received OAuth error: %s, description: %s", oauth_error, oauth_error_description ) raise HTTPException( status_code=401, @@ -1861,7 +1875,7 @@ async def auth_callback(request: Request, state: str | None = None): ) redirect_url = SSOAuthenticationHandler.get_redirect_url_for_sso(request=request, sso_callback_route="sso/callback") - verbose_proxy_logger.info(f"Redirecting to {redirect_url}") + verbose_proxy_logger.info("Redirecting to %s", redirect_url) result = None if google_client_id is not None: result = await GoogleSSOHandler.get_google_callback_response( @@ -2044,7 +2058,7 @@ async def _fetch_cli_sso_team_details( } ) except Exception as e: - verbose_proxy_logger.error(f"Error fetching team details for CLI SSO session: {e}") + verbose_proxy_logger.error("Error fetching team details for CLI SSO session: %s", e) return team_details @@ -2111,7 +2125,7 @@ async def _complete_cli_sso_callback_session( _set_cli_sso_flow(login_id=key, cache=cli_sso_session_cache, flow=flow) verbose_proxy_logger.info( - f"Stored CLI SSO session for user: {user_info.user_id}, teams: {teams}, num_teams: {len(teams)}" + "Stored CLI SSO session for user: %s, teams: %s, num_teams: %s", user_info.user_id, teams, len(teams) ) verify_url = get_custom_url( request_base_url=str(request.base_url), @@ -2165,7 +2179,7 @@ async def cli_sso_callback( result=result_non_none, generic_client_id=os.getenv("GENERIC_CLIENT_ID", None), ) - verbose_proxy_logger.debug(f"parsed_openid_result: {parsed_openid_result}") + verbose_proxy_logger.debug("parsed_openid_result: %s", parsed_openid_result) user_defined_values = await _build_cli_sso_user_defined_values( result=result_non_none, parsed_openid_result=parsed_openid_result, @@ -2196,7 +2210,7 @@ async def cli_sso_callback( except HTTPException: raise except Exception as e: - verbose_proxy_logger.error(f"Error with CLI SSO callback: {e}") + verbose_proxy_logger.error("Error with CLI SSO callback: %s", e) raise HTTPException(status_code=500, detail=f"Failed to process CLI SSO: {e}") @@ -2236,7 +2250,11 @@ async def cli_poll_key( user_id = session_data["user_id"] verbose_proxy_logger.info( - f"CLI poll: user={user_id}, team_id={team_id}, user_teams={user_teams}, num_teams={len(user_teams)}" + "CLI poll: user=%s, team_id=%s, user_teams=%s, num_teams=%s", + user_id, + team_id, + user_teams, + len(user_teams), ) # If no team_id provided and user has teams, return teams list for selection @@ -2244,7 +2262,7 @@ async def cli_poll_key( # clients we return rich team details (id + alias); older clients # can continue to rely on the simple "teams" list. if team_id is None and len(user_teams) > 1: - verbose_proxy_logger.info(f"Returning teams list for user {user_id} to select from: {user_teams}") + verbose_proxy_logger.info("Returning teams list for user %s to select from: %s", user_id, user_teams) # Best-effort construction of team_details if it wasn't # already cached for some reason. team_details_response: list[dict[str, Any]] | None = None @@ -2298,7 +2316,7 @@ async def cli_poll_key( # Delete cache entry (single-use) cli_sso_session_cache.delete_cache(key=_get_cli_sso_flow_cache_key(key_id)) - verbose_proxy_logger.info(f"CLI JWT generated for user: {user_id}, team: {team_id}") + verbose_proxy_logger.info("CLI JWT generated for user: %s, team: %s", user_id, team_id) poll_response = { "status": "ready", "key": jwt_token, @@ -2319,7 +2337,7 @@ async def cli_poll_key( except HTTPException: raise except Exception as e: - verbose_proxy_logger.error(f"Error polling for CLI JWT: {e}") + verbose_proxy_logger.error("Error polling for CLI JWT: %s", e) raise HTTPException(status_code=500, detail=f"Error checking session status: {e}") @@ -2337,7 +2355,7 @@ async def insert_sso_user( Returns: Tuple[str, str]: User ID and User Role """ - verbose_proxy_logger.debug(f"Inserting SSO user into DB. User values: {user_defined_values}") + verbose_proxy_logger.debug("Inserting SSO user into DB. User values: %s", user_defined_values) if result_openid is None: raise ValueError("result_openid is None") if isinstance(result_openid, dict): @@ -2357,7 +2375,7 @@ async def insert_sso_user( preserved_role = sso_role user_defined_values.update(litellm.default_internal_user_params) # type: ignore user_defined_values["user_role"] = preserved_role # Restore preserved role - verbose_proxy_logger.debug(f"Preserved SSO-extracted role '{preserved_role}'") + verbose_proxy_logger.debug("Preserved SSO-extracted role '%s'", preserved_role) else: # SSO didn't provide a valid role, apply all defaults including role user_defined_values.update(litellm.default_internal_user_params) # type: ignore @@ -2671,7 +2689,9 @@ class SSOAuthenticationHandler: redirect_uri=redirect_url, ) verbose_proxy_logger.info( - f"In /google-login/key/generate, \nGOOGLE_REDIRECT_URI: {redirect_url}\nGOOGLE_CLIENT_ID: {google_client_id}" + "In /google-login/key/generate, \nGOOGLE_REDIRECT_URI: %s\nGOOGLE_CLIENT_ID: %s", + redirect_url, + google_client_id, ) with google_sso: return await google_sso.get_login_redirect(state=state) @@ -2733,10 +2753,13 @@ class SSOAuthenticationHandler: code=status.HTTP_500_INTERNAL_SERVER_ERROR, ) verbose_proxy_logger.debug( - f"authorization_endpoint: {generic_authorization_endpoint}\ntoken_endpoint: {generic_token_endpoint}\nuserinfo_endpoint: {generic_userinfo_endpoint}" + "authorization_endpoint: %s\ntoken_endpoint: %s\nuserinfo_endpoint: %s", + generic_authorization_endpoint, + generic_token_endpoint, + generic_userinfo_endpoint, ) verbose_proxy_logger.debug( - f"GENERIC_REDIRECT_URI: {redirect_url}\nGENERIC_CLIENT_ID: {generic_client_id}\n" + "GENERIC_REDIRECT_URI: %s\nGENERIC_CLIENT_ID: %s\n", redirect_url, generic_client_id ) discovery = DiscoveryDocument( authorization_endpoint=generic_authorization_endpoint, @@ -2992,7 +3015,7 @@ class SSOAuthenticationHandler: ) return user_info except Exception as e: - verbose_proxy_logger.exception(f"Error upserting SSO user into LiteLLM DB: {e}") + verbose_proxy_logger.exception("Error upserting SSO user into LiteLLM DB: %s", e) return user_info @staticmethod @@ -3075,11 +3098,11 @@ class SSOAuthenticationHandler: ) try: team_obj = await TeamRepository(prisma_client).table.find_first(where={"team_id": litellm_team_id}) - verbose_proxy_logger.debug(f"Team object: {team_obj}") + verbose_proxy_logger.debug("Team object: %s", team_obj) # only create a new team if it doesn't exist if team_obj: - verbose_proxy_logger.debug(f"Team already exists: {litellm_team_id} - {litellm_team_name}") + verbose_proxy_logger.debug("Team already exists: %s - %s", litellm_team_id, litellm_team_name) return team_request: NewTeamRequest = NewTeamRequest( @@ -3104,7 +3127,7 @@ class SSOAuthenticationHandler: ), ) except Exception as e: - verbose_proxy_logger.exception(f"Error creating Litellm Team: {e}") + verbose_proxy_logger.exception("Error creating Litellm Team: %s", e) @staticmethod def _cast_and_deepcopy_litellm_default_team_params( @@ -3188,7 +3211,7 @@ class SSOAuthenticationHandler: if _user_role is not None: # Convert enum to string if needed user_role = _user_role.value if isinstance(_user_role, LitellmUserRoles) else _user_role - verbose_proxy_logger.debug(f"Extracted user_role from SSO result: {user_role}") + verbose_proxy_logger.debug("Extracted user_role from SSO result: %s", user_role) # generic client id - override with custom attribute name if specified if generic_client_id is not None and result is not None: @@ -3252,7 +3275,7 @@ class SSOAuthenticationHandler: user_email = parsed_openid_result.get("user_email") user_id = parsed_openid_result.get("user_id") user_role = parsed_openid_result.get("user_role") - verbose_proxy_logger.info(f"SSO callback result: {result}") + verbose_proxy_logger.info("SSO callback result: %s", result) user_info = None user_id_models: list = [] @@ -3318,7 +3341,7 @@ class SSOAuthenticationHandler: "Unable to map user identity to known values. 'user_defined_values' is None. File an issue - https://github.com/BerriAI/litellm/issues" ) - verbose_proxy_logger.info(f"user_defined_values for creating ui key: {user_defined_values}") + verbose_proxy_logger.info("user_defined_values for creating ui key: %s", user_defined_values) response = await generate_key_helper_fn( request_type="key", @@ -3346,7 +3369,7 @@ class SSOAuthenticationHandler: user_role=user_role, user_id=user_id, prisma_client=prisma_client ) - verbose_proxy_logger.debug(f"user_role: {user_role}; ui_access_mode: {ui_access_mode}") + verbose_proxy_logger.debug("user_role: %s; ui_access_mode: %s", user_role, ui_access_mode) ## CHECK IF ROLE ALLOWED TO USE PROXY ## is_admin_only_access = check_is_admin_only_access(ui_access_mode or {}) if is_admin_only_access: @@ -3412,7 +3435,7 @@ class SSOAuthenticationHandler: if user_id is not None and isinstance(user_id, str): litellm_dashboard_ui += "?login=success" - verbose_proxy_logger.info(f"Redirecting to {litellm_dashboard_ui}") + verbose_proxy_logger.info("Redirecting to %s", litellm_dashboard_ui) redirect_response = RedirectResponse(url=litellm_dashboard_ui, status_code=303) redirect_response.set_cookie(key="token", value=jwt_token) return redirect_response @@ -4012,7 +4035,7 @@ class MicrosoftSSOHandler: # Extract app roles from the id_token JWT app_roles = MicrosoftSSOHandler.get_app_roles_from_id_token(id_token=microsoft_sso.id_token) - verbose_proxy_logger.debug(f"Extracted app roles from id_token: {app_roles}") + verbose_proxy_logger.debug("Extracted app roles from id_token: %s", app_roles) # Combine groups and app roles user_role: LitellmUserRoles | None = None @@ -4022,10 +4045,10 @@ class MicrosoftSSOHandler: role = get_litellm_user_role(role_str) if role is not None: user_role = role - verbose_proxy_logger.debug(f"Found valid LitellmUserRoles '{role.value}' in app_roles") + verbose_proxy_logger.debug("Found valid LitellmUserRoles '%s' in app_roles", role.value) break - verbose_proxy_logger.debug(f"Combined team_ids (groups + app roles): {user_team_ids}") + verbose_proxy_logger.debug("Combined team_ids (groups + app roles): %s", user_team_ids) # if user is trying to get the raw sso response for debugging, return the raw sso response if return_raw_sso_response: @@ -4047,7 +4070,7 @@ class MicrosoftSSOHandler: user_role: LitellmUserRoles | None, ) -> CustomOpenID: response = response or {} - verbose_proxy_logger.debug(f"Microsoft SSO Callback Response: {response}") + verbose_proxy_logger.debug("Microsoft SSO Callback Response: %s", response) openid_response = CustomOpenID( email=normalize_email(response.get(MICROSOFT_USER_EMAIL_ATTRIBUTE) or response.get("mail")), display_name=response.get(MICROSOFT_USER_DISPLAY_NAME_ATTRIBUTE), @@ -4058,7 +4081,7 @@ class MicrosoftSSOHandler: team_ids=team_ids, user_role=user_role, ) - verbose_proxy_logger.debug(f"Microsoft SSO OpenID Response: {openid_response}") + verbose_proxy_logger.debug("Microsoft SSO OpenID Response: %s", openid_response) return openid_response @staticmethod @@ -4091,14 +4114,14 @@ class MicrosoftSSOHandler: roles = decoded_token.get("app_roles", []) or decoded_token.get("roles", []) if roles and isinstance(roles, list): - verbose_proxy_logger.debug(f"Found {len(roles)} app role(s) in id_token: {roles}") + verbose_proxy_logger.debug("Found %s app role(s) in id_token: %s", len(roles), roles) return roles else: verbose_proxy_logger.debug("No app roles found in id_token or roles claim is not a list") return [] except Exception as e: - verbose_proxy_logger.error(f"Error extracting app roles from id_token: {e}") + verbose_proxy_logger.error("Error extracting app roles from id_token: %s", e) return [] @staticmethod @@ -4130,7 +4153,7 @@ class MicrosoftSSOHandler: async_client=async_client, access_token=access_token, ) - verbose_proxy_logger.debug(f"Service principal group IDs: {service_principal_group_ids}") + verbose_proxy_logger.debug("Service principal group IDs: %s", service_principal_group_ids) if len(service_principal_group_ids) > 0: await MicrosoftSSOHandler.create_litellm_teams_from_service_principal_team_ids( service_principal_teams=service_principal_teams, @@ -4151,7 +4174,8 @@ class MicrosoftSSOHandler: if next_link is not None and page_count >= MicrosoftSSOHandler.MAX_GRAPH_API_PAGES: verbose_proxy_logger.warning( - f"Reached maximum page limit of {MicrosoftSSOHandler.MAX_GRAPH_API_PAGES}. Some groups may not be included." + "Reached maximum page limit of %s. Some groups may not be included.", + MicrosoftSSOHandler.MAX_GRAPH_API_PAGES, ) # If service_principal_group_ids is not empty, only return group_ids that are in both all_group_ids and service_principal_group_ids @@ -4161,7 +4185,7 @@ class MicrosoftSSOHandler: return all_group_ids except Exception as e: - verbose_proxy_logger.error(f"Error getting user groups from Microsoft Graph API: {e}") + verbose_proxy_logger.error("Error getting user groups from Microsoft Graph API: %s", e) return [] @staticmethod @@ -4238,7 +4262,7 @@ class MicrosoftSSOHandler: while next_link is not None and page_count < MicrosoftSSOHandler.MAX_GRAPH_API_PAGES: response = await async_client.get(next_link, headers=headers) response_json = response.json() - verbose_proxy_logger.debug(f"Response from service principal app role assigned to: {response_json}") + verbose_proxy_logger.debug("Response from service principal app role assigned to: %s", response_json) for _object in response_json.get("value", []): if _object.get("principalType") == "Group": @@ -4257,7 +4281,8 @@ class MicrosoftSSOHandler: if next_link is not None and page_count >= MicrosoftSSOHandler.MAX_GRAPH_API_PAGES: verbose_proxy_logger.warning( - f"Reached maximum page limit of {MicrosoftSSOHandler.MAX_GRAPH_API_PAGES}. Some service principal group assignments may not be included." + "Reached maximum page limit of %s. Some service principal group assignments may not be included.", + MicrosoftSSOHandler.MAX_GRAPH_API_PAGES, ) return group_ids, service_principal_teams @@ -4271,13 +4296,13 @@ class MicrosoftSSOHandler: When a user sets a `SERVICE_PRINCIPAL_ID` in the env, litellm will fetch groups under that service principal and create Litellm Teams from them """ - verbose_proxy_logger.debug(f"Creating Litellm Teams from Service Principal Teams: {service_principal_teams}") + verbose_proxy_logger.debug("Creating Litellm Teams from Service Principal Teams: %s", service_principal_teams) for service_principal_team in service_principal_teams: litellm_team_id: str | None = service_principal_team.get("principalId") litellm_team_name: str | None = service_principal_team.get("principalDisplayName") if not litellm_team_id: verbose_proxy_logger.debug( - f"Skipping team creation for {litellm_team_name} because it has no principalId" + "Skipping team creation for %s because it has no principalId", litellm_team_name ) continue diff --git a/litellm/proxy/management_helpers/audit_logs.py b/litellm/proxy/management_helpers/audit_logs.py index 8677627c607..081bd6af866 100644 --- a/litellm/proxy/management_helpers/audit_logs.py +++ b/litellm/proxy/management_helpers/audit_logs.py @@ -231,4 +231,4 @@ async def create_audit_log_for_update(request_data: LiteLLM_AuditLogs): ) except Exception as e: # [Non-Blocking Exception. Do not allow blocking LLM API call] - verbose_proxy_logger.error(f"Failed Creating audit log {e}") + verbose_proxy_logger.error("Failed Creating audit log %s", e) diff --git a/litellm/proxy/management_helpers/object_permission_utils.py b/litellm/proxy/management_helpers/object_permission_utils.py index 24bfbe2f9a9..69665151f07 100644 --- a/litellm/proxy/management_helpers/object_permission_utils.py +++ b/litellm/proxy/management_helpers/object_permission_utils.py @@ -166,7 +166,7 @@ async def handle_update_object_permission_common( }, ) - verbose_proxy_logger.debug(f"created_object_permission_row: {created_object_permission_row}") + verbose_proxy_logger.debug("created_object_permission_row: %s", created_object_permission_row) return created_object_permission_row.object_permission_id @@ -572,8 +572,8 @@ async def validate_key_mcp_servers_against_team( } if stale_identifiers: verbose_proxy_logger.warning( - "validate_key_mcp_servers_against_team: ignoring stale MCP server " - f"identifiers (no longer in registry or DB): {sorted(stale_identifiers)}" + "validate_key_mcp_servers_against_team: ignoring stale MCP server identifiers (no longer in registry or DB): %s", + sorted(stale_identifiers), ) _rewrite_object_permission_mcp_identifiers( object_permission=object_permission, diff --git a/litellm/proxy/ocr_endpoints/endpoints.py b/litellm/proxy/ocr_endpoints/endpoints.py index ca25be9d92c..acc3f85076f 100644 --- a/litellm/proxy/ocr_endpoints/endpoints.py +++ b/litellm/proxy/ocr_endpoints/endpoints.py @@ -96,9 +96,10 @@ async def _parse_multipart_form(request: Request) -> dict[str, Any]: data[field_name] = field_value verbose_proxy_logger.debug( - f"OCR multipart form request parsed - model: {data.get('model')}, " - f"document_type: {document['type']}, " - f"filename: {uploaded_file.filename}" + "OCR multipart form request parsed - model: %s, document_type: %s, filename: %s", + data.get("model"), + document["type"], + uploaded_file.filename, ) return data diff --git a/litellm/proxy/openai_files_endpoints/common_utils.py b/litellm/proxy/openai_files_endpoints/common_utils.py index 87514b46dbd..76b956f31b2 100644 --- a/litellm/proxy/openai_files_endpoints/common_utils.py +++ b/litellm/proxy/openai_files_endpoints/common_utils.py @@ -983,10 +983,10 @@ async def ensure_batch_response_managed_file_ids( user_api_key_dict=user_api_key_dict, ) setattr(response, file_attr, new_unified_file_id) - verbose_proxy_logger.debug(f"Converted batch {file_attr} {raw_file_id!r} to managed ID before DB write") + verbose_proxy_logger.debug("Converted batch %s %r to managed ID before DB write", file_attr, raw_file_id) except Exception as e: verbose_proxy_logger.warning( - f"Failed to convert batch {file_attr}={raw_file_id!r} to managed ID before DB write: {e}" + "Failed to convert batch %s=%r to managed ID before DB write: %s", file_attr, raw_file_id, e ) @@ -1042,12 +1042,16 @@ async def get_batch_from_database( # The stored batch object has the raw provider input_file_id. Resolve to unified ID. await resolve_input_file_id_to_unified(response, prisma_client) - verbose_proxy_logger.debug(f"Retrieved batch {batch_id} from ManagedObjectTable with status={response.status}") + verbose_proxy_logger.debug( + "Retrieved batch %s from ManagedObjectTable with status=%s", batch_id, response.status + ) return db_batch_object, response except Exception as e: - verbose_proxy_logger.warning(f"Failed to retrieve batch from ManagedObjectTable: {e}, falling back to provider") + verbose_proxy_logger.warning( + "Failed to retrieve batch from ManagedObjectTable: %s, falling back to provider", e + ) return None, None @@ -1103,10 +1107,10 @@ async def update_batch_in_database( if db_batch_object: verbose_proxy_logger.info( - f"Updating batch {batch_id} status from {db_batch_object.status} to {response.status}" + "Updating batch %s status from %s to %s", batch_id, db_batch_object.status, response.status ) else: - verbose_proxy_logger.info(f"Updating batch {batch_id} status to {response.status} after {operation}") + verbose_proxy_logger.info("Updating batch %s status to %s after %s", batch_id, response.status, operation) # Normalize status for database storage db_status = response.status if response.status != "completed" else "complete" @@ -1138,7 +1142,9 @@ async def update_batch_in_database( # retry without it so the status update still succeeds. err_str = str(col_err).lower() if "batch_processed" in err_str and update_data.get("batch_processed") is not None: - verbose_proxy_logger.warning(f"batch_processed column not found, retrying update without it: {col_err}") + verbose_proxy_logger.warning( + "batch_processed column not found, retrying update without it: %s", col_err + ) update_data.pop("batch_processed", None) await ManagedObjectRepository(prisma_client).table.update( where={"unified_object_id": batch_id}, @@ -1147,4 +1153,4 @@ async def update_batch_in_database( else: raise except Exception as e: - verbose_proxy_logger.error(f"Failed to update batch status in ManagedObjectTable: {e}") + verbose_proxy_logger.error("Failed to update batch status in ManagedObjectTable: %s", e) diff --git a/litellm/proxy/openai_files_endpoints/files_endpoints.py b/litellm/proxy/openai_files_endpoints/files_endpoints.py index 5d4c3c04818..51b9139cff1 100644 --- a/litellm/proxy/openai_files_endpoints/files_endpoints.py +++ b/litellm/proxy/openai_files_endpoints/files_endpoints.py @@ -208,7 +208,7 @@ async def route_create_file( original_id = response.id encoded_id = encode_file_id_with_model(file_id=original_id, model=model) response.id = encoded_id - verbose_proxy_logger.debug(f"Encoded file ID: {original_id} -> {encoded_id} (model: {model})") + verbose_proxy_logger.debug("Encoded file ID: %s -> %s (model: %s)", original_id, encoded_id, model) return response @@ -549,7 +549,7 @@ async def create_file( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.create_file(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.create_file(): Exception occured - %s", e) if isinstance(e, HTTPException): raise ProxyException( message=getattr(e, "message", str(e.detail)), @@ -845,7 +845,7 @@ async def get_file_content( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.retrieve_file_content(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.retrieve_file_content(): Exception occured - %s", e) verbose_proxy_logger.debug(traceback.format_exc()) if isinstance(e, HTTPException): raise ProxyException( @@ -1032,7 +1032,7 @@ async def get_file( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.error(f"litellm.proxy.proxy_server.retrieve_file(): Exception occured - {e}") + verbose_proxy_logger.error("litellm.proxy.proxy_server.retrieve_file(): Exception occured - %s", e) verbose_proxy_logger.debug(traceback.format_exc()) if isinstance(e, HTTPException): raise ProxyException( @@ -1238,7 +1238,7 @@ async def delete_file( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.delete_file(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.delete_file(): Exception occured - %s", e) if isinstance(e, HTTPException): raise ProxyException( message=getattr(e, "message", str(e.detail)), @@ -1337,7 +1337,7 @@ async def list_files( **data, # type: ignore ) - verbose_proxy_logger.debug(f"Listed files using model: {model_used}") + verbose_proxy_logger.debug("Listed files using model: %s", model_used) elif target_model_names and isinstance(target_model_names, str): target_model_names_list = target_model_names.split(",") @@ -1427,7 +1427,7 @@ async def list_files( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.error(f"litellm.proxy.proxy_server.list_files(): Exception occured - {e}") + verbose_proxy_logger.error("litellm.proxy.proxy_server.list_files(): Exception occured - %s", e) verbose_proxy_logger.debug(traceback.format_exc()) if isinstance(e, HTTPException): raise ProxyException( diff --git a/litellm/proxy/openai_files_endpoints/storage_backend_service.py b/litellm/proxy/openai_files_endpoints/storage_backend_service.py index b9658d8efee..200bad13a9f 100644 --- a/litellm/proxy/openai_files_endpoints/storage_backend_service.py +++ b/litellm/proxy/openai_files_endpoints/storage_backend_service.py @@ -82,7 +82,7 @@ class StorageBackendFileService: file_naming_strategy="uuid", ) - verbose_proxy_logger.debug(f"Storage backend upload complete: backend={target_storage}, url={storage_url}") + verbose_proxy_logger.debug("Storage backend upload complete: backend=%s, url=%s", target_storage, storage_url) # Create file object with storage metadata file_object = StorageBackendFileService._create_file_object_with_storage_metadata( @@ -223,8 +223,10 @@ class StorageBackendFileService: file_object.id = base64_unified_file_id verbose_proxy_logger.debug( - f"Storing file in managed files: unified_id={base64_unified_file_id}, " - f"storage_backend={target_storage}, storage_url={storage_url}" + "Storing file in managed files: unified_id=%s, storage_backend=%s, storage_url=%s", + base64_unified_file_id, + target_storage, + storage_url, ) # Store in managed files diff --git a/litellm/proxy/pass_through_endpoints/llm_passthrough_endpoints.py b/litellm/proxy/pass_through_endpoints/llm_passthrough_endpoints.py index 0d9b0ab9c49..026a76a767c 100644 --- a/litellm/proxy/pass_through_endpoints/llm_passthrough_endpoints.py +++ b/litellm/proxy/pass_through_endpoints/llm_passthrough_endpoints.py @@ -752,7 +752,7 @@ async def handle_bedrock_passthrough_router_model( is_streaming = any(action in endpoint for action in BEDROCK_STREAMING_ACTIONS) verbose_proxy_logger.debug( - f"Bedrock router passthrough: model='{model}', endpoint='{endpoint}', streaming={is_streaming}" + "Bedrock router passthrough: model='%s', endpoint='%s', streaming=%s", model, endpoint, is_streaming ) # Use the common processing path (same as non-router models) @@ -843,8 +843,8 @@ async def handle_bedrock_count_tokens( if key != "user_api_key_dict": # Don't overwrite user_api_key_dict litellm_params[key] = value # type: ignore - verbose_proxy_logger.debug(f"Count tokens litellm_params: {litellm_params}") - verbose_proxy_logger.debug(f"Resolved model: {resolved_model}") + verbose_proxy_logger.debug("Count tokens litellm_params: %s", litellm_params) + verbose_proxy_logger.debug("Resolved model: %s", resolved_model) # Handle the count tokens request result = await handler.handle_count_tokens_request( @@ -857,13 +857,13 @@ async def handle_bedrock_count_tokens( except BedrockError as e: # Convert BedrockError to HTTPException for FastAPI - verbose_proxy_logger.error(f"BedrockError in handle_bedrock_count_tokens: {e}") + verbose_proxy_logger.error("BedrockError in handle_bedrock_count_tokens: %s", e) raise HTTPException(status_code=e.status_code, detail={"error": e.message}) except HTTPException: # Re-raise HTTP exceptions as-is raise except Exception as e: - verbose_proxy_logger.error(f"Error in handle_bedrock_count_tokens: {e}") + verbose_proxy_logger.error("Error in handle_bedrock_count_tokens: %s", e) raise HTTPException(status_code=500, detail={"error": f"CountTokens processing error: {e}"}) @@ -947,7 +947,9 @@ async def bedrock_llm_proxy_route( ) # Fall back to existing implementation for direct Bedrock models - verbose_proxy_logger.debug(f"Bedrock passthrough: Using direct Bedrock model '{model}' for endpoint '{endpoint}'") + verbose_proxy_logger.debug( + "Bedrock passthrough: Using direct Bedrock model '%s' for endpoint '%s'", model, endpoint + ) data: dict[str, Any] = {} base_llm_response_processor = ProxyBaseLLMRequestProcessing(data=data) @@ -1148,7 +1150,7 @@ def _resolve_vertex_model_from_router( endpoint = endpoint.replace(model_id, actual_model) except Exception as e: - verbose_proxy_logger.debug(f"Error resolving vertex model from router for model {model_id}: {e}") + verbose_proxy_logger.debug("Error resolving vertex model from router for model %s: %s", model_id, e) return encoded_endpoint, endpoint, vertex_project, vertex_location diff --git a/litellm/proxy/pass_through_endpoints/llm_provider_handlers/anthropic_passthrough_logging_handler.py b/litellm/proxy/pass_through_endpoints/llm_provider_handlers/anthropic_passthrough_logging_handler.py index 5d045ff2852..275283e3e56 100644 --- a/litellm/proxy/pass_through_endpoints/llm_provider_handlers/anthropic_passthrough_logging_handler.py +++ b/litellm/proxy/pass_through_endpoints/llm_provider_handlers/anthropic_passthrough_logging_handler.py @@ -920,7 +920,7 @@ class AnthropicPassthroughLoggingHandler: } except Exception as e: - verbose_proxy_logger.error(f"Error in batch_creation_handler: {e}") + verbose_proxy_logger.error("Error in batch_creation_handler: %s", e) # Return basic response on error litellm_model_response = ModelResponse() litellm_model_response.id = str(uuid.uuid4()) @@ -1017,7 +1017,9 @@ class AnthropicPassthroughLoggingHandler: ) verbose_proxy_logger.info( - f"Stored Anthropic batch managed object with unified_object_id={unified_object_id}, batch_id={model_object_id}" + "Stored Anthropic batch managed object with unified_object_id=%s, batch_id=%s", + unified_object_id, + model_object_id, ) else: verbose_proxy_logger.warning( @@ -1025,7 +1027,7 @@ class AnthropicPassthroughLoggingHandler: ) except Exception as e: - verbose_proxy_logger.error(f"Error storing Anthropic batch managed object: {e}") + verbose_proxy_logger.error("Error storing Anthropic batch managed object: %s", e) @staticmethod def get_actual_model_id_from_router(model_name: str) -> str: @@ -1038,14 +1040,14 @@ class AnthropicPassthroughLoggingHandler: if model_ids and len(model_ids) > 0: # Use the first model ID found actual_model_id = model_ids[0] - verbose_proxy_logger.info(f"Found model ID in router: {actual_model_id}") + verbose_proxy_logger.info("Found model ID in router: %s", actual_model_id) return actual_model_id else: # Fallback to model name actual_model_id = model_name - verbose_proxy_logger.warning(f"Model not found in router, using model name: {actual_model_id}") + verbose_proxy_logger.warning("Model not found in router, using model name: %s", actual_model_id) return actual_model_id else: # Fallback if router is not available - verbose_proxy_logger.warning(f"Router not available, using model name: {model_name}") + verbose_proxy_logger.warning("Router not available, using model name: %s", model_name) return model_name diff --git a/litellm/proxy/pass_through_endpoints/llm_provider_handlers/assembly_passthrough_logging_handler.py b/litellm/proxy/pass_through_endpoints/llm_provider_handlers/assembly_passthrough_logging_handler.py index 397f1d94a34..97cbe9a0615 100644 --- a/litellm/proxy/pass_through_endpoints/llm_provider_handlers/assembly_passthrough_logging_handler.py +++ b/litellm/proxy/pass_through_endpoints/llm_provider_handlers/assembly_passthrough_logging_handler.py @@ -203,7 +203,7 @@ class AssemblyAIPassthroughLoggingHandler: return response.json() except Exception as e: - verbose_proxy_logger.exception(f"[Non blocking logging error] Error getting AssemblyAI transcript: {e}") + verbose_proxy_logger.exception("[Non blocking logging error] Error getting AssemblyAI transcript: %s", e) return None def _poll_assembly_for_transcript_response( @@ -275,7 +275,7 @@ class AssemblyAIPassthroughLoggingHandler: return None except Exception as e: - verbose_proxy_logger.exception(f"[Non blocking logging error] Error getting AssemblyAI model info: {e}") + verbose_proxy_logger.exception("[Non blocking logging error] Error getting AssemblyAI model info: %s", e) return None @staticmethod diff --git a/litellm/proxy/pass_through_endpoints/llm_provider_handlers/openai_passthrough_logging_handler.py b/litellm/proxy/pass_through_endpoints/llm_provider_handlers/openai_passthrough_logging_handler.py index 63414a1c19e..18e56d914c6 100644 --- a/litellm/proxy/pass_through_endpoints/llm_provider_handlers/openai_passthrough_logging_handler.py +++ b/litellm/proxy/pass_through_endpoints/llm_provider_handlers/openai_passthrough_logging_handler.py @@ -183,7 +183,7 @@ class OpenAIPassthroughLoggingHandler(BasePassthroughLoggingHandler): return cost except Exception as e: - verbose_proxy_logger.warning(f"Error calculating image generation cost: {e}") + verbose_proxy_logger.warning("Error calculating image generation cost: %s", e) return 0.0 @staticmethod @@ -217,7 +217,7 @@ class OpenAIPassthroughLoggingHandler(BasePassthroughLoggingHandler): return cost except Exception as e: - verbose_proxy_logger.warning(f"Error calculating image editing cost: {e}") + verbose_proxy_logger.warning("Error calculating image editing cost: %s", e) return 0.0 @staticmethod @@ -445,7 +445,7 @@ class OpenAIPassthroughLoggingHandler(BasePassthroughLoggingHandler): } except Exception as e: - verbose_proxy_logger.error(f"Error in OpenAI passthrough cost tracking: {e}") + verbose_proxy_logger.error("Error in OpenAI passthrough cost tracking: %s", e) # Fall back to base handler without cost tracking base_handler = OpenAIPassthroughLoggingHandler() return base_handler.passthrough_chat_handler( @@ -501,7 +501,7 @@ class OpenAIPassthroughLoggingHandler(BasePassthroughLoggingHandler): all_openai_chunks.append(transformed_chunk) except (StopIteration, StopAsyncIteration, Exception) as e: - verbose_proxy_logger.debug(f"Error parsing streaming chunk: {e}") + verbose_proxy_logger.debug("Error parsing streaming chunk: %s", e) continue if not all_openai_chunks: @@ -514,7 +514,7 @@ class OpenAIPassthroughLoggingHandler(BasePassthroughLoggingHandler): return complete_streaming_response except Exception as e: - verbose_proxy_logger.error(f"Error building complete streaming response: {e}") + verbose_proxy_logger.error("Error building complete streaming response: %s", e) return None @staticmethod @@ -608,7 +608,7 @@ class OpenAIPassthroughLoggingHandler(BasePassthroughLoggingHandler): } except Exception as e: - verbose_proxy_logger.error(f"Error in OpenAI streaming passthrough cost tracking: {e}") + verbose_proxy_logger.error("Error in OpenAI streaming passthrough cost tracking: %s", e) return { "result": None, "kwargs": {}, diff --git a/litellm/proxy/pass_through_endpoints/llm_provider_handlers/vertex_ai_live_passthrough_logging_handler.py b/litellm/proxy/pass_through_endpoints/llm_provider_handlers/vertex_ai_live_passthrough_logging_handler.py index 11672571f3f..fd703b22549 100644 --- a/litellm/proxy/pass_through_endpoints/llm_provider_handlers/vertex_ai_live_passthrough_logging_handler.py +++ b/litellm/proxy/pass_through_endpoints/llm_provider_handlers/vertex_ai_live_passthrough_logging_handler.py @@ -148,11 +148,11 @@ class VertexAILivePassthroughLoggingHandler(BasePassthroughLoggingHandler): # Get model pricing information model_info = get_model_info(model=model, custom_llm_provider=custom_llm_provider) - verbose_proxy_logger.debug(f"Vertex AI Live API model info for '{model}': {model_info}") + verbose_proxy_logger.debug("Vertex AI Live API model info for '%s': %s", model, model_info) # Check if pricing info is available if not model_info or not model_info.get("input_cost_per_token"): - verbose_proxy_logger.error(f"No pricing info found for {model} in local model pricing database") + verbose_proxy_logger.error("No pricing info found for %s in local model pricing database", model) return 0.0 total_cost = 0.0 @@ -221,7 +221,7 @@ class VertexAILivePassthroughLoggingHandler(BasePassthroughLoggingHandler): return total_cost except Exception as e: - verbose_proxy_logger.error(f"Error calculating Vertex AI Live API cost: {e}") + verbose_proxy_logger.error("Error calculating Vertex AI Live API cost: %s", e) return 0.0 @staticmethod @@ -302,7 +302,9 @@ class VertexAILivePassthroughLoggingHandler(BasePassthroughLoggingHandler): # Extract model from request body or kwargs model = kwargs.get("model", "gemini-2.0-flash-live-preview-04-09") custom_llm_provider = kwargs.get("custom_llm_provider", "vertex_ai") - verbose_proxy_logger.debug(f"Vertex AI Live API model: {model}, custom_llm_provider: {custom_llm_provider}") + verbose_proxy_logger.debug( + "Vertex AI Live API model: %s, custom_llm_provider: %s", model, custom_llm_provider + ) # Extract usage metadata from WebSocket messages usage_metadata = self._extract_usage_metadata_from_websocket_messages(websocket_messages) @@ -360,7 +362,7 @@ class VertexAILivePassthroughLoggingHandler(BasePassthroughLoggingHandler): } except Exception as e: - verbose_proxy_logger.error(f"Error in Vertex AI Live API passthrough handler: {e}") + verbose_proxy_logger.error("Error in Vertex AI Live API passthrough handler: %s", e) return { "result": None, "kwargs": kwargs, diff --git a/litellm/proxy/pass_through_endpoints/llm_provider_handlers/vertex_passthrough_logging_handler.py b/litellm/proxy/pass_through_endpoints/llm_provider_handlers/vertex_passthrough_logging_handler.py index 233127c3fef..bab16d0ba54 100644 --- a/litellm/proxy/pass_through_endpoints/llm_provider_handlers/vertex_passthrough_logging_handler.py +++ b/litellm/proxy/pass_through_endpoints/llm_provider_handlers/vertex_passthrough_logging_handler.py @@ -744,7 +744,7 @@ class VertexPassthroughLoggingHandler: } except Exception as e: - verbose_proxy_logger.error(f"Error in batch_prediction_jobs_handler: {e}") + verbose_proxy_logger.error("Error in batch_prediction_jobs_handler: %s", e) # Return basic response on error litellm_model_response = ModelResponse() litellm_model_response.id = str(uuid.uuid4()) @@ -841,7 +841,9 @@ class VertexPassthroughLoggingHandler: ) verbose_proxy_logger.info( - f"Stored batch managed object with unified_object_id={unified_object_id}, batch_id={model_object_id}" + "Stored batch managed object with unified_object_id=%s, batch_id=%s", + unified_object_id, + model_object_id, ) else: verbose_proxy_logger.warning( @@ -849,7 +851,7 @@ class VertexPassthroughLoggingHandler: ) except Exception as e: - verbose_proxy_logger.error(f"Error storing batch managed object: {e}") + verbose_proxy_logger.error("Error storing batch managed object: %s", e) @staticmethod def get_actual_model_id_from_router(model_name: str) -> str: @@ -864,15 +866,15 @@ class VertexPassthroughLoggingHandler: if model_ids and len(model_ids) > 0: # Use the first model ID found actual_model_id = model_ids[0] - verbose_proxy_logger.info(f"Found model ID in router: {actual_model_id}") + verbose_proxy_logger.info("Found model ID in router: %s", actual_model_id) return actual_model_id else: # Fallback to constructed model name actual_model_id = extracted_model_name - verbose_proxy_logger.warning(f"Model not found in router, using constructed name: {actual_model_id}") + verbose_proxy_logger.warning("Model not found in router, using constructed name: %s", actual_model_id) return actual_model_id else: # Fallback if router is not available extracted_model_name = VertexPassthroughLoggingHandler.extract_model_name_from_vertex_path(model_name) - verbose_proxy_logger.warning(f"Router not available, using constructed model name: {extracted_model_name}") + verbose_proxy_logger.warning("Router not available, using constructed model name: %s", extracted_model_name) return extracted_model_name diff --git a/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py b/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py index b8aba215d10..171df5b4d2c 100644 --- a/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py +++ b/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py @@ -294,7 +294,7 @@ async def chat_completion_pass_through_endpoint( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.completion(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.completion(): Exception occured - %s", e) error_msg = f"{e}" raise ProxyException( message=getattr(e, "message", error_msg), @@ -890,7 +890,7 @@ async def pass_through_request( if "metadata" not in _parsed_body: _parsed_body["metadata"] = {} _parsed_body["metadata"]["guardrails"] = guardrails_to_run - verbose_proxy_logger.debug(f"Added guardrails to passthrough request metadata: {guardrails_to_run}") + verbose_proxy_logger.debug("Added guardrails to passthrough request metadata: %s", guardrails_to_run) ## LOGGING OBJECT ## - initialize before pre_call_hook so guardrails can access it # Surface the requested model (when the body carries one) so logging/spans @@ -1502,7 +1502,7 @@ async def pass_through_request( ) else: verbose_proxy_logger.exception( - f"litellm.proxy.proxy_server.pass_through_endpoint(): Exception occured - {e}" + "litellm.proxy.proxy_server.pass_through_endpoint(): Exception occured - %s", e ) ######################################################### @@ -1887,12 +1887,12 @@ async def websocket_passthrough_request( websocket_messages: list[dict[str, Any]] = [] litellm_call_id = str(uuid.uuid4()) - verbose_proxy_logger.info(f"WebSocket passthrough ({endpoint}): Starting WebSocket connection to {target}") + verbose_proxy_logger.info("WebSocket passthrough (%s): Starting WebSocket connection to %s", endpoint, target) # Only accept the WebSocket if requested (for generic usage) if accept_websocket: await websocket.accept() - verbose_proxy_logger.debug(f"WebSocket passthrough ({endpoint}): WebSocket connection accepted") + verbose_proxy_logger.debug("WebSocket passthrough (%s): WebSocket connection accepted", endpoint) # Prepare headers for the upstream connection upstream_headers = custom_headers.copy() @@ -1985,13 +1985,15 @@ async def websocket_passthrough_request( ) try: - verbose_proxy_logger.debug(f"WebSocket passthrough ({endpoint}): Establishing upstream connection to {target}") + verbose_proxy_logger.debug( + "WebSocket passthrough (%s): Establishing upstream connection to %s", endpoint, target + ) async with connect( target, additional_headers=upstream_headers, ) as upstream_ws: verbose_proxy_logger.info( - f"WebSocket passthrough ({endpoint}): Upstream connection established successfully" + "WebSocket passthrough (%s): Upstream connection established successfully", endpoint ) async def forward_client_to_upstream() -> None: @@ -2011,14 +2013,17 @@ async def websocket_passthrough_request( # Try to extract model from client setup message for Vertex AI Live if endpoint and "/vertex_ai/live" in endpoint: verbose_proxy_logger.debug( - f"WebSocket passthrough ({endpoint}): Processing client message for model extraction" + "WebSocket passthrough (%s): Processing client message for model extraction", + endpoint, ) try: client_message = json.loads(text_data) if isinstance(client_message, dict) and "setup" in client_message: setup_data = client_message["setup"] verbose_proxy_logger.debug( - f"WebSocket passthrough ({endpoint}): Found setup data in client message: {setup_data}" + "WebSocket passthrough (%s): Found setup data in client message: %s", + endpoint, + setup_data, ) if isinstance(setup_data, dict) and "model" in setup_data: extracted_model = _extract_model_from_vertex_ai_setup(setup_data) @@ -2030,23 +2035,32 @@ async def websocket_passthrough_request( logging_obj.model_call_details["model"] = extracted_model logging_obj.model_call_details["custom_llm_provider"] = "vertex_ai" verbose_proxy_logger.info( - f"WebSocket passthrough ({endpoint}): Successfully extracted model '{extracted_model}' and set provider to 'vertex_ai' from client setup message" + "WebSocket passthrough (%s): Successfully extracted model '%s' and set provider to 'vertex_ai' from client setup message", + endpoint, + extracted_model, ) else: verbose_proxy_logger.warning( - f"WebSocket passthrough ({endpoint}): Failed to extract model from client setup data: {setup_data}" + "WebSocket passthrough (%s): Failed to extract model from client setup data: %s", + endpoint, + setup_data, ) else: verbose_proxy_logger.debug( - f"WebSocket passthrough ({endpoint}): Setup data does not contain model field: {setup_data}" + "WebSocket passthrough (%s): Setup data does not contain model field: %s", + endpoint, + setup_data, ) else: verbose_proxy_logger.debug( - f"WebSocket passthrough ({endpoint}): Client message does not contain setup data" + "WebSocket passthrough (%s): Client message does not contain setup data", + endpoint, ) except (json.JSONDecodeError, KeyError, TypeError) as e: verbose_proxy_logger.debug( - f"WebSocket passthrough ({endpoint}): Client message is not a valid setup message: {e}" + "WebSocket passthrough (%s): Client message is not a valid setup message: %s", + endpoint, + e, ) # Not a JSON message or doesn't contain setup data @@ -2057,7 +2071,7 @@ async def websocket_passthrough_request( raise except Exception: verbose_proxy_logger.exception( - f"WebSocket passthrough ({endpoint}): error forwarding client message" + "WebSocket passthrough (%s): error forwarding client message", endpoint ) await upstream_ws.close() @@ -2070,12 +2084,13 @@ async def websocket_passthrough_request( if isinstance(raw_response, str): raw_response = raw_response.encode("ascii") setup_response = json.loads(raw_response.decode("ascii")) - verbose_proxy_logger.debug(f"Setup response: {setup_response}") + verbose_proxy_logger.debug("Setup response: %s", setup_response) # Extract model and provider from setup response for Vertex AI Live if endpoint and "/vertex_ai/live" in endpoint: verbose_proxy_logger.debug( - f"WebSocket passthrough ({endpoint}): Processing server setup response for model extraction" + "WebSocket passthrough (%s): Processing server setup response for model extraction", + endpoint, ) extracted_model = _extract_model_from_vertex_ai_setup(setup_response) if extracted_model: @@ -2086,15 +2101,20 @@ async def websocket_passthrough_request( logging_obj.model_call_details["model"] = extracted_model logging_obj.model_call_details["custom_llm_provider"] = "vertex_ai_language_models" verbose_proxy_logger.debug( - f"WebSocket passthrough ({endpoint}): Successfully extracted model '{extracted_model}' and set provider to 'vertex_ai' from server setup response" + "WebSocket passthrough (%s): Successfully extracted model '%s' and set provider to 'vertex_ai' from server setup response", + endpoint, + extracted_model, ) else: verbose_proxy_logger.warning( - f"WebSocket passthrough ({endpoint}): Failed to extract model from server setup response: {setup_response}" + "WebSocket passthrough (%s): Failed to extract model from server setup response: %s", + endpoint, + setup_response, ) else: verbose_proxy_logger.debug( - f"WebSocket passthrough ({endpoint}): Not a Vertex AI Live endpoint, skipping model extraction" + "WebSocket passthrough (%s): Not a Vertex AI Live endpoint, skipping model extraction", + endpoint, ) # Send the setup response to the client @@ -2120,14 +2140,14 @@ async def websocket_passthrough_request( pass except (ConnectionClosedOK, ConnectionClosedError) as e: - verbose_proxy_logger.debug(f"Upstream WebSocket connection closed: {e}") + verbose_proxy_logger.debug("Upstream WebSocket connection closed: %s", e) except asyncio.CancelledError: verbose_proxy_logger.debug("asyncio.CancelledError in forward_upstream_to_client") raise except Exception as e: - verbose_proxy_logger.debug(f"Exception in forward_upstream_to_client: {e}") + verbose_proxy_logger.debug("Exception in forward_upstream_to_client: %s", e) verbose_proxy_logger.exception( - f"WebSocket passthrough ({endpoint}): error forwarding upstream message" + "WebSocket passthrough (%s): error forwarding upstream message", endpoint ) raise @@ -2218,7 +2238,7 @@ async def websocket_passthrough_request( ) except InvalidStatus as exc: - verbose_proxy_logger.exception(f"WebSocket passthrough ({endpoint}): upstream rejected WebSocket connection") + verbose_proxy_logger.exception("WebSocket passthrough (%s): upstream rejected WebSocket connection", endpoint) # Prepare request payload for logging request_payload = {} @@ -2244,7 +2264,9 @@ async def websocket_passthrough_request( reason="Upstream connection rejected", ) except Exception as e: - verbose_proxy_logger.exception(f"WebSocket passthrough ({endpoint}): unexpected error while proxying WebSocket") + verbose_proxy_logger.exception( + "WebSocket passthrough (%s): unexpected error while proxying WebSocket", endpoint + ) # Prepare request payload for logging request_payload = {} @@ -2321,8 +2343,9 @@ async def _relay_passthrough_response_bytes( finally: if not upstream_fully_relayed: verbose_proxy_logger.warning( - f"Passthrough stream for {url_route} ended before upstream body was fully relayed; " - f"{bytes_relayed} bytes were sent to the client" + "Passthrough stream for %s ended before upstream body was fully relayed; %s bytes were sent to the client", + url_route, + bytes_relayed, ) await response.aclose() GLOBAL_LOGGING_WORKER.ensure_initialized_and_enqueue( @@ -2370,7 +2393,7 @@ def _extract_model_from_vertex_ai_setup(setup_response: dict) -> str | None: model_name = model_path.split("/models/")[-1] return model_name except Exception as e: - verbose_proxy_logger.debug(f"Error extracting model from setup response: {e}") + verbose_proxy_logger.debug("Error extracting model from setup response: %s", e) return None diff --git a/litellm/proxy/pass_through_endpoints/passthrough_endpoint_router.py b/litellm/proxy/pass_through_endpoints/passthrough_endpoint_router.py index ed35e3d1b46..bd7f7b94f7a 100644 --- a/litellm/proxy/pass_through_endpoints/passthrough_endpoint_router.py +++ b/litellm/proxy/pass_through_endpoints/passthrough_endpoint_router.py @@ -49,12 +49,14 @@ class PassthroughEndpointRouter: custom_llm_provider=custom_llm_provider, region_name=region_name, ) - verbose_router_logger.debug(f"Pass-through llm endpoints router, looking for credentials for {credential_name}") + verbose_router_logger.debug( + "Pass-through llm endpoints router, looking for credentials for %s", credential_name + ) if credential_name in self.credentials: - verbose_router_logger.debug(f"Found credentials for {credential_name}") + verbose_router_logger.debug("Found credentials for %s", credential_name) return self.credentials[credential_name] else: - verbose_router_logger.debug(f"No credentials found for {credential_name}, looking for env variable") + verbose_router_logger.debug("No credentials found for %s, looking for env variable", credential_name) _env_variable_name = self._get_default_env_variable_name_passthrough_endpoint( custom_llm_provider=custom_llm_provider, ) diff --git a/litellm/proxy/pass_through_endpoints/streaming_handler.py b/litellm/proxy/pass_through_endpoints/streaming_handler.py index 9a4a28c7678..b8fd6d757b5 100644 --- a/litellm/proxy/pass_through_endpoints/streaming_handler.py +++ b/litellm/proxy/pass_through_endpoints/streaming_handler.py @@ -89,7 +89,7 @@ class PassThroughStreamingHandler: yield chunk except Exception as e: - verbose_proxy_logger.error(f"Error in chunk_processor: {e}") + verbose_proxy_logger.error("Error in chunk_processor: %s", e) raise finally: # GeneratorExit (raised on client disconnect) is not caught by @@ -115,7 +115,7 @@ class PassThroughStreamingHandler: ) ) except Exception as e: - verbose_proxy_logger.error(f"Error scheduling chunk_processor logging: {e}") + verbose_proxy_logger.error("Error scheduling chunk_processor logging: %s", e) @staticmethod async def _route_streaming_logging_to_handler( @@ -165,7 +165,7 @@ class PassThroughStreamingHandler: **kwargs, ) except Exception as e: - verbose_proxy_logger.error(f"Error in _route_streaming_logging_to_handler: {e}") + verbose_proxy_logger.error("Error in _route_streaming_logging_to_handler: %s", e) @staticmethod def _build_passthrough_logging_result( diff --git a/litellm/proxy/policy_engine/attachment_registry.py b/litellm/proxy/policy_engine/attachment_registry.py index 797f72f7667..9bbe5405965 100644 --- a/litellm/proxy/policy_engine/attachment_registry.py +++ b/litellm/proxy/policy_engine/attachment_registry.py @@ -58,14 +58,14 @@ class AttachmentRegistry: try: attachment = self._parse_attachment(attachment_data) self._attachments.append(attachment) - verbose_proxy_logger.debug(f"Loaded attachment for policy: {attachment.policy}") + verbose_proxy_logger.debug("Loaded attachment for policy: %s", attachment.policy) except Exception as e: - verbose_proxy_logger.error(f"Error loading attachment: {e}") + verbose_proxy_logger.error("Error loading attachment: %s", e) raise ValueError(f"Invalid attachment: {e}") from e self._config_attachments = tuple(self._attachments) self._initialized = True - verbose_proxy_logger.info(f"Loaded {len(self._attachments)} policy attachments") + verbose_proxy_logger.info("Loaded %s policy attachments", len(self._attachments)) def _parse_attachment(self, attachment_data: dict[str, Any]) -> PolicyAttachment: """ @@ -123,9 +123,12 @@ class AttachmentRegistry: } ) verbose_proxy_logger.debug( - f"Attachment matched: policy={attachment.policy}, " - f"matched_via={matched_via}, " - f"context=(team={context.team_alias}, key={context.key_alias}, model={context.model})" + "Attachment matched: policy=%s, matched_via=%s, context=(team=%s, key=%s, model=%s)", + attachment.policy, + matched_via, + context.team_alias, + context.key_alias, + context.model, ) return results @@ -222,7 +225,7 @@ class AttachmentRegistry: """ self._attachments.append(attachment) self._initialized = True - verbose_proxy_logger.debug(f"Added attachment for policy: {attachment.policy}") + verbose_proxy_logger.debug("Added attachment for policy: %s", attachment.policy) def remove_attachments_for_policy(self, policy_name: str) -> int: """ @@ -238,7 +241,7 @@ class AttachmentRegistry: self._attachments = [a for a in self._attachments if a.policy != policy_name] removed_count = original_count - len(self._attachments) if removed_count > 0: - verbose_proxy_logger.debug(f"Removed {removed_count} attachment(s) for policy: {policy_name}") + verbose_proxy_logger.debug("Removed %s attachment(s) for policy: %s", removed_count, policy_name) return removed_count def remove_attachment_by_id(self, attachment_id: str) -> bool: @@ -317,7 +320,7 @@ class AttachmentRegistry: updated_by=created_attachment.updated_by, ) except Exception as e: - verbose_proxy_logger.exception(f"Error adding attachment to DB: {e}") + verbose_proxy_logger.exception("Error adding attachment to DB: %s", e) raise Exception(f"Error adding attachment to DB: {e}") async def delete_attachment_from_db( @@ -353,7 +356,7 @@ class AttachmentRegistry: return {"message": f"Attachment {attachment_id} deleted successfully"} except Exception as e: - verbose_proxy_logger.exception(f"Error deleting attachment from DB: {e}") + verbose_proxy_logger.exception("Error deleting attachment from DB: %s", e) raise Exception(f"Error deleting attachment from DB: {e}") async def get_attachment_by_id_from_db( @@ -393,7 +396,7 @@ class AttachmentRegistry: updated_by=attachment.updated_by, ) except Exception as e: - verbose_proxy_logger.exception(f"Error getting attachment from DB: {e}") + verbose_proxy_logger.exception("Error getting attachment from DB: %s", e) raise Exception(f"Error getting attachment from DB: {e}") async def get_all_attachments_from_db( @@ -431,7 +434,7 @@ class AttachmentRegistry: for a in attachments ] except Exception as e: - verbose_proxy_logger.exception(f"Error getting attachments from DB: {e}") + verbose_proxy_logger.exception("Error getting attachments from DB: %s", e) raise Exception(f"Error getting attachments from DB: {e}") async def sync_attachments_from_db( @@ -463,11 +466,12 @@ class AttachmentRegistry: self._initialized = True verbose_proxy_logger.info( - f"Synced {len(attachments)} attachments from DB to in-memory registry " - f"({len(self._config_attachments)} config-defined attachments preserved)" + "Synced %s attachments from DB to in-memory registry (%s config-defined attachments preserved)", + len(attachments), + len(self._config_attachments), ) except Exception as e: - verbose_proxy_logger.exception(f"Error syncing attachments from DB: {e}") + verbose_proxy_logger.exception("Error syncing attachments from DB: %s", e) raise Exception(f"Error syncing attachments from DB: {e}") diff --git a/litellm/proxy/policy_engine/condition_evaluator.py b/litellm/proxy/policy_engine/condition_evaluator.py index 02268fcd721..2f3a4fa8015 100644 --- a/litellm/proxy/policy_engine/condition_evaluator.py +++ b/litellm/proxy/policy_engine/condition_evaluator.py @@ -48,7 +48,9 @@ class ConditionEvaluator: condition=condition.model, model=context.model, ): - verbose_proxy_logger.debug(f"Condition failed: model={context.model} did not match {condition.model}") + verbose_proxy_logger.debug( + "Condition failed: model=%s did not match %s", context.model, condition.model + ) return False return True diff --git a/litellm/proxy/policy_engine/init_policies.py b/litellm/proxy/policy_engine/init_policies.py index 1facec0898f..c3016afbd6c 100644 --- a/litellm/proxy/policy_engine/init_policies.py +++ b/litellm/proxy/policy_engine/init_policies.py @@ -124,7 +124,7 @@ async def init_policies( Raises: ValueError: If fail_on_error is True and validation errors are found """ - verbose_proxy_logger.info(f"Initializing {len(policies_config)} policies...") + verbose_proxy_logger.info("Initializing %s policies...", len(policies_config)) # Print policies to console on startup _print_policies_on_startup(policies_config, policy_attachments_config) @@ -146,13 +146,13 @@ async def init_policies( if validation_result.errors: for error in validation_result.errors: verbose_proxy_logger.error( - f"Policy validation error in '{error.policy_name}': [{error.error_type}] {error.message}" + "Policy validation error in '%s': [%s] %s", error.policy_name, error.error_type, error.message ) if validation_result.warnings: for warning in validation_result.warnings: verbose_proxy_logger.warning( - f"Policy validation warning in '{warning.policy_name}': [{warning.error_type}] {warning.message}" + "Policy validation warning in '%s': [%s] %s", warning.policy_name, warning.error_type, warning.message ) # Fail if there are errors and fail_on_error is True @@ -165,18 +165,18 @@ async def init_policies( # Load policies into registry (even with warnings) try: policy_registry.load_policies(policies_config) - verbose_proxy_logger.info(f"Successfully loaded {len(policies_config)} policies") + verbose_proxy_logger.info("Successfully loaded %s policies", len(policies_config)) except Exception as e: - verbose_proxy_logger.error(f"Failed to load policies: {e}") + verbose_proxy_logger.error("Failed to load policies: %s", e) raise # Load attachments if provided if policy_attachments_config: try: attachment_registry.load_attachments(policy_attachments_config) - verbose_proxy_logger.info(f"Successfully loaded {len(policy_attachments_config)} policy attachments") + verbose_proxy_logger.info("Successfully loaded %s policy attachments", len(policy_attachments_config)) except Exception as e: - verbose_proxy_logger.error(f"Failed to load policy attachments: {e}") + verbose_proxy_logger.error("Failed to load policy attachments: %s", e) raise return validation_result diff --git a/litellm/proxy/policy_engine/pipeline_executor.py b/litellm/proxy/policy_engine/pipeline_executor.py index 983d2da124b..7feb5123093 100644 --- a/litellm/proxy/policy_engine/pipeline_executor.py +++ b/litellm/proxy/policy_engine/pipeline_executor.py @@ -92,7 +92,12 @@ class PipelineExecutor: step_results.append(step_result) verbose_proxy_logger.debug( - f"Pipeline '{policy_name}' step {i}: guardrail={step.guardrail}, outcome={outcome}, action={action}" + "Pipeline '%s' step %s: guardrail=%s, outcome=%s, action=%s", + policy_name, + i, + step.guardrail, + outcome, + action, ) # Forward modified data to next step if pass_data is True @@ -158,7 +163,7 @@ class PipelineExecutor: """ callback = PipelineExecutor.find_guardrail_callback(step.guardrail) if callback is None: - verbose_proxy_logger.warning(f"Pipeline: guardrail '{step.guardrail}' not found in callbacks") + verbose_proxy_logger.warning("Pipeline: guardrail '%s' not found in callbacks", step.guardrail) return ("error", None, f"Guardrail '{step.guardrail}' not found", None) try: @@ -205,7 +210,7 @@ class PipelineExecutor: error_msg = _extract_error_message(e) return ("fail", None, error_msg, e) else: - verbose_proxy_logger.error(f"Pipeline: unexpected error from guardrail '{step.guardrail}': {e}") + verbose_proxy_logger.error("Pipeline: unexpected error from guardrail '%s': %s", step.guardrail, e) return ("error", None, str(e), e) @staticmethod diff --git a/litellm/proxy/policy_engine/policy_endpoints.py b/litellm/proxy/policy_engine/policy_endpoints.py index 1d0fd67cfc8..9959c2302b5 100644 --- a/litellm/proxy/policy_engine/policy_endpoints.py +++ b/litellm/proxy/policy_engine/policy_endpoints.py @@ -142,7 +142,7 @@ async def list_policies(version_status: str | None = None): policies = db_policies + config_policies return PolicyListDBResponse(policies=policies, total_count=len(policies)) except Exception as e: - verbose_proxy_logger.exception(f"Error listing policies: {e}") + verbose_proxy_logger.exception("Error listing policies: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -201,7 +201,7 @@ async def create_policy( ) return result except Exception as e: - verbose_proxy_logger.exception(f"Error creating policy: {e}") + verbose_proxy_logger.exception("Error creating policy: %s", e) if "unique constraint" in str(e).lower(): raise HTTPException( status_code=400, @@ -236,7 +236,7 @@ async def list_policy_versions(policy_name: str): prisma_client=prisma_client, ) except Exception as e: - verbose_proxy_logger.exception(f"Error listing policy versions: {e}") + verbose_proxy_logger.exception("Error listing policy versions: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -269,7 +269,7 @@ async def create_policy_version( created_by=created_by, ) except Exception as e: - verbose_proxy_logger.exception(f"Error creating policy version: {e}") + verbose_proxy_logger.exception("Error creating policy version: %s", e) if "not found" in str(e).lower() or "no production" in str(e).lower(): raise HTTPException(status_code=404, detail=str(e)) raise HTTPException(status_code=500, detail=str(e)) @@ -308,7 +308,7 @@ async def update_policy_version_status( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error updating version status: {e}") + verbose_proxy_logger.exception("Error updating version status: %s", e) if "invalid status" in str(e).lower() or "only draft" in str(e).lower() or "cannot promote" in str(e).lower(): raise HTTPException(status_code=400, detail=str(e)) if "not found" in str(e).lower(): @@ -341,7 +341,7 @@ async def compare_policy_versions( prisma_client=prisma_client, ) except Exception as e: - verbose_proxy_logger.exception(f"Error comparing versions: {e}") + verbose_proxy_logger.exception("Error comparing versions: %s", e) if "not found" in str(e).lower(): raise HTTPException(status_code=404, detail=str(e)) raise HTTPException(status_code=500, detail=str(e)) @@ -367,7 +367,7 @@ async def delete_all_policy_versions(policy_name: str): prisma_client=prisma_client, ) except Exception as e: - verbose_proxy_logger.exception(f"Error deleting all versions: {e}") + verbose_proxy_logger.exception("Error deleting all versions: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -408,7 +408,7 @@ async def get_policy(policy_id: str): except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error getting policy: {e}") + verbose_proxy_logger.exception("Error getting policy: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -467,7 +467,7 @@ async def update_policy( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error updating policy: {e}") + verbose_proxy_logger.exception("Error updating policy: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -516,7 +516,7 @@ async def delete_policy(policy_id: str): except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error deleting policy: {e}") + verbose_proxy_logger.exception("Error deleting policy: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -577,7 +577,7 @@ async def get_resolved_guardrails(policy_id: str): except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: - verbose_proxy_logger.exception(f"Error resolving guardrails: {e}") + verbose_proxy_logger.exception("Error resolving guardrails: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -640,7 +640,7 @@ async def test_pipeline( ) return result.model_dump() except Exception as e: - verbose_proxy_logger.exception(f"Error testing pipeline: {e}") + verbose_proxy_logger.exception("Error testing pipeline: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -699,7 +699,7 @@ async def list_policy_attachments(): attachments = db_attachments + config_attachments return PolicyAttachmentListResponse(attachments=attachments, total_count=len(attachments)) except Exception as e: - verbose_proxy_logger.exception(f"Error listing policy attachments: {e}") + verbose_proxy_logger.exception("Error listing policy attachments: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -791,7 +791,7 @@ async def create_policy_attachment( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error creating policy attachment: {e}") + verbose_proxy_logger.exception("Error creating policy attachment: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -830,7 +830,7 @@ async def get_policy_attachment(attachment_id: str): except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error getting policy attachment: {e}") + verbose_proxy_logger.exception("Error getting policy attachment: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -881,5 +881,5 @@ async def delete_policy_attachment(attachment_id: str): except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error deleting policy attachment: {e}") + verbose_proxy_logger.exception("Error deleting policy attachment: %s", e) raise HTTPException(status_code=500, detail=str(e)) diff --git a/litellm/proxy/policy_engine/policy_registry.py b/litellm/proxy/policy_engine/policy_registry.py index 07a4c2abac6..6031f4a372e 100644 --- a/litellm/proxy/policy_engine/policy_registry.py +++ b/litellm/proxy/policy_engine/policy_registry.py @@ -185,15 +185,15 @@ class PolicyRegistry: try: policy = self._parse_policy(policy_name, policy_data) self._policies[policy_name] = policy - verbose_proxy_logger.debug(f"Loaded policy: {policy_name}") + verbose_proxy_logger.debug("Loaded policy: %s", policy_name) except Exception as e: - verbose_proxy_logger.error(f"Error loading policy '{policy_name}': {e}") + verbose_proxy_logger.error("Error loading policy '%s': %s", policy_name, e) raise ValueError(f"Invalid policy '{policy_name}': {e}") from e self._config_policies = dict(self._policies) self._sources = {policy_name: "config" for policy_name in self._policies} self._initialized = True - verbose_proxy_logger.info(f"Loaded {len(self._policies)} policies") + verbose_proxy_logger.info("Loaded %s policies", len(self._policies)) def _parse_policy(self, policy_name: str, policy_data: dict[str, Any]) -> Policy: """ @@ -336,7 +336,7 @@ class PolicyRegistry: if source == "config": self._config_policies = {**self._config_policies, policy_name: policy} self._initialized = True - verbose_proxy_logger.debug(f"Added/updated policy: {policy_name}") + verbose_proxy_logger.debug("Added/updated policy: %s", policy_name) def remove_policy(self, policy_name: str) -> bool: """ @@ -355,11 +355,11 @@ class PolicyRegistry: if config_fallback is not None: self._policies[policy_name] = config_fallback self._sources = {**self._sources, policy_name: "config"} - verbose_proxy_logger.debug(f"Removed policy: {policy_name}; restored config-defined version") + verbose_proxy_logger.debug("Removed policy: %s; restored config-defined version", policy_name) return True del self._policies[policy_name] self._sources = {name: source for name, source in self._sources.items() if name != policy_name} - verbose_proxy_logger.debug(f"Removed policy: {policy_name}") + verbose_proxy_logger.debug("Removed policy: %s", policy_name) return True # ───────────────────────────────────────────────────────────────────────── @@ -432,7 +432,7 @@ class PolicyRegistry: return _row_to_policy_db_response(created_policy) except Exception as e: - verbose_proxy_logger.exception(f"Error adding policy to DB: {e}") + verbose_proxy_logger.exception("Error adding policy to DB: %s", e) raise Exception(f"Error adding policy to DB: {e}") async def update_policy_in_db( @@ -496,7 +496,7 @@ class PolicyRegistry: return _row_to_policy_db_response(updated_policy) except Exception as e: - verbose_proxy_logger.exception(f"Error updating policy in DB: {e}") + verbose_proxy_logger.exception("Error updating policy in DB: %s", e) raise Exception(f"Error updating policy in DB: {e}") async def delete_policy_from_db( @@ -546,7 +546,7 @@ class PolicyRegistry: return result except Exception as e: - verbose_proxy_logger.exception(f"Error deleting policy from DB: {e}") + verbose_proxy_logger.exception("Error deleting policy from DB: %s", e) raise Exception(f"Error deleting policy from DB: {e}") async def get_policy_by_id_from_db( @@ -572,7 +572,7 @@ class PolicyRegistry: return _row_to_policy_db_response(policy) except Exception as e: - verbose_proxy_logger.exception(f"Error getting policy from DB: {e}") + verbose_proxy_logger.exception("Error getting policy from DB: %s", e) raise Exception(f"Error getting policy from DB: {e}") def get_policy_by_id_for_request(self, policy_id: str) -> tuple[str, Policy] | None: @@ -619,7 +619,7 @@ class PolicyRegistry: return [_row_to_policy_db_response(p) for p in policies] except Exception as e: - verbose_proxy_logger.exception(f"Error getting policies from DB: {e}") + verbose_proxy_logger.exception("Error getting policies from DB: %s", e) raise Exception(f"Error getting policies from DB: {e}") async def sync_policies_from_db( @@ -653,7 +653,8 @@ class PolicyRegistry: } for policy_name in set(db_policies) & set(self._config_policies): verbose_proxy_logger.warning( - f"Policy '{policy_name}' is defined in both config.yaml and the DB; the DB version takes precedence" + "Policy '%s' is defined in both config.yaml and the DB; the DB version takes precedence", + policy_name, ) config_sources: Mapping[str, Literal["db", "config"]] = {name: "config" for name in self._config_policies} db_sources: Mapping[str, Literal["db", "config"]] = {name: "db" for name in db_policies} @@ -683,12 +684,13 @@ class PolicyRegistry: self._initialized = True verbose_proxy_logger.info( - f"Synced {len(production)} production policies and {len(non_production)} " - "draft/published (by ID) from DB to in-memory registry " - f"({len(self._config_policies)} config-defined policies preserved)" + "Synced %s production policies and %s draft/published (by ID) from DB to in-memory registry (%s config-defined policies preserved)", + len(production), + len(non_production), + len(self._config_policies), ) except Exception as e: - verbose_proxy_logger.exception(f"Error syncing policies from DB: {e}") + verbose_proxy_logger.exception("Error syncing policies from DB: %s", e) raise Exception(f"Error syncing policies from DB: {e}") async def resolve_guardrails_from_db( @@ -741,7 +743,7 @@ class PolicyRegistry: return sorted(resolved_policy.guardrails) except Exception as e: - verbose_proxy_logger.exception(f"Error resolving guardrails from DB: {e}") + verbose_proxy_logger.exception("Error resolving guardrails from DB: %s", e) raise Exception(f"Error resolving guardrails from DB: {e}") async def get_versions_by_policy_name( @@ -771,7 +773,7 @@ class PolicyRegistry: total_count=len(versions), ) except Exception as e: - verbose_proxy_logger.exception(f"Error getting versions: {e}") + verbose_proxy_logger.exception("Error getting versions: %s", e) raise Exception(f"Error getting versions: {e}") async def create_new_version( @@ -857,7 +859,7 @@ class PolicyRegistry: created = await _policy_table(prisma_client).create(data=data) return _row_to_policy_db_response(created) except Exception as e: - verbose_proxy_logger.exception(f"Error creating new version: {e}") + verbose_proxy_logger.exception("Error creating new version: %s", e) raise Exception(f"Error creating new version: {e}") async def update_version_status( @@ -962,7 +964,7 @@ class PolicyRegistry: return _row_to_policy_db_response(updated) except Exception as e: - verbose_proxy_logger.exception(f"Error updating version status: {e}") + verbose_proxy_logger.exception("Error updating version status: %s", e) raise Exception(f"Error updating version status: {e}") async def compare_versions( @@ -1015,7 +1017,7 @@ class PolicyRegistry: field_diffs=field_diffs, ) except Exception as e: - verbose_proxy_logger.exception(f"Error comparing versions: {e}") + verbose_proxy_logger.exception("Error comparing versions: %s", e) raise Exception(f"Error comparing versions: {e}") async def delete_all_versions( @@ -1046,7 +1048,7 @@ class PolicyRegistry: } return {"message": message} except Exception as e: - verbose_proxy_logger.exception(f"Error deleting all versions: {e}") + verbose_proxy_logger.exception("Error deleting all versions: %s", e) raise Exception(f"Error deleting all versions: {e}") diff --git a/litellm/proxy/policy_engine/policy_resolve_endpoints.py b/litellm/proxy/policy_engine/policy_resolve_endpoints.py index e5c2693cf21..575a9cbacc2 100644 --- a/litellm/proxy/policy_engine/policy_resolve_endpoints.py +++ b/litellm/proxy/policy_engine/policy_resolve_endpoints.py @@ -298,7 +298,7 @@ async def resolve_policies_for_context( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error resolving policies: {e}") + verbose_proxy_logger.exception("Error resolving policies: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -408,5 +408,5 @@ async def estimate_attachment_impact( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error estimating attachment impact: {e}") + verbose_proxy_logger.exception("Error estimating attachment impact: %s", e) raise HTTPException(status_code=500, detail=str(e)) diff --git a/litellm/proxy/policy_engine/policy_resolver.py b/litellm/proxy/policy_engine/policy_resolver.py index 65c8236a0b3..355bc10c003 100644 --- a/litellm/proxy/policy_engine/policy_resolver.py +++ b/litellm/proxy/policy_engine/policy_resolver.py @@ -47,7 +47,7 @@ class PolicyResolver: visited = set() if policy_name in visited: - verbose_proxy_logger.warning(f"Circular inheritance detected for policy '{policy_name}'") + verbose_proxy_logger.warning("Circular inheritance detected for policy '%s'", policy_name) return [] policy = policies.get(policy_name) @@ -106,7 +106,7 @@ class PolicyResolver: context=context, ): verbose_proxy_logger.debug( - f"Policy '{chain_policy_name}' condition did not match, skipping guardrails" + "Policy '%s' condition did not match, skipping guardrails", chain_policy_name ) continue @@ -163,8 +163,10 @@ class PolicyResolver: if not matching_policy_names: verbose_proxy_logger.debug( - f"No policies match context: team_alias={context.team_alias}, " - f"key_alias={context.key_alias}, model={context.model}" + "No policies match context: team_alias=%s, key_alias=%s, model=%s", + context.team_alias, + context.key_alias, + context.model, ) return [] @@ -178,10 +180,10 @@ class PolicyResolver: context=context, ) all_guardrails.update(resolved.guardrails) - verbose_proxy_logger.debug(f"Policy '{policy_name}' contributes guardrails: {resolved.guardrails}") + verbose_proxy_logger.debug("Policy '%s' contributes guardrails: %s", policy_name, resolved.guardrails) result = list(all_guardrails) - verbose_proxy_logger.debug(f"Final guardrails for context: {result}") + verbose_proxy_logger.debug("Final guardrails for context: %s", result) return result @@ -229,7 +231,7 @@ class PolicyResolver: if policy.pipeline is not None: pipelines.append((policy_name, policy.pipeline)) verbose_proxy_logger.debug( - f"Policy '{policy_name}' has pipeline with {len(policy.pipeline.steps)} steps" + "Policy '%s' has pipeline with %s steps", policy_name, len(policy.pipeline.steps) ) return pipelines diff --git a/litellm/proxy/policy_engine/policy_validator.py b/litellm/proxy/policy_engine/policy_validator.py index 67f7b37472c..c8799a71307 100644 --- a/litellm/proxy/policy_engine/policy_validator.py +++ b/litellm/proxy/policy_engine/policy_validator.py @@ -78,7 +78,7 @@ class PolicyValidator: guardrails = IN_MEMORY_GUARDRAIL_HANDLER.list_in_memory_guardrails() return {g.get("guardrail_name", "") for g in guardrails if g.get("guardrail_name")} except Exception as e: - verbose_proxy_logger.warning(f"Could not get guardrails from registry: {e}") + verbose_proxy_logger.warning("Could not get guardrails from registry: %s", e) return set() async def check_team_alias_exists(self, team_alias: str) -> bool: @@ -100,7 +100,7 @@ class PolicyValidator: ) return team is not None except Exception as e: - verbose_proxy_logger.warning(f"Could not check team alias '{team_alias}': {e}") + verbose_proxy_logger.warning("Could not check team alias '%s': %s", team_alias, e) return True # Assume valid on error async def check_key_alias_exists(self, key_alias: str) -> bool: @@ -122,7 +122,7 @@ class PolicyValidator: ) return key is not None except Exception as e: - verbose_proxy_logger.warning(f"Could not check key alias '{key_alias}': {e}") + verbose_proxy_logger.warning("Could not check key alias '%s': %s", key_alias, e) return True # Assume valid on error def check_model_exists(self, model: str) -> bool: @@ -151,7 +151,7 @@ class PolicyValidator: return False except Exception as e: - verbose_proxy_logger.warning(f"Could not check model '{model}': {e}") + verbose_proxy_logger.warning("Could not check model '%s': %s", model, e) return True # Assume valid on error @staticmethod diff --git a/litellm/proxy/prisma_migration.py b/litellm/proxy/prisma_migration.py index 0f6944fac79..b09a49cbff5 100644 --- a/litellm/proxy/prisma_migration.py +++ b/litellm/proxy/prisma_migration.py @@ -16,9 +16,9 @@ run_server(["--skip_server_startup"], standalone_mode=False) # run prisma generate verbose_proxy_logger.info("Running 'prisma generate'...") result = subprocess.run(["prisma", "generate"], capture_output=True, text=True) -verbose_proxy_logger.info(f"'prisma generate' stdout: {result.stdout}") # Log stdout +verbose_proxy_logger.info("'prisma generate' stdout: %s", result.stdout) # Log stdout exit_code = result.returncode if exit_code != 0: - verbose_proxy_logger.info(f"'prisma generate' failed with exit code {exit_code}.") - verbose_proxy_logger.error(f"'prisma generate' stderr: {result.stderr}") # Log stderr + verbose_proxy_logger.info("'prisma generate' failed with exit code %s.", exit_code) + verbose_proxy_logger.error("'prisma generate' stderr: %s", result.stderr) # Log stderr diff --git a/litellm/proxy/prometheus_cleanup.py b/litellm/proxy/prometheus_cleanup.py index 2a22b1c5fae..7cf27193b9a 100644 --- a/litellm/proxy/prometheus_cleanup.py +++ b/litellm/proxy/prometheus_cleanup.py @@ -21,9 +21,9 @@ def wipe_directory(directory: str) -> None: os.remove(filepath) deleted += 1 except OSError as e: - verbose_proxy_logger.warning(f"Failed to delete stale prometheus file {filepath}: {e}") + verbose_proxy_logger.warning("Failed to delete stale prometheus file %s: %s", filepath, e) if deleted: - verbose_proxy_logger.info(f"Prometheus cleanup: wiped {deleted} stale .db files from {directory}") + verbose_proxy_logger.info("Prometheus cleanup: wiped %s stale .db files from %s", deleted, directory) def mark_worker_exit(worker_pid: int) -> None: @@ -34,6 +34,6 @@ def mark_worker_exit(worker_pid: int) -> None: from prometheus_client import multiprocess multiprocess.mark_process_dead(worker_pid) - verbose_proxy_logger.info(f"Prometheus cleanup: marked worker {worker_pid} as dead") + verbose_proxy_logger.info("Prometheus cleanup: marked worker %s as dead", worker_pid) except Exception as e: - verbose_proxy_logger.warning(f"Failed to mark prometheus worker {worker_pid} as dead: {e}") + verbose_proxy_logger.warning("Failed to mark prometheus worker %s as dead: %s", worker_pid, e) diff --git a/litellm/proxy/prompts/init_prompts.py b/litellm/proxy/prompts/init_prompts.py index 67e961b2da8..752762f07b9 100644 --- a/litellm/proxy/prompts/init_prompts.py +++ b/litellm/proxy/prompts/init_prompts.py @@ -23,4 +23,4 @@ def init_prompts( if initialized_prompt: prompt_list.append(initialized_prompt) - verbose_proxy_logger.debug(f"\nPrompt List:{prompt_list}\n") + verbose_proxy_logger.debug("\nPrompt List:%s\n", prompt_list) diff --git a/litellm/proxy/prompts/prompt_endpoints.py b/litellm/proxy/prompts/prompt_endpoints.py index 89087a3fdd5..fd0437a4265 100644 --- a/litellm/proxy/prompts/prompt_endpoints.py +++ b/litellm/proxy/prompts/prompt_endpoints.py @@ -755,7 +755,7 @@ async def create_prompt( return initialized_prompt except Exception as e: - verbose_proxy_logger.exception(f"Error creating prompt: {e}") + verbose_proxy_logger.exception("Error creating prompt: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -871,7 +871,7 @@ async def update_prompt( except HTTPException as e: raise e except Exception as e: - verbose_proxy_logger.exception(f"Error updating prompt: {e}") + verbose_proxy_logger.exception("Error updating prompt: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -970,7 +970,7 @@ async def delete_prompt( except HTTPException as e: raise e except Exception as e: - verbose_proxy_logger.exception(f"Error deleting prompt: {e}") + verbose_proxy_logger.exception("Error deleting prompt: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -1111,7 +1111,7 @@ async def patch_prompt( except HTTPException as e: raise e except Exception as e: - verbose_proxy_logger.exception(f"Error patching prompt: {e}") + verbose_proxy_logger.exception("Error patching prompt: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -1252,7 +1252,7 @@ async def test_prompt( except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: - verbose_proxy_logger.exception(f"Error testing prompt: {e}") + verbose_proxy_logger.exception("Error testing prompt: %s", e) raise HTTPException(status_code=500, detail=str(e)) diff --git a/litellm/proxy/prompts/prompt_registry.py b/litellm/proxy/prompts/prompt_registry.py index 9e00d4e7c63..78b449873a8 100644 --- a/litellm/proxy/prompts/prompt_registry.py +++ b/litellm/proxy/prompts/prompt_registry.py @@ -51,7 +51,7 @@ def get_prompt_initializer_from_integrations(): module_path = f"litellm.integrations.{item}" try: # Import the module - verbose_proxy_logger.debug(f"Discovering prompt integrations in: {module_path}") + verbose_proxy_logger.debug("Discovering prompt integrations in: %s", module_path) module = importlib.import_module(module_path) @@ -61,22 +61,22 @@ def get_prompt_initializer_from_integrations(): if isinstance(registry, dict): discovered_initializers.update(registry) verbose_proxy_logger.debug( - f"Found prompt_initializer_registry in {module_path}: {list(registry.keys())}" + "Found prompt_initializer_registry in %s: %s", module_path, list(registry.keys()) ) except ImportError as e: - verbose_proxy_logger.error(f"Could not import {module_path}: {e}") + verbose_proxy_logger.error("Could not import %s: %s", module_path, e) continue except Exception as e: - verbose_proxy_logger.error(f"Error processing {module_path}: {e}") + verbose_proxy_logger.error("Error processing %s: %s", module_path, e) continue verbose_proxy_logger.debug( - f"Discovered {len(discovered_initializers)} prompt initializers: {list(discovered_initializers.keys())}" + "Discovered %s prompt initializers: %s", len(discovered_initializers), list(discovered_initializers.keys()) ) except Exception as e: - verbose_proxy_logger.error(f"Error discovering prompt initializers: {e}") + verbose_proxy_logger.error("Error discovering prompt initializers: %s", e) return discovered_initializers diff --git a/litellm/proxy/proxy_cli.py b/litellm/proxy/proxy_cli.py index 58b4ec88192..82cbb7fda48 100644 --- a/litellm/proxy/proxy_cli.py +++ b/litellm/proxy/proxy_cli.py @@ -163,8 +163,8 @@ def _with_query_value(url: str, key: str, value: str) -> str: def append_query_params(url: str | None, params: dict) -> str: from litellm._logging import verbose_proxy_logger - verbose_proxy_logger.debug(f"url: {url}") - verbose_proxy_logger.debug(f"params: {params}") + verbose_proxy_logger.debug("url: %s", url) + verbose_proxy_logger.debug("params: %s", params) if not isinstance(url, str) or url == "": # Preserve previous startup behavior when DATABASE_URL is absent. # Returning an empty string avoids urlparse type errors in test/dev flows. diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index ac45898ce0b..d53ffd528ba 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -855,12 +855,16 @@ async def _initialize_shared_aiohttp_session(): session = ClientSession(connector=connector) verbose_proxy_logger.info( - f"SESSION REUSE: Created shared aiohttp session for connection pooling (ID: {id(session)}, " - f"limit={AIOHTTP_CONNECTOR_LIMIT}, limit_per_host={AIOHTTP_CONNECTOR_LIMIT_PER_HOST})" + "SESSION REUSE: Created shared aiohttp session for connection pooling (ID: %s, limit=%s, limit_per_host=%s)", + id(session), + AIOHTTP_CONNECTOR_LIMIT, + AIOHTTP_CONNECTOR_LIMIT_PER_HOST, ) return session except Exception as e: - verbose_proxy_logger.warning(f"Failed to create shared aiohttp session: {e}. Continuing without session reuse.") + verbose_proxy_logger.warning( + "Failed to create shared aiohttp session: %s. Continuing without session reuse.", e + ) return None @@ -911,7 +915,7 @@ async def proxy_startup_event(app: FastAPI): raise ## CHECK PREMIUM USER - verbose_proxy_logger.debug(f"litellm.proxy.proxy_server.py::startup() - CHECKING PREMIUM USER - {premium_user}") + verbose_proxy_logger.debug("litellm.proxy.proxy_server.py::startup() - CHECKING PREMIUM USER - %s", premium_user) if premium_user is False: premium_user = _license_check.is_premium() @@ -966,9 +970,9 @@ async def proxy_startup_event(app: FastAPI): async def _run_pw_migration(): try: result = await migrate_passwords_to_scrypt_async(prisma_client) - verbose_proxy_logger.info(f"Password migration: {result}") + verbose_proxy_logger.info("Password migration: %s", result) except Exception as e: - verbose_proxy_logger.warning(f"Password migration skipped: {e}") + verbose_proxy_logger.warning("Password migration skipped: %s", e) asyncio.create_task(_run_pw_migration()) @@ -1042,14 +1046,14 @@ async def proxy_startup_event(app: FastAPI): verbose_proxy_logger.debug("About to initialize semantic tool filter") _config = proxy_config.get_config_state() _litellm_settings = _config.get("litellm_settings", {}) - verbose_proxy_logger.debug(f"litellm_settings keys = {list(_litellm_settings.keys())}") + verbose_proxy_logger.debug("litellm_settings keys = %s", list(_litellm_settings.keys())) await ProxyStartupEvent._initialize_semantic_tool_filter( llm_router=llm_router, litellm_settings=_litellm_settings, ) verbose_proxy_logger.debug("After semantic tool filter initialization") except Exception as e: - verbose_proxy_logger.error(f"Semantic filter init failed: {e}", exc_info=True) + verbose_proxy_logger.error("Semantic filter init failed: %s", e, exc_info=True) ## JWT AUTH ## ProxyStartupEvent._initialize_jwt_auth( @@ -1126,7 +1130,7 @@ async def proxy_startup_event(app: FastAPI): await shared_aiohttp_session.close() verbose_proxy_logger.info("SESSION REUSE: Closed shared aiohttp session") except Exception as e: - verbose_proxy_logger.error(f"Error closing shared aiohttp session: {e}") + verbose_proxy_logger.error("Error closing shared aiohttp session: %s", e) # Shutdown event - stop RDS IAM token refresh background task if ( @@ -1137,14 +1141,14 @@ async def proxy_startup_event(app: FastAPI): try: await prisma_client.db.stop_token_refresh_task() except Exception as e: - verbose_proxy_logger.error(f"Error stopping token refresh task: {e}") + verbose_proxy_logger.error("Error stopping token refresh task: %s", e) # Shutdown event - stop Prisma DB health watchdog task if prisma_client is not None and hasattr(prisma_client, "stop_db_health_watchdog_task"): try: await prisma_client.stop_db_health_watchdog_task() except Exception as e: - verbose_proxy_logger.error(f"Error stopping DB health watchdog task: {e}") + verbose_proxy_logger.error("Error stopping DB health watchdog task: %s", e) await proxy_config.stop_config_sync_subscriber() @@ -1591,7 +1595,7 @@ try: # Primary signal: marker file created by Dockerfile marker_file = os.path.join(ui_dir, ".litellm_ui_ready") if os.path.exists(marker_file): - verbose_proxy_logger.debug(f"Found UI ready marker: {marker_file}") + verbose_proxy_logger.debug("Found UI ready marker: %s", marker_file) return True # Fallback signal: Detect restructuring pattern @@ -1610,11 +1614,11 @@ try: if os.path.exists(index_path): # Found at least one restructured route - this proves the pattern verbose_proxy_logger.debug( - f"Detected restructured UI via pattern: found {entry.name}/index.html" + "Detected restructured UI via pattern: found %s/index.html", entry.name ) return True except (PermissionError, OSError) as e: - verbose_proxy_logger.debug(f"Could not scan {ui_dir} for restructuring detection: {e}") + verbose_proxy_logger.debug("Could not scan %s for restructuring detection: %s", ui_dir, e) return False # No restructured routes found @@ -1634,7 +1638,7 @@ try: target_path, dirs_exist_ok=True, ) - verbose_proxy_logger.info(f"Successfully populated UI at {target_path}") + verbose_proxy_logger.info("Successfully populated UI at %s", target_path) return True, "" else: return False, "Source or target directory state invalid" @@ -1658,7 +1662,7 @@ try: # Validate packaged UI before proceeding if not _validate_ui_directory(packaged_ui_path): verbose_proxy_logger.error( - f"Packaged UI at {packaged_ui_path} is invalid or incomplete. UI may not function correctly." + "Packaged UI at %s is invalid or incomplete. UI may not function correctly.", packaged_ui_path ) # Decision tree for UI path selection: @@ -1677,20 +1681,20 @@ try: # Case 2: Runtime UI exists and is ready if has_content and is_pre_restructured: - verbose_proxy_logger.info(f"Using pre-restructured UI at {runtime_ui_path}") + verbose_proxy_logger.info("Using pre-restructured UI at %s", runtime_ui_path) ui_path = runtime_ui_path # Case 3: Runtime UI exists but needs restructuring elif has_content and not is_pre_restructured: verbose_proxy_logger.warning( - f"UI at {runtime_ui_path} has content but is not properly restructured. " - f"Will attempt to restructure in place." + "UI at %s has content but is not properly restructured. Will attempt to restructure in place.", + runtime_ui_path, ) ui_path = runtime_ui_path # Case 4: Runtime UI missing - try to populate else: - verbose_proxy_logger.info(f"UI not found at {runtime_ui_path}. Attempting to populate from packaged UI.") + verbose_proxy_logger.info("UI not found at %s. Attempting to populate from packaged UI.", runtime_ui_path) success, error = _try_populate_ui_directory(packaged_ui_path, runtime_ui_path) @@ -1700,20 +1704,20 @@ try: else: # Case 4b: Population failed - fall back to packaged UI verbose_proxy_logger.warning( - f"Failed to populate UI at {runtime_ui_path}: {error}. " - f"Falling back to packaged UI at {packaged_ui_path}. " - f"For read-only deployments, pre-build UI in Dockerfile " - f"or set LITELLM_UI_PATH to a writable emptyDir volume." + "Failed to populate UI at %s: %s. Falling back to packaged UI at %s. For read-only deployments, pre-build UI in Dockerfile or set LITELLM_UI_PATH to a writable emptyDir volume.", + runtime_ui_path, + error, + packaged_ui_path, ) ui_path = packaged_ui_path else: # Case 1: Using packaged UI directly (local development) - verbose_proxy_logger.info(f"Using packaged UI directory: {packaged_ui_path}") + verbose_proxy_logger.info("Using packaged UI directory: %s", packaged_ui_path) ui_path = packaged_ui_path # Validate final UI path if not _validate_ui_directory(ui_path): - verbose_proxy_logger.error(f"Selected UI path {ui_path} is invalid or incomplete. UI may not work correctly.") + verbose_proxy_logger.error("Selected UI path %s is invalid or incomplete. UI may not work correctly.", ui_path) # Only modify files if a custom server root path is set AND filesystem is writable if server_root_path and server_root_path != "/": @@ -1722,9 +1726,8 @@ try: if not is_writable: verbose_proxy_logger.warning( - f"Cannot apply server_root_path replacements to UI at {ui_path}: " - f"path is not writable. Ensure server_root_path is '/' or pre-process " - f"UI files in Dockerfile with custom server_root_path." + "Cannot apply server_root_path replacements to UI at %s: path is not writable. Ensure server_root_path is '/' or pre-process UI files in Dockerfile with custom server_root_path.", + ui_path, ) else: # Iterate through files in the UI directory @@ -1818,20 +1821,19 @@ try: is_writable = os.access(ui_path, os.W_OK) if is_pre_restructured: - verbose_proxy_logger.info(f"Skipping UI restructuring: {ui_path} is already pre-restructured") + verbose_proxy_logger.info("Skipping UI restructuring: %s is already pre-restructured", ui_path) elif not is_writable: verbose_proxy_logger.warning( - f"Cannot restructure UI at {ui_path}: path is not writable. " - f"UI may not work correctly for extensionless routes. " - f"Pre-build and restructure UI in Dockerfile for read-only deployments." + "Cannot restructure UI at %s: path is not writable. UI may not work correctly for extensionless routes. Pre-build and restructure UI in Dockerfile for read-only deployments.", + ui_path, ) else: _restructure_ui_html_files(ui_path) - verbose_proxy_logger.info(f"Restructured UI directory: {ui_path}") + verbose_proxy_logger.info("Restructured UI directory: %s", ui_path) except PermissionError as e: - verbose_proxy_logger.exception(f"Permission error while restructuring UI directory {ui_path}: {e}") + verbose_proxy_logger.exception("Permission error while restructuring UI directory %s: %s", ui_path, e) except Exception as e: - verbose_proxy_logger.exception(f"Error while restructuring UI directory {ui_path}: {e}") + verbose_proxy_logger.exception("Error while restructuring UI directory %s: %s", ui_path, e) except Exception: pass @@ -2819,7 +2821,7 @@ async def update_cache( hashed_token = token verbose_proxy_logger.debug("_update_key_cache: hashed_token=%s", hashed_token) existing_spend_obj = await user_api_key_cache.async_get_cache(key=hashed_token, model_type=UserAPIKeyAuth) - verbose_proxy_logger.debug(f"_update_key_cache: existing_spend_obj={existing_spend_obj}") + verbose_proxy_logger.debug("_update_key_cache: existing_spend_obj=%s", existing_spend_obj) if existing_spend_obj is None: return @@ -2882,7 +2884,7 @@ async def update_cache( if existing_spend_obj is None: return verbose_proxy_logger.debug( - f"_update_user_db: existing spend: {existing_spend_obj}; response_cost: {response_cost}" + "_update_user_db: existing spend: %s; response_cost: %s", existing_spend_obj, response_cost ) existing_spend = existing_spend_obj.spend or 0.0 @@ -2932,7 +2934,7 @@ async def update_cache( if existing_spend_obj is None: return verbose_proxy_logger.debug( - f"_update_end_user_db: existing spend: {existing_spend_obj}; response_cost: {response_cost}" + "_update_end_user_db: existing spend: %s; response_cost: %s", existing_spend_obj, response_cost ) existing_spend = existing_spend_obj.spend or 0.0 @@ -2974,7 +2976,7 @@ async def update_cache( if existing_spend_obj is None: return verbose_proxy_logger.debug( - f"_update_team_db: existing spend: {existing_spend_obj}; response_cost: {response_cost}" + "_update_team_db: existing spend: %s; response_cost: %s", existing_spend_obj, response_cost ) existing_spend: float = existing_spend_obj.spend or 0.0 @@ -3024,7 +3026,10 @@ async def update_cache( continue verbose_proxy_logger.debug( - f"_update_tag_cache: existing spend for tag={tag_name}: {existing_tag_obj}; response_cost: {response_cost}" + "_update_tag_cache: existing spend for tag=%s: %s; response_cost: %s", + tag_name, + existing_tag_obj, + response_cost, ) existing_spend = existing_tag_obj.spend or 0.0 @@ -3094,9 +3099,10 @@ def run_ollama_serve(): with open(os.devnull, "w") as devnull: subprocess.Popen(command, stdout=devnull, stderr=devnull) except Exception as e: - verbose_proxy_logger.debug(f""" - LiteLLM Warning: proxy started with `ollama` model\n`ollama serve` failed with Exception{e}. \nEnsure you run `ollama serve` - """) + verbose_proxy_logger.debug( + "\n LiteLLM Warning: proxy started with `ollama` model\n`ollama serve` failed with Exception%s. \nEnsure you run `ollama serve`\n ", + e, + ) def _get_process_rss_mb() -> float | None: @@ -4018,7 +4024,7 @@ class ProxyConfig: dict: Processed configuration dictionary. """ if depth > max_depth: - verbose_proxy_logger.warning(f"Maximum recursion depth ({max_depth}) reached while processing config.") + verbose_proxy_logger.warning("Maximum recursion depth (%s) reached while processing config.", max_depth) return config for key, value in config.items(): @@ -4222,7 +4228,9 @@ class ProxyConfig: return copy.deepcopy(self.config) except Exception as e: verbose_proxy_logger.debug( - f"ProxyConfig:get_config_state(): Error returning copy of config state. self.config={self.config}\nError: {e}" + "ProxyConfig:get_config_state(): Error returning copy of config state. self.config=%s\nError: %s", + self.config, + e, ) return {} @@ -4286,7 +4294,7 @@ class ProxyConfig: search_tool_typed: SearchToolTypedDict = SearchToolTypedDict(**search_tool) # type: ignore search_tools_parsed.append(search_tool_typed) except Exception as e: - verbose_proxy_logger.error(f"Error parsing search tool {search_tool_name}: {e}") + verbose_proxy_logger.error("Error parsing search tool %s: %s", search_tool_name, e) continue return search_tools_parsed if search_tools_parsed else None @@ -4476,7 +4484,7 @@ class ProxyConfig: ) ) if litellm.cache is not None: - verbose_proxy_logger.debug(f"{blue_color_code}Set Cache on LiteLLM Proxy{reset_color_code}") + verbose_proxy_logger.debug("%sSet Cache on LiteLLM Proxy%s", blue_color_code, reset_color_code) elif key == "cache" and value is False: pass elif key == "guardrails": @@ -4496,7 +4504,7 @@ class ProxyConfig: set_global_prompt_directory(value) verbose_proxy_logger.info( - f"{blue_color_code}Set Global Prompt Directory on LiteLLM Proxy{reset_color_code}" + "%sSet Global Prompt Directory on LiteLLM Proxy%s", blue_color_code, reset_color_code ) elif key == "global_bitbucket_config": from litellm.integrations.bitbucket import ( @@ -4505,14 +4513,14 @@ class ProxyConfig: set_global_bitbucket_config(value) verbose_proxy_logger.info( - f"{blue_color_code}Set Global BitBucket Config on LiteLLM Proxy{reset_color_code}" + "%sSet Global BitBucket Config on LiteLLM Proxy%s", blue_color_code, reset_color_code ) elif key == "global_gitlab_config": from litellm.integrations.gitlab import set_global_gitlab_config set_global_gitlab_config(value) verbose_proxy_logger.info( - f"{blue_color_code}Set Global Gitlab Config on LiteLLM Proxy{reset_color_code}" + "%sSet Global Gitlab Config on LiteLLM Proxy%s", blue_color_code, reset_color_code ) elif key == "priority_reservation_settings": from litellm.types.utils import PriorityReservationSettings @@ -4534,7 +4542,7 @@ class ProxyConfig: elif key == "post_call_rules": litellm.post_call_rules = [get_instance_fn(value=value, config_file_path=config_file_path)] - verbose_proxy_logger.debug(f"litellm.post_call_rules: {litellm.post_call_rules}") + verbose_proxy_logger.debug("litellm.post_call_rules: %s", litellm.post_call_rules) elif key == "max_budget": litellm.max_budget = float(value) elif key == "max_internal_user_budget": @@ -4550,7 +4558,11 @@ class ProxyConfig: else value ) verbose_proxy_logger.debug( - f"{blue_color_code} setting litellm.{key}={_redact_general_setting_value(key, litellm.default_internal_user_params, is_full_admin=False)}{reset_color_code}" + "%s setting litellm.%s=%s%s", + blue_color_code, + key, + _redact_general_setting_value(key, litellm.default_internal_user_params, is_full_admin=False), + reset_color_code, ) elif key == "custom_provider_map": from litellm.utils import custom_llm_setup @@ -4654,12 +4666,20 @@ class ProxyConfig: native_background_mode = background_mode.get("native_background_mode", []) polling_cache_ttl = background_mode.get("ttl", 3600) verbose_proxy_logger.debug( - f"{blue_color_code} Initialized polling via cache: enabled={polling_via_cache_enabled}, native_background_mode={native_background_mode}, ttl={polling_cache_ttl}{reset_color_code}" + "%s Initialized polling via cache: enabled=%s, native_background_mode=%s, ttl=%s%s", + blue_color_code, + polling_via_cache_enabled, + native_background_mode, + polling_cache_ttl, + reset_color_code, ) elif key == "max_ui_session_budget": litellm.max_ui_session_budget = float(value) if value is not None else None verbose_proxy_logger.debug( - f"{blue_color_code} setting litellm.max_ui_session_budget={litellm.max_ui_session_budget}{reset_color_code}" + "%s setting litellm.max_ui_session_budget=%s%s", + blue_color_code, + litellm.max_ui_session_budget, + reset_color_code, ) elif key == "default_team_settings": for idx, team_setting in enumerate(value): # run through pydantic validation @@ -4674,7 +4694,11 @@ class ProxyConfig: f"team_id missing from default_team_settings at index={idx}\npassed in value={type(team_setting)}" ) verbose_proxy_logger.debug( - f"{blue_color_code} setting litellm.{key}={_redact_general_setting_value(key, value, is_full_admin=False)}{reset_color_code}" + "%s setting litellm.%s=%s%s", + blue_color_code, + key, + _redact_general_setting_value(key, value, is_full_admin=False), + reset_color_code, ) setattr(litellm, key, value) elif key == "upperbound_key_generate_params": @@ -4688,7 +4712,9 @@ class ProxyConfig: elif key == "json_logs" and value is True: litellm.json_logs = True litellm._turn_on_json() - verbose_proxy_logger.debug(f"{blue_color_code} Enabled JSON logging via config{reset_color_code}") + verbose_proxy_logger.debug( + "%s Enabled JSON logging via config%s", blue_color_code, reset_color_code + ) elif key == "budget_reset_time": from litellm.proxy.common_utils.timezone_utils import ( parse_budget_reset_time, @@ -4698,7 +4724,11 @@ class ProxyConfig: setattr(litellm, key, value) else: verbose_proxy_logger.debug( - f"{blue_color_code} setting litellm.{key}={_redact_general_setting_value(key, value, is_full_admin=False)}{reset_color_code}" + "%s setting litellm.%s=%s%s", + blue_color_code, + key, + _redact_general_setting_value(key, value, is_full_admin=False), + reset_color_code, ) setattr(litellm, key, value) if key == "request_timeout": @@ -5019,7 +5049,7 @@ class ProxyConfig: ) else: verbose_proxy_logger.warning( - f"Key '{k}' is not a valid argument for Router.__init__(). Ignoring this key." + "Key '%s' is not a valid argument for Router.__init__(). Ignoring this key.", k ) router = litellm.Router( **router_params, @@ -5152,7 +5182,7 @@ class ProxyConfig: policy_attachments_config = config.get("policy_attachments", None) - verbose_proxy_logger.info(f"Policy engine: found {len(policies_config)} policies in config") + verbose_proxy_logger.info("Policy engine: found %s policies in config", len(policies_config)) # Initialize policies await init_policies( @@ -5175,7 +5205,7 @@ class ProxyConfig: # Ensure proxy_logging_obj.alerting is set for all alerting types _alerting_value = general_settings.get("alerting", None) - verbose_proxy_logger.debug(f"_load_alerting_settings: Calling update_values with alerting={_alerting_value}") + verbose_proxy_logger.debug("_load_alerting_settings: Calling update_values with alerting=%s", _alerting_value) proxy_logging_obj.update_values( alerting=_alerting_value, alerting_threshold=general_settings.get("alerting_threshold", 600), @@ -5393,7 +5423,7 @@ class ProxyConfig: else: verbose_proxy_logger.error( - f"Invalid model added to proxy db. Invalid litellm params. litellm_params={_litellm_params}" + "Invalid model added to proxy db. Invalid litellm params. litellm_params=%s", _litellm_params ) continue # skip to next model _model_info = self.get_model_info_with_id(model=m, db_model=True) ## 👈 FLAG = True for db_models @@ -5423,7 +5453,7 @@ class ProxyConfig: _litellm_params = LiteLLM_Params.model_validate(_litellm_params) else: verbose_proxy_logger.error( - f"Invalid model added to proxy db. Invalid litellm params. litellm_params={_litellm_params}" + "Invalid model added to proxy db. Invalid litellm params. litellm_params=%s", _litellm_params ) continue # skip to next model @@ -5472,13 +5502,13 @@ class ProxyConfig: models_list: list = new_models if isinstance(new_models, list) else [] if llm_router is None and master_key is not None: - verbose_proxy_logger.debug(f"len new_models: {len(models_list)}") + verbose_proxy_logger.debug("len new_models: %s", len(models_list)) _model_list: list = self.decrypt_model_list_from_db(new_models=models_list) # Only create router if we have models or search_tools to route # Router can function with model_list=[] if search_tools are configured if len(_model_list) > 0 or search_tools: - verbose_proxy_logger.debug(f"_model_list: {_model_list}") + verbose_proxy_logger.debug("_model_list: %s", _model_list) llm_router = litellm.Router( model_list=_model_list, router_general_settings=RouterGeneralSettings( @@ -5487,9 +5517,9 @@ class ProxyConfig: search_tools=search_tools, ignore_invalid_deployments=True, ) - verbose_proxy_logger.debug(f"updated llm_router: {llm_router}") + verbose_proxy_logger.debug("updated llm_router: %s", llm_router) else: - verbose_proxy_logger.debug(f"len new_models: {len(models_list)}") + verbose_proxy_logger.debug("len new_models: %s", len(models_list)) if search_tools is not None and llm_router is not None: llm_router.search_tools = search_tools ## DELETE MODEL LOGIC @@ -5499,7 +5529,7 @@ class ProxyConfig: self._add_deployment(db_models=models_list) except Exception as e: - verbose_proxy_logger.exception(f"Error adding/deleting model to llm_router: {e}") + verbose_proxy_logger.exception("Error adding/deleting model to llm_router: %s", e) if llm_router is not None: llm_model_list = llm_router.get_model_list() @@ -5784,7 +5814,10 @@ class ProxyConfig: item for item in _general_settings["alerting"] if item not in general_settings["alerting"] ] verbose_proxy_logger.debug( - f"Merging alerting values: YAML={general_settings['alerting']}, DB={_general_settings['alerting']}, Merged={_merged_alerting}" + "Merging alerting values: YAML=%s, DB=%s, Merged=%s", + general_settings["alerting"], + _general_settings["alerting"], + _merged_alerting, ) general_settings["alerting"] = _merged_alerting # Use update_values to properly set alerting for both slack and email @@ -5863,9 +5896,9 @@ class ProxyConfig: replace_existing=True, misfire_grace_time=APSCHEDULER_MISFIRE_GRACE_TIME, ) - verbose_proxy_logger.info(f"Spend log cleanup rescheduled with cron: {cleanup_cron}") + verbose_proxy_logger.info("Spend log cleanup rescheduled with cron: %s", cleanup_cron) except ValueError: - verbose_proxy_logger.error(f"Invalid maximum_spend_logs_cleanup_cron value: {cleanup_cron}") + verbose_proxy_logger.error("Invalid maximum_spend_logs_cleanup_cron value: %s", cleanup_cron) else: # Interval-based scheduling (existing behavior) from litellm.litellm_core_utils.duration_parser import ( @@ -5884,7 +5917,7 @@ class ProxyConfig: replace_existing=True, misfire_grace_time=APSCHEDULER_MISFIRE_GRACE_TIME, ) - verbose_proxy_logger.info(f"Spend log cleanup rescheduled with interval: {retention_interval}") + verbose_proxy_logger.info("Spend log cleanup rescheduled with interval: %s", retention_interval) except ValueError: verbose_proxy_logger.error("Invalid maximum_spend_logs_retention_interval value") @@ -6119,7 +6152,7 @@ class ProxyConfig: # If supported_db_objects is set, only load specified objects if not isinstance(supported_db_objects, list): verbose_proxy_logger.warning( - f"supported_db_objects is not a list, got {type(supported_db_objects)}. Loading all objects." + "supported_db_objects is not a list, got %s. Loading all objects.", type(supported_db_objects) ) return True @@ -6143,7 +6176,7 @@ class ProxyConfig: return new_models except Exception as e: verbose_proxy_logger.exception( - f"litellm.proxy_server.py::add_deployment() - Error getting new models from DB - {e}" + "litellm.proxy_server.py::add_deployment() - Error getting new models from DB - %s", e ) return None @@ -6200,7 +6233,7 @@ class ProxyConfig: await self._init_non_llm_objects_in_db(prisma_client=prisma_client) except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.py::ProxyConfig:add_deployment - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.py::ProxyConfig:add_deployment - %s", e) return still_desired_ids @@ -6234,7 +6267,7 @@ class ProxyConfig: try: await subscriber.stop() except Exception as e: - verbose_proxy_logger.error(f"Error stopping config sync subscriber: {e}") + verbose_proxy_logger.error("Error stopping config sync subscriber: %s", e) async def _init_non_llm_objects_in_db(self, prisma_client: PrismaClient): """ @@ -6355,7 +6388,7 @@ class ProxyConfig: self._last_semantic_filter_config = mcp_semantic_filter_config.copy() except Exception as e: - verbose_proxy_logger.exception(f"Error initializing semantic filter settings from DB: {e}") + verbose_proxy_logger.exception("Error initializing semantic filter settings from DB: %s", e) async def _init_sso_settings_in_db(self, prisma_client: PrismaClient): """ @@ -6375,7 +6408,9 @@ class ProxyConfig: uppercase_sso_settings = {key.upper(): value for key, value in sso_settings.sso_settings.items()} self._decrypt_and_set_db_env_variables(environment_variables=uppercase_sso_settings) except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.py::ProxyConfig:_init_sso_settings_in_db - {e}") + verbose_proxy_logger.exception( + "litellm.proxy.proxy_server.py::ProxyConfig:_init_sso_settings_in_db - %s", e + ) async def _init_hashicorp_vault_config_override(self, prisma_client: PrismaClient): """ @@ -6476,7 +6511,7 @@ class ProxyConfig: f"Model cost map reload triggered by interval. Hours since last reload: {hours_since_last_reload:.2f}, Interval: {interval_hours}" ) except Exception as e: - verbose_proxy_logger.warning(f"Error parsing last reload time: {e}") + verbose_proxy_logger.warning("Error parsing last reload time: %s", e) # If we can't parse the last reload time, reload anyway should_reload = True else: @@ -6528,11 +6563,12 @@ class ProxyConfig: await evict_config_param("model_cost_map_reload_config") verbose_proxy_logger.info( - f"Model cost map reloaded successfully. Models count: {len(new_model_cost_map) if new_model_cost_map else 0}" + "Model cost map reloaded successfully. Models count: %s", + len(new_model_cost_map) if new_model_cost_map else 0, ) except Exception as e: - verbose_proxy_logger.exception(f"Error in _check_and_reload_model_cost_map: {e}") + verbose_proxy_logger.exception("Error in _check_and_reload_model_cost_map: %s", e) async def _check_and_reload_anthropic_beta_headers(self, prisma_client: PrismaClient): """ @@ -6576,7 +6612,7 @@ class ProxyConfig: f"Anthropic beta headers reload triggered by interval. Hours since last reload: {hours_since_last_reload:.2f}, Interval: {interval_hours}" ) except Exception as e: - verbose_proxy_logger.warning(f"Error parsing last reload time: {e}") + verbose_proxy_logger.warning("Error parsing last reload time: %s", e) # If we can't parse the last reload time, reload anyway should_reload = True else: @@ -6625,11 +6661,11 @@ class ProxyConfig: # Count providers in config provider_count = sum(1 for k in new_config.keys() if k != "provider_aliases" and k != "description") verbose_proxy_logger.info( - f"Anthropic beta headers config reloaded successfully. Providers: {provider_count}" + "Anthropic beta headers config reloaded successfully. Providers: %s", provider_count ) except Exception as e: - verbose_proxy_logger.exception(f"Error in _check_and_reload_anthropic_beta_headers: {e}") + verbose_proxy_logger.exception("Error in _check_and_reload_anthropic_beta_headers: %s", e) def _get_prompt_spec_for_db_prompt(self, db_prompt): """ @@ -6658,7 +6694,7 @@ class ProxyConfig: prompt_spec = self._get_prompt_spec_for_db_prompt(db_prompt=prompt) IN_MEMORY_PROMPT_REGISTRY.initialize_prompt(prompt=prompt_spec) except Exception as e: - verbose_proxy_logger.debug(f"litellm.proxy.proxy_server.py::ProxyConfig:_init_prompts_in_db - {e}") + verbose_proxy_logger.debug("litellm.proxy.proxy_server.py::ProxyConfig:_init_prompts_in_db - %s", e) async def _init_guardrails_in_db(self, prisma_client: PrismaClient): from litellm.proxy.guardrails.guardrail_registry import ( @@ -6685,7 +6721,7 @@ class ProxyConfig: # pod. Config-loaded entries are never touched. IN_MEMORY_GUARDRAIL_HANDLER.reconcile_db_guardrails(db_guardrail_ids=db_guardrail_ids) except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.py::ProxyConfig:_init_guardrails_in_db - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.py::ProxyConfig:_init_guardrails_in_db - %s", e) async def _init_policies_in_db(self, prisma_client: PrismaClient): """ @@ -6709,7 +6745,7 @@ class ProxyConfig: verbose_proxy_logger.debug("Successfully synced policies and attachments from DB") except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.py::ProxyConfig:_init_policies_in_db - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.py::ProxyConfig:_init_policies_in_db - %s", e) async def _init_tool_policy_in_db(self, prisma_client: PrismaClient): """ @@ -6723,7 +6759,7 @@ class ProxyConfig: await registry.sync_tool_policy_from_db(prisma_client=prisma_client) verbose_proxy_logger.debug("Successfully synced tool policy from DB") except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.py::ProxyConfig:_init_tool_policy_in_db - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.py::ProxyConfig:_init_tool_policy_in_db - %s", e) async def _init_vector_stores_in_db(self, prisma_client: PrismaClient): from litellm.vector_stores.vector_store_registry import VectorStoreRegistry @@ -6741,7 +6777,7 @@ class ProxyConfig: litellm.vector_store_registry.add_vector_store_to_registry(vector_store=vector_store) except Exception as e: verbose_proxy_logger.exception( - f"litellm.proxy.proxy_server.py::ProxyConfig:_init_vector_stores_in_db - {e}" + "litellm.proxy.proxy_server.py::ProxyConfig:_init_vector_stores_in_db - %s", e ) async def _init_vector_store_indexes_in_db(self, prisma_client: PrismaClient): @@ -6765,7 +6801,7 @@ class ProxyConfig: litellm.vector_store_index_registry.upsert_vector_store_index(vector_store_index=vector_store_index) except Exception as e: verbose_proxy_logger.exception( - f"litellm.proxy.proxy_server.py::ProxyConfig:_init_vector_stores_in_db - {e}" + "litellm.proxy.proxy_server.py::ProxyConfig:_init_vector_stores_in_db - %s", e ) async def _init_mcp_servers_in_db(self): @@ -6790,7 +6826,7 @@ class ProxyConfig: await backfill_null_oauth2_flows(prisma_client) except Exception as e: # noqa: BLE001 verbose_proxy_logger.exception( - f"litellm.proxy.proxy_server.py::ProxyConfig:_init_mcp_servers_in_db backfill - {e}" + "litellm.proxy.proxy_server.py::ProxyConfig:_init_mcp_servers_in_db backfill - %s", e ) try: @@ -6798,13 +6834,13 @@ class ProxyConfig: await backfill_discovery_stamped_issuers(prisma_client) except Exception as e: # noqa: BLE001 verbose_proxy_logger.exception( - f"litellm.proxy.proxy_server.py::ProxyConfig:_init_mcp_servers_in_db issuer stamp backfill - {e}" + "litellm.proxy.proxy_server.py::ProxyConfig:_init_mcp_servers_in_db issuer stamp backfill - %s", e ) try: await global_mcp_server_manager.reload_servers_from_database() except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.py::ProxyConfig:_init_mcp_servers_in_db - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.py::ProxyConfig:_init_mcp_servers_in_db - %s", e) async def init_mcp_servers_from_db(self) -> None: if self._should_load_db_object(object_type="mcp"): @@ -6832,7 +6868,7 @@ class ProxyConfig: await global_mcp_server_manager.reload_servers_from_database() except Exception as e: # noqa: BLE001 # scheduled job: a reload failure must not kill the recurring retry verbose_proxy_logger.exception( - f"litellm.proxy.proxy_server.py::ProxyConfig:reload_mcp_servers_from_db - {e}" + "litellm.proxy.proxy_server.py::ProxyConfig:reload_mcp_servers_from_db - %s", e ) async def _init_agents_in_db(self, prisma_client: PrismaClient): @@ -6844,7 +6880,7 @@ class ProxyConfig: db_agents = await AGENT_REGISTRY.get_all_agents_from_db(prisma_client=prisma_client) AGENT_REGISTRY.load_agents_from_db_and_config(db_agents=db_agents) except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.py::ProxyConfig:_init_agents_in_db - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.py::ProxyConfig:_init_agents_in_db - %s", e) async def _init_search_tools_in_db(self, prisma_client: PrismaClient): """ @@ -6869,13 +6905,15 @@ class ProxyConfig: ) verbose_proxy_logger.info( - f"Loading {len(search_tools)} search tool(s) into router " - f"({len(config_search_tools)} from config, {len(db_search_tools)} from database)" + "Loading %s search tool(s) into router (%s from config, %s from database)", + len(search_tools), + len(config_search_tools), + len(db_search_tools), ) if llm_router is not None and search_tools: await SearchAPIRouter.update_router_search_tools(router_instance=llm_router, search_tools=search_tools) - verbose_proxy_logger.info(f"Successfully loaded {len(search_tools)} search tool(s) into router") + verbose_proxy_logger.info("Successfully loaded %s search tool(s) into router", len(search_tools)) elif llm_router is not None: verbose_proxy_logger.debug("No search tools found in config or database, skipping router update") else: @@ -6884,7 +6922,9 @@ class ProxyConfig: ) except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.py::ProxyConfig:_init_search_tools_in_db - {e}") + verbose_proxy_logger.exception( + "litellm.proxy.proxy_server.py::ProxyConfig:_init_search_tools_in_db - %s", e + ) @staticmethod def _merge_config_and_db_search_tools( @@ -6950,7 +6990,7 @@ class ProxyConfig: CredentialAccessor.upsert_credentials(credentials) # upsert credentials that are in the all-up list except Exception as e: verbose_proxy_logger.exception( - f"litellm.proxy_server.py::get_credentials() - Error getting credentials from DB - {e}" + "litellm.proxy_server.py::get_credentials() - Error getting credentials from DB - %s", e ) return [] @@ -7137,7 +7177,7 @@ async def async_assistants_data_generator(response, user_api_key_dict: UserAPIKe yield f"data: {done_message}\n\n" except Exception as e: verbose_proxy_logger.exception( - f"litellm.proxy.proxy_server.async_assistants_data_generator(): Exception occured - {e}" + "litellm.proxy.proxy_server.async_assistants_data_generator(): Exception occured - %s", e ) await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, @@ -7145,7 +7185,8 @@ async def async_assistants_data_generator(response, user_api_key_dict: UserAPIKe request_data=request_data, ) verbose_proxy_logger.debug( - f"\033[1;31mAn error occurred: {e}\n\n Debug this by setting `--debug`, e.g. `litellm --model gpt-3.5-turbo --debug`" + "\x1b[1;31mAn error occurred: %s\n\n Debug this by setting `--debug`, e.g. `litellm --model gpt-3.5-turbo --debug`", + e, ) if isinstance(e, HTTPException): raise e @@ -7616,14 +7657,15 @@ async def async_data_generator( client_disconnected = True raise except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.async_data_generator(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.async_data_generator(): Exception occured - %s", e) await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=request_data, ) verbose_proxy_logger.debug( - f"\033[1;31mAn error occurred: {e}\n\n Debug this by setting `--debug`, e.g. `litellm --model gpt-3.5-turbo --debug`" + "\x1b[1;31mAn error occurred: %s\n\n Debug this by setting `--debug`, e.g. `litellm --model gpt-3.5-turbo --debug`", + e, ) if isinstance(e, HTTPException): @@ -7865,8 +7907,9 @@ class ProxyStartupEvent: return verbose_proxy_logger.debug( - f"Initializing semantic tool filter: llm_router={llm_router is not None}, " - f"config={mcp_semantic_filter_config}" + "Initializing semantic tool filter: llm_router=%s, config=%s", + llm_router is not None, + mcp_semantic_filter_config, ) hook = await SemanticToolFilterHook.initialize_from_config( config=mcp_semantic_filter_config, @@ -8258,9 +8301,9 @@ class ProxyStartupEvent: replace_existing=True, misfire_grace_time=APSCHEDULER_MISFIRE_GRACE_TIME, ) - verbose_proxy_logger.info(f"Spend log cleanup scheduled with cron: {cleanup_cron}") + verbose_proxy_logger.info("Spend log cleanup scheduled with cron: %s", cleanup_cron) except ValueError: - verbose_proxy_logger.error(f"Invalid maximum_spend_logs_cleanup_cron value: {cleanup_cron}") + verbose_proxy_logger.error("Invalid maximum_spend_logs_cleanup_cron value: %s", cleanup_cron) else: # Interval-based scheduling (existing behavior) retention_interval = general_settings.get("maximum_spend_logs_retention_interval", "1d") @@ -8302,7 +8345,7 @@ class ProxyStartupEvent: verbose_proxy_logger.info("Batch cost check job scheduled successfully") except Exception as e: - verbose_proxy_logger.debug(f"Failed to setup batch cost checking: {e}") + verbose_proxy_logger.debug("Failed to setup batch cost checking: %s", e) verbose_proxy_logger.debug( "Checking batch cost for LiteLLM Managed Files is an Enterprise Feature. Skipping..." ) @@ -8331,7 +8374,7 @@ class ProxyStartupEvent: verbose_proxy_logger.info("Responses cost check job scheduled successfully") except Exception as e: - verbose_proxy_logger.debug(f"Failed to setup responses cost checking: {e}") + verbose_proxy_logger.debug("Failed to setup responses cost checking: %s", e) verbose_proxy_logger.debug( "Checking responses cost for LiteLLM Managed Files is an Enterprise Feature. Skipping..." ) @@ -8343,8 +8386,8 @@ class ProxyStartupEvent: # Start the scheduler immediately without processing backlogs scheduler.start(paused=False) verbose_proxy_logger.info( - f"APScheduler started with memory leak prevention settings: " - f"removed jitter, increased intervals, misfire_grace_time={APSCHEDULER_MISFIRE_GRACE_TIME}" + "APScheduler started with memory leak prevention settings: removed jitter, increased intervals, misfire_grace_time=%s", + APSCHEDULER_MISFIRE_GRACE_TIME, ) @classmethod @@ -8432,7 +8475,7 @@ class ProxyStartupEvent: ) key_rotation_enabled: bool | None = str_to_bool(LITELLM_KEY_ROTATION_ENABLED) - verbose_proxy_logger.debug(f"key_rotation_enabled: {key_rotation_enabled}") + verbose_proxy_logger.debug("key_rotation_enabled: %s", key_rotation_enabled) if key_rotation_enabled is True: try: @@ -8449,7 +8492,8 @@ class ProxyStartupEvent: pod_lock_manager=pod_lock_manager, ) verbose_proxy_logger.debug( - f"Key rotation background job scheduled every {LITELLM_KEY_ROTATION_CHECK_INTERVAL_SECONDS} seconds (LITELLM_KEY_ROTATION_ENABLED=true)" + "Key rotation background job scheduled every %s seconds (LITELLM_KEY_ROTATION_ENABLED=true)", + LITELLM_KEY_ROTATION_CHECK_INTERVAL_SECONDS, ) scheduler.add_job( key_rotation_manager.process_rotations, @@ -8460,7 +8504,7 @@ class ProxyStartupEvent: else: verbose_proxy_logger.warning("Key rotation enabled but prisma_client not available") except Exception as e: - verbose_proxy_logger.warning(f"Failed to setup key rotation job: {e}") + verbose_proxy_logger.warning("Failed to setup key rotation job: %s", e) else: verbose_proxy_logger.debug("Key rotation disabled (set LITELLM_KEY_ROTATION_ENABLED=true to enable)") @@ -8487,7 +8531,7 @@ class ProxyStartupEvent: expired_ui_session_key_cleanup_enabled: bool | None = str_to_bool( LITELLM_EXPIRED_UI_SESSION_KEY_CLEANUP_ENABLED ) - verbose_proxy_logger.debug(f"expired_ui_session_key_cleanup_enabled: {expired_ui_session_key_cleanup_enabled}") + verbose_proxy_logger.debug("expired_ui_session_key_cleanup_enabled: %s", expired_ui_session_key_cleanup_enabled) if expired_ui_session_key_cleanup_enabled is True: try: @@ -8503,11 +8547,8 @@ class ProxyStartupEvent: pod_lock_manager=pod_lock_manager, ) verbose_proxy_logger.debug( - "Expired UI session key cleanup background job scheduled " - "every " - f"{LITELLM_EXPIRED_UI_SESSION_KEY_CLEANUP_INTERVAL_SECONDS} " - "seconds " - "(LITELLM_EXPIRED_UI_SESSION_KEY_CLEANUP_ENABLED=true)" + "Expired UI session key cleanup background job scheduled every %s seconds (LITELLM_EXPIRED_UI_SESSION_KEY_CLEANUP_ENABLED=true)", + LITELLM_EXPIRED_UI_SESSION_KEY_CLEANUP_INTERVAL_SECONDS, ) scheduler.add_job( expired_ui_session_key_cleanup_manager.cleanup_expired_keys, @@ -8520,7 +8561,7 @@ class ProxyStartupEvent: "Expired UI session key cleanup enabled but prisma_client not available" ) except Exception as e: - verbose_proxy_logger.warning(f"Failed to setup expired UI session key cleanup job: {e}") + verbose_proxy_logger.warning("Failed to setup expired UI session key cleanup job: %s", e) else: verbose_proxy_logger.debug( "Expired UI session key cleanup disabled (set " @@ -9367,7 +9408,7 @@ async def completion( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.completion(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.completion(): Exception occured - %s", e) error_msg = f"{e}" raise ProxyException( message=getattr(e, "message", error_msg), @@ -9606,7 +9647,7 @@ async def moderations( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.moderations(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.moderations(): Exception occured - %s", e) if isinstance(e, HTTPException): raise ProxyException( message=getattr(e, "message", str(e)), @@ -9752,7 +9793,7 @@ async def audio_speech( original_exception=e, request_data=data, ) - verbose_proxy_logger.error(f"litellm.proxy.proxy_server.audio_speech(): Exception occured - {e}") + verbose_proxy_logger.error("litellm.proxy.proxy_server.audio_speech(): Exception occured - %s", e) verbose_proxy_logger.debug(traceback.format_exc()) raise e @@ -9894,7 +9935,7 @@ async def audio_transcriptions( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.audio_transcription(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.audio_transcription(): Exception occured - %s", e) if isinstance(e, HTTPException): raise ProxyException( message=getattr(e, "message", str(e.detail)), @@ -10180,7 +10221,7 @@ async def get_assistants( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.error(f"litellm.proxy.proxy_server.get_assistants(): Exception occured - {e}") + verbose_proxy_logger.error("litellm.proxy.proxy_server.get_assistants(): Exception occured - %s", e) verbose_proxy_logger.debug(traceback.format_exc()) if isinstance(e, HTTPException): raise ProxyException( @@ -10271,7 +10312,7 @@ async def create_assistant( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.error(f"litellm.proxy.proxy_server.create_assistant(): Exception occured - {e}") + verbose_proxy_logger.error("litellm.proxy.proxy_server.create_assistant(): Exception occured - %s", e) verbose_proxy_logger.debug(traceback.format_exc()) if isinstance(e, HTTPException): raise ProxyException( @@ -10360,7 +10401,7 @@ async def delete_assistant( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.error(f"litellm.proxy.proxy_server.delete_assistant(): Exception occured - {e}") + verbose_proxy_logger.error("litellm.proxy.proxy_server.delete_assistant(): Exception occured - %s", e) verbose_proxy_logger.debug(traceback.format_exc()) if isinstance(e, HTTPException): raise ProxyException( @@ -10449,7 +10490,7 @@ async def create_threads( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.error(f"litellm.proxy.proxy_server.create_threads(): Exception occured - {e}") + verbose_proxy_logger.error("litellm.proxy.proxy_server.create_threads(): Exception occured - %s", e) verbose_proxy_logger.debug(traceback.format_exc()) if isinstance(e, HTTPException): raise ProxyException( @@ -10536,7 +10577,7 @@ async def get_thread( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.error(f"litellm.proxy.proxy_server.get_thread(): Exception occured - {e}") + verbose_proxy_logger.error("litellm.proxy.proxy_server.get_thread(): Exception occured - %s", e) verbose_proxy_logger.debug(traceback.format_exc()) if isinstance(e, HTTPException): raise ProxyException( @@ -10627,7 +10668,7 @@ async def add_messages( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.error(f"litellm.proxy.proxy_server.add_messages(): Exception occured - {e}") + verbose_proxy_logger.error("litellm.proxy.proxy_server.add_messages(): Exception occured - %s", e) verbose_proxy_logger.debug(traceback.format_exc()) if isinstance(e, HTTPException): raise ProxyException( @@ -10714,7 +10755,7 @@ async def get_messages( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.error(f"litellm.proxy.proxy_server.get_messages(): Exception occured - {e}") + verbose_proxy_logger.error("litellm.proxy.proxy_server.get_messages(): Exception occured - %s", e) verbose_proxy_logger.debug(traceback.format_exc()) if isinstance(e, HTTPException): raise ProxyException( @@ -10815,7 +10856,7 @@ async def run_thread( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.error(f"litellm.proxy.proxy_server.run_thread(): Exception occured - {e}") + verbose_proxy_logger.error("litellm.proxy.proxy_server.run_thread(): Exception occured - %s", e) verbose_proxy_logger.debug(traceback.format_exc()) if isinstance(e, HTTPException): raise ProxyException( @@ -10954,8 +10995,9 @@ async def _try_provider_token_count( code=result.status_code or 500, ) verbose_proxy_logger.warning( - f"Provider token counting failed ({result.status_code}): {result.error_message}. " - "Falling back to local tokenizer." + "Provider token counting failed (%s): %s. Falling back to local tokenizer.", + result.status_code, + result.error_message, ) return None return result @@ -11752,7 +11794,7 @@ async def _apply_search_filter_to_models( ) search_total_count = router_models_count + db_models_total_count except Exception as e: - verbose_proxy_logger.exception(f"Error querying database models with search: {e}") + verbose_proxy_logger.exception("Error querying database models with search: %s", e) search_total_count = router_models_count else: search_total_count = router_models_count @@ -11887,7 +11929,7 @@ def _sort_models( sorted_models = sorted(all_models, key=get_sort_key, reverse=reverse) return sorted_models except Exception as e: - verbose_proxy_logger.exception(f"Error sorting models by {sort_by}: {e}") + verbose_proxy_logger.exception("Error sorting models by %s: %s", sort_by, e) return all_models @@ -11935,7 +11977,12 @@ def _paginate_models_response( paginated_models = all_models[skip : skip + size] verbose_proxy_logger.debug( - f"Pagination: skip={skip}, take={size}, total_count={total_count}, total_pages={total_pages}, search={search}" + "Pagination: skip=%s, take=%s, total_count=%s, total_pages=%s, search=%s", + skip, + size, + total_count, + total_pages, + search, ) return { @@ -11963,11 +12010,11 @@ async def _load_team_object_for_model_filter(team_id: str, prisma_client: Prisma try: team_db_object = await TeamRepository(prisma_client).table.find_unique(where={"team_id": team_id}) if team_db_object is None: - verbose_proxy_logger.warning(f"Team {team_id} not found in database") + verbose_proxy_logger.warning("Team %s not found in database", team_id) return None return LiteLLM_TeamTable.model_validate(team_db_object.model_dump()) except Exception as e: - verbose_proxy_logger.exception(f"Error fetching team {team_id}: {e}") + verbose_proxy_logger.exception("Error fetching team %s: %s", team_id, e) return None @@ -12017,7 +12064,7 @@ async def _gather_team_accessible_model_ids( if db_model.model_id: team_accessible_model_ids.add(db_model.model_id) except Exception as e: - verbose_proxy_logger.debug(f"Error querying database models for team {team_id}: {e}") + verbose_proxy_logger.debug("Error querying database models for team %s: %s", team_id, e) return team_accessible_model_ids @@ -12155,7 +12202,7 @@ async def _find_model_by_id( if decrypted_models: found_model = decrypted_models[0] except Exception as e: - verbose_proxy_logger.exception(f"Error querying database for modelId {model_id}: {e}") + verbose_proxy_logger.exception("Error querying database for modelId %s: %s", model_id, e) # If model found, verify search filter if provided if found_model is not None: @@ -13771,7 +13818,7 @@ async def login_v2(request: Request): json_response.set_cookie(key="token", value=jwt_token) return json_response except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.login_v2(): Exception occurred - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.login_v2(): Exception occurred - %s", e) if isinstance(e, ProxyException): raise e elif isinstance(e, HTTPException): @@ -13848,7 +13895,7 @@ async def login_v3(request: Request): status_code=status.HTTP_200_OK, ) except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.login_v3(): Exception occurred - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.login_v3(): Exception occurred - %s", e) if isinstance(e, ProxyException): raise e elif isinstance(e, HTTPException): @@ -13921,7 +13968,7 @@ async def login_v3_exchange(request: Request): except ProxyException: raise except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.login_v3_exchange(): Exception occurred - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.login_v3_exchange(): Exception occurred - %s", e) raise ProxyException( message=str(e), type=ProxyErrorTypes.auth_error, @@ -14289,11 +14336,12 @@ async def get_image(): if not os.path.exists(assets_dir): try: os.makedirs(assets_dir, exist_ok=True) - verbose_proxy_logger.debug(f"Created assets directory at {assets_dir}") + verbose_proxy_logger.debug("Created assets directory at %s", assets_dir) except (PermissionError, OSError) as e: verbose_proxy_logger.warning( - f"Cannot create assets directory at {assets_dir}: {e}. " - f"Logo caching may not work. Using current directory for assets." + "Cannot create assets directory at %s: %s. Logo caching may not work. Using current directory for assets.", + assets_dir, + e, ) assets_dir = current_dir @@ -14748,7 +14796,7 @@ async def update_config( return {"message": "Config updated successfully"} except Exception as e: - verbose_proxy_logger.error(f"litellm.proxy.proxy_server.update_config(): Exception occured - {e}") + verbose_proxy_logger.error("litellm.proxy.proxy_server.update_config(): Exception occured - %s", e) verbose_proxy_logger.debug(traceback.format_exc()) if isinstance(e, HTTPException): raise ProxyException( @@ -15576,7 +15624,7 @@ async def delete_callback( except HTTPException: raise except Exception as e: - verbose_proxy_logger.error(f"litellm.proxy.proxy_server.delete_callback(): Exception occurred - {e}") + verbose_proxy_logger.error("litellm.proxy.proxy_server.delete_callback(): Exception occurred - %s", e) verbose_proxy_logger.debug(traceback.format_exc()) raise ProxyException( message="Error deleting callback: " + str(e), @@ -15700,7 +15748,7 @@ async def get_config( "available_callbacks": all_available_callbacks, } except Exception as e: - verbose_proxy_logger.exception(f"litellm.proxy.proxy_server.get_config(): Exception occured - {e}") + verbose_proxy_logger.exception("litellm.proxy.proxy_server.get_config(): Exception occured - %s", e) if isinstance(e, HTTPException): raise ProxyException( message=getattr(e, "detail", f"Authentication Error({e})"), @@ -15809,7 +15857,7 @@ async def reload_model_cost_map( await invalidate_config_param("model_cost_map_reload_config") models_count = len(new_model_cost_map) if new_model_cost_map else 0 - verbose_proxy_logger.info(f"Model cost map reloaded successfully in current pod. Models count: {models_count}") + verbose_proxy_logger.info("Model cost map reloaded successfully in current pod. Models count: %s", models_count) return { "message": f"Price data reloaded successfully! {models_count} models updated.", @@ -15818,7 +15866,7 @@ async def reload_model_cost_map( "timestamp": current_time.isoformat(), } except Exception as e: - verbose_proxy_logger.exception(f"Failed to reload model cost map: {e}") + verbose_proxy_logger.exception("Failed to reload model cost map: %s", e) raise HTTPException(status_code=500, detail=f"Failed to reload model cost map: {e}") @@ -15866,7 +15914,7 @@ async def schedule_model_cost_map_reload( ) await invalidate_config_param("model_cost_map_reload_config") - verbose_proxy_logger.info(f"Model cost map reload scheduled for every {hours} hours") + verbose_proxy_logger.info("Model cost map reload scheduled for every %s hours", hours) return { "message": f"Model cost map reload scheduled for every {hours} hours", @@ -15875,7 +15923,7 @@ async def schedule_model_cost_map_reload( "timestamp": datetime.utcnow().isoformat(), } except Exception as e: - verbose_proxy_logger.exception(f"Failed to schedule model cost map reload: {e}") + verbose_proxy_logger.exception("Failed to schedule model cost map reload: %s", e) raise HTTPException( status_code=500, detail=f"Failed to schedule model cost map reload: {e}", @@ -15920,7 +15968,7 @@ async def cancel_model_cost_map_reload( "timestamp": datetime.utcnow().isoformat(), } except Exception as e: - verbose_proxy_logger.exception(f"Failed to cancel model cost map reload: {e}") + verbose_proxy_logger.exception("Failed to cancel model cost map reload: %s", e) raise HTTPException(status_code=500, detail=f"Failed to cancel model cost map reload: {e}") @@ -15948,7 +15996,7 @@ async def get_model_cost_map_reload_status( try: global prisma_client, last_model_cost_map_reload - verbose_proxy_logger.info(f"Checking model cost map reload status. Last reload: {last_model_cost_map_reload}") + verbose_proxy_logger.info("Checking model cost map reload status. Last reload: %s", last_model_cost_map_reload) if prisma_client is None: verbose_proxy_logger.info("No database connection, returning not scheduled") @@ -15998,7 +16046,7 @@ async def get_model_cost_map_reload_status( if hours_since_last_reload < interval_hours: next_run = (last_reload_time + timedelta(hours=interval_hours)).isoformat() except Exception as e: - verbose_proxy_logger.warning(f"Error parsing last reload time: {e}") + verbose_proxy_logger.warning("Error parsing last reload time: %s", e) return { "scheduled": True, @@ -16007,7 +16055,7 @@ async def get_model_cost_map_reload_status( "next_run": next_run, } except Exception as e: - verbose_proxy_logger.exception(f"Failed to get model cost map reload status: {e}") + verbose_proxy_logger.exception("Failed to get model cost map reload status: %s", e) raise HTTPException( status_code=500, detail=f"Failed to get model cost map reload status: {e}", @@ -16055,7 +16103,7 @@ async def get_model_cost_map_source( "model_count": model_count, } except Exception as e: - verbose_proxy_logger.exception(f"Failed to get model cost map source info: {e}") + verbose_proxy_logger.exception("Failed to get model cost map source info: %s", e) raise HTTPException( status_code=500, detail=f"Failed to get model cost map source info: {e}", @@ -16124,7 +16172,7 @@ async def reload_anthropic_beta_headers( provider_count = sum(1 for k in new_config.keys() if k not in ["provider_aliases", "description"]) verbose_proxy_logger.info( - f"Anthropic beta headers config reloaded successfully in current pod. Providers: {provider_count}" + "Anthropic beta headers config reloaded successfully in current pod. Providers: %s", provider_count ) return { @@ -16134,7 +16182,7 @@ async def reload_anthropic_beta_headers( "timestamp": current_time.isoformat(), } except Exception as e: - verbose_proxy_logger.exception(f"Failed to reload anthropic beta headers: {e}") + verbose_proxy_logger.exception("Failed to reload anthropic beta headers: %s", e) raise HTTPException(status_code=500, detail=f"Failed to reload anthropic beta headers: {e}") @@ -16182,7 +16230,7 @@ async def schedule_anthropic_beta_headers_reload( ) await invalidate_config_param("anthropic_beta_headers_reload_config") - verbose_proxy_logger.info(f"Anthropic beta headers reload scheduled for every {hours} hours") + verbose_proxy_logger.info("Anthropic beta headers reload scheduled for every %s hours", hours) return { "message": f"Anthropic beta headers reload scheduled for every {hours} hours", @@ -16191,7 +16239,7 @@ async def schedule_anthropic_beta_headers_reload( "timestamp": datetime.utcnow().isoformat(), } except Exception as e: - verbose_proxy_logger.exception(f"Failed to schedule anthropic beta headers reload: {e}") + verbose_proxy_logger.exception("Failed to schedule anthropic beta headers reload: %s", e) raise HTTPException( status_code=500, detail=f"Failed to schedule anthropic beta headers reload: {e}", @@ -16236,7 +16284,7 @@ async def cancel_anthropic_beta_headers_reload( "timestamp": datetime.utcnow().isoformat(), } except Exception as e: - verbose_proxy_logger.exception(f"Failed to cancel anthropic beta headers reload: {e}") + verbose_proxy_logger.exception("Failed to cancel anthropic beta headers reload: %s", e) raise HTTPException( status_code=500, detail=f"Failed to cancel anthropic beta headers reload: {e}", @@ -16268,7 +16316,7 @@ async def get_anthropic_beta_headers_reload_status( global prisma_client, last_anthropic_beta_headers_reload verbose_proxy_logger.info( - f"Checking anthropic beta headers reload status. Last reload: {last_anthropic_beta_headers_reload}" + "Checking anthropic beta headers reload status. Last reload: %s", last_anthropic_beta_headers_reload ) if prisma_client is None: @@ -16319,7 +16367,7 @@ async def get_anthropic_beta_headers_reload_status( if hours_since_last_reload < interval_hours: next_run = (last_reload_time + timedelta(hours=interval_hours)).isoformat() except Exception as e: - verbose_proxy_logger.warning(f"Error parsing last reload time: {e}") + verbose_proxy_logger.warning("Error parsing last reload time: %s", e) return { "scheduled": True, @@ -16328,7 +16376,7 @@ async def get_anthropic_beta_headers_reload_status( "next_run": next_run, } except Exception as e: - verbose_proxy_logger.exception(f"Failed to get anthropic beta headers reload status: {e}") + verbose_proxy_logger.exception("Failed to get anthropic beta headers reload status: %s", e) raise HTTPException( status_code=500, detail=f"Failed to get anthropic beta headers reload status: {e}", diff --git a/litellm/proxy/rag_endpoints/endpoints.py b/litellm/proxy/rag_endpoints/endpoints.py index a4ef30fb3c4..129ff8df3bd 100644 --- a/litellm/proxy/rag_endpoints/endpoints.py +++ b/litellm/proxy/rag_endpoints/endpoints.py @@ -191,7 +191,7 @@ async def _save_vector_store_to_db_from_rag_ingest( elif hasattr(response, "vector_store_id"): vector_store_id = response.vector_store_id else: - verbose_proxy_logger.warning(f"Unable to extract vector_store_id from response type: {type(response)}") + verbose_proxy_logger.warning("Unable to extract vector_store_id from response type: %s", type(response)) return if vector_store_id is None or not isinstance(vector_store_id, str): @@ -229,7 +229,7 @@ async def _save_vector_store_to_db_from_rag_ingest( # Only create if it doesn't exist if existing_vector_store is None: - verbose_proxy_logger.info(f"Saving newly created vector store {vector_store_id} to database") + verbose_proxy_logger.info("Saving newly created vector store %s to database", vector_store_id) # Initialize metadata with first file initial_metadata = {"ingested_files": [file_entry]} @@ -250,9 +250,9 @@ async def _save_vector_store_to_db_from_rag_ingest( user_id=user_api_key_dict.user_id, ) - verbose_proxy_logger.info(f"Vector store {vector_store_id} saved to database successfully") + verbose_proxy_logger.info("Vector store %s saved to database successfully", vector_store_id) else: - verbose_proxy_logger.info(f"Vector store {vector_store_id} already exists, appending file to metadata") + verbose_proxy_logger.info("Vector store %s already exists, appending file to metadata", vector_store_id) # Update existing vector store with new file existing_metadata = existing_vector_store.vector_store_metadata or {} @@ -274,11 +274,13 @@ async def _save_vector_store_to_db_from_rag_ingest( ) verbose_proxy_logger.info( - f"Added file {file_entry.get('filename') or file_entry.get('file_url', 'Unknown')} to vector store {vector_store_id} metadata" + "Added file %s to vector store %s metadata", + file_entry.get("filename") or file_entry.get("file_url", "Unknown"), + vector_store_id, ) except Exception as db_error: # Log the error but don't fail the request since ingestion succeeded - verbose_proxy_logger.exception(f"Failed to save vector store {vector_store_id} to database: {db_error}") + verbose_proxy_logger.exception("Failed to save vector store %s to database: %s", vector_store_id, db_error) async def parse_rag_ingest_request( @@ -495,7 +497,7 @@ async def rag_ingest( proxy_config=proxy_config, ) - verbose_proxy_logger.debug(f"RAG Ingest - options: {ingest_options}") + verbose_proxy_logger.debug("RAG Ingest - options: %s", ingest_options) # Call ingest response = await litellm.aingest( @@ -509,7 +511,10 @@ async def rag_ingest( # Save vector store to database if it was newly created and prisma_client is available verbose_proxy_logger.debug( - f"RAG Ingest - Checking database save conditions: prisma_client={prisma_client is not None}, response={response is not None}, response_type={type(response)}" + "RAG Ingest - Checking database save conditions: prisma_client=%s, response=%s, response_type=%s", + prisma_client is not None, + response is not None, + type(response), ) if prisma_client is not None and response is not None: @@ -523,7 +528,7 @@ async def rag_ingest( ) else: verbose_proxy_logger.warning( - f"Skipping database save: prisma_client={prisma_client is not None}, response={response is not None}" + "Skipping database save: prisma_client=%s, response=%s", prisma_client is not None, response is not None ) return response @@ -531,7 +536,7 @@ async def rag_ingest( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"RAG Ingest failed: {e}") + verbose_proxy_logger.exception("RAG Ingest failed: %s", e) raise HTTPException( status_code=500, detail={"error": str(e)}, @@ -663,7 +668,7 @@ async def rag_query( proxy_config=proxy_config, ) - verbose_proxy_logger.debug(f"RAG Query - model: {model}, retrieval_config: {retrieval_config}") + verbose_proxy_logger.debug("RAG Query - model: %s, retrieval_config: %s", model, retrieval_config) # Call query response = await litellm.aquery( @@ -706,7 +711,7 @@ async def rag_query( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"RAG Query failed: {e}") + verbose_proxy_logger.exception("RAG Query failed: %s", e) raise HTTPException( status_code=500, detail={"error": str(e)}, diff --git a/litellm/proxy/rerank_endpoints/endpoints.py b/litellm/proxy/rerank_endpoints/endpoints.py index f1c138fa1bf..e91b3b18f01 100644 --- a/litellm/proxy/rerank_endpoints/endpoints.py +++ b/litellm/proxy/rerank_endpoints/endpoints.py @@ -103,7 +103,7 @@ async def rerank( await proxy_logging_obj.post_call_failure_hook( user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data ) - verbose_proxy_logger.error(f"litellm.proxy.proxy_server.rerank(): Exception occured - {e}") + verbose_proxy_logger.error("litellm.proxy.proxy_server.rerank(): Exception occured - %s", e) if isinstance(e, HTTPException): raise ProxyException( message=getattr(e, "message", str(e)), diff --git a/litellm/proxy/response_api_endpoints/endpoints.py b/litellm/proxy/response_api_endpoints/endpoints.py index 9fa634dc12e..f03db48b4a7 100644 --- a/litellm/proxy/response_api_endpoints/endpoints.py +++ b/litellm/proxy/response_api_endpoints/endpoints.py @@ -116,7 +116,7 @@ async def responses_api( ResponsePollingHandler, ) - verbose_proxy_logger.info(f"Starting background response with polling for model={data.get('model')}") + verbose_proxy_logger.info("Starting background response with polling for model=%s", data.get("model")) # Run pre-call checks (rate limits, guardrails, budget) BEFORE creating # polling ID. This ensures rate-limited requests get a synchronous 429 @@ -233,7 +233,8 @@ async def responses_api( if not model_id: verbose_proxy_logger.warning( - f"No model_id found in response hidden params for response {response.id}, skipping managed object storage" + "No model_id found in response hidden params for response %s, skipping managed object storage", + response.id, ) raise Exception("No model_id found in response hidden params") # Store in managed objects table @@ -247,10 +248,14 @@ async def responses_api( ) verbose_proxy_logger.info( - f"Stored background response {response.id} in managed objects table with unified_id={response.id}" + "Stored background response %s in managed objects table with unified_id=%s", + response.id, + response.id, ) except Exception as e: - verbose_proxy_logger.error(f"Failed to store background response in managed objects table: {e}") + verbose_proxy_logger.error( + "Failed to store background response in managed objects table: %s", e + ) return response except ModifyResponseException as e: diff --git a/litellm/proxy/response_polling/background_streaming.py b/litellm/proxy/response_polling/background_streaming.py index b744396e850..7d81390866a 100644 --- a/litellm/proxy/response_polling/background_streaming.py +++ b/litellm/proxy/response_polling/background_streaming.py @@ -51,7 +51,7 @@ async def background_streaming_task( """ try: - verbose_proxy_logger.info(f"Starting background streaming for {polling_id}") + verbose_proxy_logger.info("Starting background streaming for %s", polling_id) # Update status to in_progress (OpenAI format) await polling_handler.update_state( @@ -146,8 +146,8 @@ async def background_streaming_task( # Handle StreamingResponse if not hasattr(response, "body_iterator"): verbose_proxy_logger.warning( - f"background_streaming_task: response for {polling_id} has no " - "body_iterator; this may indicate a misconfiguration or provider error" + "background_streaming_task: response for %s has no body_iterator; this may indicate a misconfiguration or provider error", + polling_id, ) if hasattr(response, "body_iterator"): @@ -293,7 +293,7 @@ async def background_streaming_task( await flush_state_if_needed() except json.JSONDecodeError as e: - verbose_proxy_logger.warning(f"Failed to parse streaming chunk: {e}") + verbose_proxy_logger.warning("Failed to parse streaming chunk: %s", e) # Final flush to ensure all accumulated state is saved await flush_state_if_needed(force=True) @@ -324,11 +324,16 @@ async def background_streaming_task( ) verbose_proxy_logger.info( - f"Finished background streaming for {polling_id}, status={final_status}, error={terminal_error}, incomplete_details={incomplete_details_data}, output_items={len(output_items)}" + "Finished background streaming for %s, status=%s, error=%s, incomplete_details=%s, output_items=%s", + polling_id, + final_status, + terminal_error, + incomplete_details_data, + len(output_items), ) except Exception as e: - verbose_proxy_logger.error(f"Error in background streaming task for {polling_id}: {e}") + verbose_proxy_logger.error("Error in background streaming task for %s: %s", polling_id, e) import traceback verbose_proxy_logger.error(traceback.format_exc()) diff --git a/litellm/proxy/response_polling/polling_handler.py b/litellm/proxy/response_polling/polling_handler.py index 4f2ad70cc7d..c39e5949f19 100644 --- a/litellm/proxy/response_polling/polling_handler.py +++ b/litellm/proxy/response_polling/polling_handler.py @@ -77,7 +77,7 @@ class ResponsePollingHandler: value=response.model_dump_json(), # Pydantic v2 method ttl=self.ttl, ) - verbose_proxy_logger.debug(f"Created initial polling state for {polling_id} with TTL={self.ttl}s") + verbose_proxy_logger.debug("Created initial polling state for %s with TTL=%ss", polling_id, self.ttl) return response @@ -141,7 +141,7 @@ class ResponsePollingHandler: # Get current state cached_state = await self.redis_cache.async_get_cache(cache_key) if not cached_state: - verbose_proxy_logger.warning(f"No cached state found for polling_id: {polling_id}") + verbose_proxy_logger.warning("No cached state found for polling_id: %s", polling_id) return # Parse existing ResponsesAPIResponse from cache @@ -209,7 +209,7 @@ class ResponsePollingHandler: output_count = len(state.get("output", [])) verbose_proxy_logger.debug( - f"Updated polling state for {polling_id}: status={state['status']}, output_items={output_count}" + "Updated polling state for %s: status=%s, output_items=%s", polling_id, state["status"], output_count ) async def get_state(self, polling_id: str) -> dict[str, Any] | None: @@ -277,7 +277,7 @@ def should_use_polling_for_request( # Check if model is in native_background_mode list - these use native provider background mode if native_background_mode and model in native_background_mode: - verbose_proxy_logger.debug(f"Model {model} is in native_background_mode list, skipping polling via cache") + verbose_proxy_logger.debug("Model %s is in native_background_mode list, skipping polling via cache", model) return False # "all" enables polling for all providers @@ -311,9 +311,9 @@ def should_use_polling_for_request( # If ANY deployment's provider matches, enable polling if dep_provider and dep_provider in polling_via_cache_enabled: - verbose_proxy_logger.debug(f"Polling enabled for model={model}, provider={dep_provider}") + verbose_proxy_logger.debug("Polling enabled for model=%s, provider=%s", model, dep_provider) return True except Exception as e: - verbose_proxy_logger.debug(f"Could not resolve provider for model {model}: {e}") + verbose_proxy_logger.debug("Could not resolve provider for model %s: %s", model, e) return False diff --git a/litellm/proxy/route_llm_request.py b/litellm/proxy/route_llm_request.py index 5e775d1cbf7..97832b0b6c4 100644 --- a/litellm/proxy/route_llm_request.py +++ b/litellm/proxy/route_llm_request.py @@ -262,7 +262,7 @@ async def add_shared_session_to_data(data: dict) -> None: if session is not None and not session.closed: data["shared_session"] = session - verbose_proxy_logger.info(f"SESSION REUSE: Attached shared aiohttp session to request (ID: {id(session)})") + verbose_proxy_logger.info("SESSION REUSE: Attached shared aiohttp session to request (ID: %s)", id(session)) elif session is not None and session.closed: # Session was created at startup but has since closed — recreate it # Use lock to prevent concurrent recreation (avoids session/connector leak) @@ -278,7 +278,7 @@ async def add_shared_session_to_data(data: dict) -> None: # or closed — either way we need to recreate if session is not None: verbose_proxy_logger.warning( - f"SESSION REUSE: Shared aiohttp session is closed (ID: {id(session)}), recreating..." + "SESSION REUSE: Shared aiohttp session is closed (ID: %s), recreating...", id(session) ) else: verbose_proxy_logger.warning( diff --git a/litellm/proxy/search_endpoints/endpoints.py b/litellm/proxy/search_endpoints/endpoints.py index 0032083b09c..09814672ccf 100644 --- a/litellm/proxy/search_endpoints/endpoints.py +++ b/litellm/proxy/search_endpoints/endpoints.py @@ -170,14 +170,15 @@ async def search( team_object=team_object, ) except Exception as e: - verbose_proxy_logger.error(f"Search tool authorization failed for {search_tool_name_value}: {e}") + verbose_proxy_logger.error("Search tool authorization failed for %s: %s", search_tool_name_value, e) raise if llm_router is not None and hasattr(llm_router, "search_tools"): verbose_proxy_logger.debug( - f"Search endpoint - Looking for search_tool_name: {search_tool_name_value}. " - f"Available search tools in router: {[tool.get('search_tool_name') for tool in llm_router.search_tools]}. " - f"Total search tools: {len(llm_router.search_tools)}" + "Search endpoint - Looking for search_tool_name: %s. Available search tools in router: %s. Total search tools: %s", + search_tool_name_value, + [tool.get("search_tool_name") for tool in llm_router.search_tools], + len(llm_router.search_tools), ) matching_tools = [ @@ -302,5 +303,5 @@ async def list_search_tools( except Exception as e: from litellm._logging import verbose_proxy_logger - verbose_proxy_logger.exception(f"Error listing search tools: {e}") + verbose_proxy_logger.exception("Error listing search tools: %s", e) raise HTTPException(status_code=500, detail=str(e)) diff --git a/litellm/proxy/search_endpoints/search_tool_management.py b/litellm/proxy/search_endpoints/search_tool_management.py index 6b0bbacd131..1b3462b48a4 100644 --- a/litellm/proxy/search_endpoints/search_tool_management.py +++ b/litellm/proxy/search_endpoints/search_tool_management.py @@ -161,7 +161,7 @@ async def list_search_tools( if parsed_tools: config_search_tools = parsed_tools except Exception as e: - verbose_proxy_logger.debug(f"Could not get config-defined search tools: {e}") + verbose_proxy_logger.debug("Could not get config-defined search tools: %s", e) for config_search_tool in config_search_tools: tool_name = config_search_tool.get("search_tool_name") @@ -214,7 +214,7 @@ async def list_search_tools( return ListSearchToolsResponse(search_tools=visible_search_tools) except Exception as e: - verbose_proxy_logger.exception(f"Error getting search tools: {e}") + verbose_proxy_logger.exception("Error getting search tools: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -278,13 +278,13 @@ async def create_search_tool(request: CreateSearchToolRequest): ) verbose_proxy_logger.debug( - f"Successfully added search tool '{result.get('search_tool_name')}' to database. " - f"Router will be updated by the cron job." + "Successfully added search tool '%s' to database. Router will be updated by the cron job.", + result.get("search_tool_name"), ) return result except Exception as e: - verbose_proxy_logger.exception(f"Error adding search tool to db: {e}") + verbose_proxy_logger.exception("Error adding search tool to db: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -361,15 +361,15 @@ async def update_search_tool(search_tool_id: str, request: UpdateSearchToolReque ) verbose_proxy_logger.debug( - f"Successfully updated search tool '{result.get('search_tool_name')}' in database. " - f"Router will be updated by the cron job." + "Successfully updated search tool '%s' in database. Router will be updated by the cron job.", + result.get("search_tool_name"), ) return result except HTTPException as e: raise e except Exception as e: - verbose_proxy_logger.exception(f"Error updating search tool: {e}") + verbose_proxy_logger.exception("Error updating search tool: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -425,7 +425,7 @@ async def delete_search_tool(search_tool_id: str): except HTTPException as e: raise e except Exception as e: - verbose_proxy_logger.exception(f"Error deleting search tool: {e}") + verbose_proxy_logger.exception("Error deleting search tool: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -498,7 +498,7 @@ async def get_search_tool_info(search_tool_id: str): except HTTPException as e: raise e except Exception as e: - verbose_proxy_logger.exception(f"Error getting search tool info: {e}") + verbose_proxy_logger.exception("Error getting search tool info: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -561,7 +561,7 @@ async def test_search_tool_connection(request: TestSearchToolConnectionRequest): if not search_provider: raise HTTPException(status_code=400, detail="search_provider is required in litellm_params") - verbose_proxy_logger.debug(f"Testing connection to search provider: {search_provider}") + verbose_proxy_logger.debug("Testing connection to search provider: %s", search_provider) # Make a simple test search query with max_results=1 to minimize cost test_query = "test" @@ -574,7 +574,7 @@ async def test_search_tool_connection(request: TestSearchToolConnectionRequest): timeout=10.0, # 10 second timeout for test ) - verbose_proxy_logger.debug(f"Successfully tested connection to {search_provider} search provider") + verbose_proxy_logger.debug("Successfully tested connection to %s search provider", search_provider) return { "status": "success", @@ -587,7 +587,7 @@ async def test_search_tool_connection(request: TestSearchToolConnectionRequest): error_message = str(e) error_type = type(e).__name__ - verbose_proxy_logger.exception(f"Failed to connect to search provider: {error_message}") + verbose_proxy_logger.exception("Failed to connect to search provider: %s", error_message) # Return error details in a structured format return { @@ -652,10 +652,10 @@ async def get_available_search_providers(): } ) except Exception as e: - verbose_proxy_logger.debug(f"Could not get config for search provider {provider.value}: {e}") + verbose_proxy_logger.debug("Could not get config for search provider %s: %s", provider.value, e) continue return {"providers": available_providers} except Exception as e: - verbose_proxy_logger.exception(f"Error getting available search providers: {e}") + verbose_proxy_logger.exception("Error getting available search providers: %s", e) raise HTTPException(status_code=500, detail=str(e)) diff --git a/litellm/proxy/search_endpoints/search_tool_registry.py b/litellm/proxy/search_endpoints/search_tool_registry.py index d7e5efa6d1e..ad8c8b6fe42 100644 --- a/litellm/proxy/search_endpoints/search_tool_registry.py +++ b/litellm/proxy/search_endpoints/search_tool_registry.py @@ -78,7 +78,7 @@ class SearchToolRegistry: return search_tool_dict except Exception as e: - verbose_proxy_logger.exception(f"Error adding search tool to DB: {e}") + verbose_proxy_logger.exception("Error adding search tool to DB: %s", e) raise Exception(f"Error adding search tool to DB: {e}") async def delete_search_tool_from_db(self, search_tool_id: str, prisma_client: PrismaClient): @@ -109,7 +109,7 @@ class SearchToolRegistry: "search_tool_name": existing_tool.search_tool_name, } except Exception as e: - verbose_proxy_logger.exception(f"Error deleting search tool from DB: {e}") + verbose_proxy_logger.exception("Error deleting search tool from DB: %s", e) raise Exception(f"Error deleting search tool from DB: {e}") async def update_search_tool_in_db(self, search_tool_id: str, search_tool: SearchTool, prisma_client: PrismaClient): @@ -143,7 +143,7 @@ class SearchToolRegistry: # Convert to dict with ISO formatted datetimes return self._convert_prisma_to_dict(updated_search_tool) except Exception as e: - verbose_proxy_logger.exception(f"Error updating search tool in DB: {e}") + verbose_proxy_logger.exception("Error updating search tool in DB: %s", e) raise Exception(f"Error updating search tool in DB: {e}") @staticmethod @@ -176,7 +176,7 @@ class SearchToolRegistry: return search_tools except Exception as e: - verbose_proxy_logger.exception(f"Error getting search tools from DB: {e}") + verbose_proxy_logger.exception("Error getting search tools from DB: %s", e) raise Exception(f"Error getting search tools from DB: {e}") async def get_search_tool_by_id_from_db( @@ -204,7 +204,7 @@ class SearchToolRegistry: search_tool_dict = self._convert_prisma_to_dict(search_tool) return SearchTool(**search_tool_dict) # type: ignore except Exception as e: - verbose_proxy_logger.exception(f"Error getting search tool from DB: {e}") + verbose_proxy_logger.exception("Error getting search tool from DB: %s", e) raise Exception(f"Error getting search tool from DB: {e}") async def get_search_tool_by_name_from_db( @@ -232,5 +232,5 @@ class SearchToolRegistry: search_tool_dict = self._convert_prisma_to_dict(search_tool) return SearchTool(**search_tool_dict) # type: ignore except Exception as e: - verbose_proxy_logger.exception(f"Error getting search tool from DB: {e}") + verbose_proxy_logger.exception("Error getting search tool from DB: %s", e) raise Exception(f"Error getting search tool from DB: {e}") diff --git a/litellm/proxy/spend_tracking/cloudzero_endpoints.py b/litellm/proxy/spend_tracking/cloudzero_endpoints.py index 7b573b2fad7..fdeb176aa99 100644 --- a/litellm/proxy/spend_tracking/cloudzero_endpoints.py +++ b/litellm/proxy/spend_tracking/cloudzero_endpoints.py @@ -161,7 +161,7 @@ async def get_cloudzero_settings( # Re-raise HTTPExceptions as-is raise e except Exception as e: - verbose_proxy_logger.error(f"Error retrieving CloudZero settings: {e}") + verbose_proxy_logger.error("Error retrieving CloudZero settings: %s", e) raise HTTPException( status_code=500, detail={"error": f"Failed to retrieve CloudZero settings: {e}"}, @@ -238,7 +238,7 @@ async def update_cloudzero_settings( ) raise e except Exception as e: - verbose_proxy_logger.error(f"Error updating CloudZero settings: {e}") + verbose_proxy_logger.error("Error updating CloudZero settings: %s", e) raise HTTPException( status_code=500, detail={"error": f"Failed to update CloudZero settings: {e}"}, @@ -275,7 +275,7 @@ async def is_cloudzero_setup_in_db() -> bool: return cloudzero_config is not None and cloudzero_config.param_value is not None except Exception as e: - verbose_proxy_logger.error(f"Error checking CloudZero status: {e}") + verbose_proxy_logger.error("Error checking CloudZero status: %s", e) return False @@ -317,7 +317,7 @@ async def is_cloudzero_setup() -> bool: return False except Exception as e: - verbose_proxy_logger.error(f"Error checking CloudZero setup: {e}") + verbose_proxy_logger.error("Error checking CloudZero setup: %s", e) return False @@ -364,7 +364,7 @@ async def init_cloudzero_settings( return CloudZeroInitResponse(message="CloudZero settings initialized successfully", status="success") except Exception as e: - verbose_proxy_logger.error(f"Error initializing CloudZero settings: {e}") + verbose_proxy_logger.error("Error initializing CloudZero settings: %s", e) raise HTTPException( status_code=500, detail={"error": f"Failed to initialize CloudZero settings: {e}"}, @@ -422,7 +422,7 @@ async def cloudzero_dry_run_export( ) except Exception as e: - verbose_proxy_logger.error(f"Error performing CloudZero dry run export: {e}") + verbose_proxy_logger.error("Error performing CloudZero dry run export: %s", e) raise HTTPException( status_code=500, detail={"error": f"Failed to perform CloudZero dry run export: {e}"}, @@ -487,7 +487,7 @@ async def cloudzero_export( ) except Exception as e: - verbose_proxy_logger.error(f"Error performing CloudZero export: {e}") + verbose_proxy_logger.error("Error performing CloudZero export: %s", e) raise HTTPException( status_code=500, detail={"error": f"Failed to perform CloudZero export: {e}"}, @@ -550,7 +550,7 @@ async def delete_cloudzero_settings( except HTTPException as e: raise e except Exception as e: - verbose_proxy_logger.error(f"Error deleting CloudZero settings: {e}") + verbose_proxy_logger.error("Error deleting CloudZero settings: %s", e) raise HTTPException( status_code=500, detail={"error": f"Failed to delete CloudZero settings: {e}"}, diff --git a/litellm/proxy/spend_tracking/spend_management_endpoints.py b/litellm/proxy/spend_tracking/spend_management_endpoints.py index 0bcc2b9994b..aa26a45ae0e 100644 --- a/litellm/proxy/spend_tracking/spend_management_endpoints.py +++ b/litellm/proxy/spend_tracking/spend_management_endpoints.py @@ -1648,7 +1648,7 @@ async def _get_spend_report_for_time_range( return response, spend_per_tag except Exception as e: - verbose_proxy_logger.error(f"Exception in _get_daily_spend_reports {e}") + verbose_proxy_logger.error("Exception in _get_daily_spend_reports %s", e) @router.post( @@ -2261,7 +2261,7 @@ async def ui_view_spend_logs( total_is_capped=total_is_capped, ) except Exception as e: - verbose_proxy_logger.exception(f"Error in ui_view_spend_logs: {e}") + verbose_proxy_logger.exception("Error in ui_view_spend_logs: %s", e) raise handle_exception_on_proxy(e) @@ -2789,7 +2789,7 @@ async def global_spend_refresh(): } except Exception as e: - verbose_proxy_logger.exception(f"Failed to refresh materialized view - {e}") + verbose_proxy_logger.exception("Failed to refresh materialized view - %s", e) return { "message": "Failed to refresh materialized view", "status": "failure", @@ -2830,7 +2830,7 @@ async def global_spend_for_internal_user( return response except Exception as e: - verbose_proxy_logger.error(f"/global/spend/logs Error: {e}") + verbose_proxy_logger.error("/global/spend/logs Error: %s", e) raise e @@ -2906,7 +2906,7 @@ async def global_spend_logs( except Exception as e: error_trace = traceback.format_exc() error_str = str(e) + "\n" + error_trace - verbose_proxy_logger.error(f"/global/spend/logs Error: {error_str}") + verbose_proxy_logger.error("/global/spend/logs Error: %s", error_str) if isinstance(e, HTTPException): raise ProxyException( message=getattr(e, "detail", f"/global/spend/logs Error({error_str})"), @@ -3387,7 +3387,7 @@ async def provider_budgets() -> ProviderBudgetResponse: provider_budget_response_dict[_provider] = provider_budget_response_object return ProviderBudgetResponse(providers=provider_budget_response_dict) except Exception as e: - verbose_proxy_logger.exception(f"/provider/budgets: Exception occured - {e}") + verbose_proxy_logger.exception("/provider/budgets: Exception occured - %s", e) raise handle_exception_on_proxy(e) diff --git a/litellm/proxy/spend_tracking/vantage_endpoints.py b/litellm/proxy/spend_tracking/vantage_endpoints.py index ac45594de22..d965a150ac1 100644 --- a/litellm/proxy/spend_tracking/vantage_endpoints.py +++ b/litellm/proxy/spend_tracking/vantage_endpoints.py @@ -166,7 +166,7 @@ async def get_vantage_settings( except HTTPException: raise except Exception as e: - verbose_proxy_logger.error(f"Error retrieving Vantage settings: {e}") + verbose_proxy_logger.error("Error retrieving Vantage settings: %s", e) raise HTTPException( status_code=500, detail={"error": f"Failed to retrieve Vantage settings: {e}"}, @@ -235,7 +235,7 @@ async def update_vantage_settings( except HTTPException: raise except Exception as e: - verbose_proxy_logger.error(f"Error updating Vantage settings: {e}") + verbose_proxy_logger.error("Error updating Vantage settings: %s", e) raise HTTPException( status_code=500, detail={"error": f"Failed to update Vantage settings: {e}"}, @@ -257,7 +257,7 @@ async def is_vantage_setup_in_db() -> bool: return vantage_config is not None and vantage_config.param_value is not None except Exception as e: - verbose_proxy_logger.error(f"Error checking Vantage status: {e}") + verbose_proxy_logger.error("Error checking Vantage status: %s", e) return False @@ -280,7 +280,7 @@ async def is_vantage_setup() -> bool: return True return False except Exception as e: - verbose_proxy_logger.error(f"Error checking Vantage setup: {e}") + verbose_proxy_logger.error("Error checking Vantage setup: %s", e) return False @@ -324,7 +324,7 @@ async def init_vantage_settings( except HTTPException: raise except Exception as e: - verbose_proxy_logger.error(f"Error initializing Vantage settings: {e}") + verbose_proxy_logger.error("Error initializing Vantage settings: %s", e) raise HTTPException( status_code=500, detail={"error": f"Failed to initialize Vantage settings: {e}"}, @@ -415,7 +415,7 @@ async def vantage_dry_run_export( except HTTPException: raise except Exception as e: - verbose_proxy_logger.error(f"Error performing Vantage dry run export: {e}") + verbose_proxy_logger.error("Error performing Vantage dry run export: %s", e) raise HTTPException( status_code=500, detail={"error": f"Failed to perform Vantage dry run export: {e}"}, @@ -488,7 +488,7 @@ async def vantage_export( except HTTPException: raise except Exception as e: - verbose_proxy_logger.error(f"Error performing Vantage export: {e}") + verbose_proxy_logger.error("Error performing Vantage export: %s", e) raise HTTPException( status_code=500, detail={"error": f"Failed to perform Vantage export: {e}"}, @@ -548,7 +548,7 @@ async def delete_vantage_settings( except HTTPException: raise except Exception as e: - verbose_proxy_logger.error(f"Error deleting Vantage settings: {e}") + verbose_proxy_logger.error("Error deleting Vantage settings: %s", e) raise HTTPException( status_code=500, detail={"error": f"Failed to delete Vantage settings: {e}"}, diff --git a/litellm/proxy/types_utils/utils.py b/litellm/proxy/types_utils/utils.py index e61fcdd859b..ae2bdbc5895 100644 --- a/litellm/proxy/types_utils/utils.py +++ b/litellm/proxy/types_utils/utils.py @@ -127,8 +127,11 @@ def _load_instance_from_remote_storage(remote_url: str, config_file_path: str | object_key = f"{module_path}.py" verbose_proxy_logger.debug( - f"Loading custom logger from {storage_type}: bucket={bucket_name}, " - f"object_key={object_key}, instance={instance_name}" + "Loading custom logger from %s: bucket=%s, object_key=%s, instance=%s", + storage_type, + bucket_name, + object_key, + instance_name, ) import tempfile @@ -170,9 +173,9 @@ def _load_instance_from_remote_storage(remote_url: str, config_file_path: str | try: os.remove(local_file_path) except Exception as cleanup_error: - verbose_proxy_logger.warning(f"Could not clean up temporary file {local_file_path}: {cleanup_error}") + verbose_proxy_logger.warning("Could not clean up temporary file %s: %s", local_file_path, cleanup_error) - verbose_proxy_logger.info(f"Successfully loaded custom logger from {remote_url}") + verbose_proxy_logger.info("Successfully loaded custom logger from %s", remote_url) return instance except Exception as e: @@ -190,7 +193,7 @@ async def _download_gcs_file_wrapper(bucket_name: str, object_key: str, local_fi except Exception as e: from litellm._logging import verbose_proxy_logger - verbose_proxy_logger.error(f"Error downloading from GCS: {e}") + verbose_proxy_logger.error("Error downloading from GCS: %s", e) return False diff --git a/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py b/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py index 8ed848ac1bf..22759a37ae7 100644 --- a/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py +++ b/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py @@ -689,7 +689,10 @@ async def update_default_team_member_budget(teams: list[NewUserRequestTeam], use ) except Exception as e: verbose_proxy_logger.info( - f"Error updating team {team_id} with team member budget {max_budget_in_team} with error: {e}, skipping.." + "Error updating team %s with team member budget %s with error: %s, skipping..", + team_id, + max_budget_in_team, + e, ) continue @@ -1209,7 +1212,7 @@ async def update_mcp_semantic_filter_settings( if prisma_client is not None: await proxy_config._init_semantic_filter_settings_in_db(prisma_client=prisma_client) except Exception as e: - verbose_proxy_logger.warning(f"Failed to reinitialize MCP semantic filter settings immediately: {e}") + verbose_proxy_logger.warning("Failed to reinitialize MCP semantic filter settings immediately: %s", e) return result diff --git a/litellm/proxy/utils.py b/litellm/proxy/utils.py index 5f18189b6b3..51c9b300b6e 100644 --- a/litellm/proxy/utils.py +++ b/litellm/proxy/utils.py @@ -196,7 +196,7 @@ def print_verbose(print_statement): """ import traceback - verbose_proxy_logger.debug(f"{print_statement}\n{traceback.format_exc()}") + verbose_proxy_logger.debug("%s\n%s", print_statement, traceback.format_exc()) if litellm.set_verbose: print(f"LiteLLM Proxy: {_redact_string(str(print_statement))}") # noqa: T201 @@ -722,11 +722,11 @@ class ProxyLogging: else: # Could not parse modified arguments, allow original call but warn verbose_proxy_logger.warning( - f"Could not parse modified arguments from guardrail response: {new_content}" + "Could not parse modified arguments from guardrail response: %s", new_content ) return None except Exception as e: - verbose_proxy_logger.error(f"Error parsing modified arguments: {e}") + verbose_proxy_logger.error("Error parsing modified arguments: %s", e) # Fallback: allow original call return None @@ -742,7 +742,7 @@ class ProxyLogging: """ import json - verbose_proxy_logger.debug(f"Extracting modified args from content: {masked_content}") + verbose_proxy_logger.debug("Extracting modified args from content: %s", masked_content) try: # The format should be: "Tool: \nArguments: " @@ -753,16 +753,16 @@ class ProxyLogging: # Get the arguments part - everything after "Arguments: " args_text = line[len("Arguments:") :].strip() - verbose_proxy_logger.debug(f"Found arguments text: {args_text}") + verbose_proxy_logger.debug("Found arguments text: %s", args_text) # Try to parse as JSON first try: modified_args = json.loads(args_text) - verbose_proxy_logger.debug(f"Successfully parsed JSON args: {modified_args}") + verbose_proxy_logger.debug("Successfully parsed JSON args: %s", modified_args) return modified_args except json.JSONDecodeError as e: # If JSON parsing fails, try to extract key-value pairs manually - verbose_proxy_logger.debug(f"Failed to parse JSON arguments: {args_text}, error: {e}") + verbose_proxy_logger.debug("Failed to parse JSON arguments: %s, error: %s", args_text, e) return self._parse_arguments_manually(args_text, request_obj.arguments) # If we can't find the Arguments: line, return None @@ -770,7 +770,7 @@ class ProxyLogging: return None except Exception as e: - verbose_proxy_logger.error(f"Error extracting modified arguments: {e}") + verbose_proxy_logger.error("Error extracting modified arguments: %s", e) return None def _parse_arguments_manually(self, args_text: str, original_args: dict) -> dict | None: @@ -799,7 +799,7 @@ class ProxyLogging: return modified_args except Exception as e: - verbose_proxy_logger.error(f"Error in manual argument parsing: {e}") + verbose_proxy_logger.error("Error in manual argument parsing: %s", e) return None def _convert_llm_result_to_mcp_during_response(self, llm_result, request_obj) -> Any | None: @@ -2174,10 +2174,10 @@ class ProxyLogging: except Exception as e: # Log non-HTTPException errors from callbacks but don't break the flow verbose_proxy_logger.exception( - f"[Non-Blocking] Error in async_post_call_failure_hook callback: {e}" + "[Non-Blocking] Error in async_post_call_failure_hook callback: %s", e ) except Exception as e: - verbose_proxy_logger.exception(f"[Non-Blocking] Error setting up post_call_failure_hook callback: {e}") + verbose_proxy_logger.exception("[Non-Blocking] Error setting up post_call_failure_hook callback: %s", e) return transformed_exception @@ -3019,7 +3019,7 @@ class PrismaClient: try: from prisma import Prisma # type: ignore except Exception as e: - verbose_proxy_logger.error(f"Failed to import Prisma client: {e}") + verbose_proxy_logger.error("Failed to import Prisma client: %s", e) verbose_proxy_logger.error("This usually means 'prisma generate' hasn't been run yet.") verbose_proxy_logger.error("Please run 'prisma generate' to generate the Prisma client.") raise Exception("Unable to find Prisma binaries. Please run 'prisma generate' first.") @@ -3283,7 +3283,8 @@ class PrismaClient: missing_views = expected_views_set - ret_view_names_set verbose_proxy_logger.warning( - f"\n\n\033[93mNot all views exist in db, needed for UI 'Usage' tab. Missing={missing_views}.\nRun 'create_views.py' from https://github.com/BerriAI/litellm/tree/main/db_scripts to create missing views.\033[0m\n" + "\n\n\x1b[93mNot all views exist in db, needed for UI 'Usage' tab. Missing=%s.\nRun 'create_views.py' from https://github.com/BerriAI/litellm/tree/main/db_scripts to create missing views.\x1b[0m\n", + missing_views, ) except Exception: @@ -3444,7 +3445,7 @@ class PrismaClient: if token is not None: if isinstance(token, str): hashed_token = _hash_token_if_needed(token=token) - verbose_proxy_logger.debug(f"PrismaClient: find_unique for token: {hashed_token}") + verbose_proxy_logger.debug("PrismaClient: find_unique for token: %s", hashed_token) if query_type == "find_unique" and hashed_token is not None: if token is None: raise HTTPException( @@ -3687,7 +3688,7 @@ class PrismaClient: if token is not None: if isinstance(token, str): hashed_token = _hash_token_if_needed(token=token) - verbose_proxy_logger.debug(f"PrismaClient: find_unique for token: {hashed_token}") + verbose_proxy_logger.debug("PrismaClient: find_unique for token: %s", hashed_token) if query_type == "find_unique": if token is None: raise HTTPException( @@ -3994,7 +3995,7 @@ class PrismaClient: """ Update existing data """ - verbose_proxy_logger.debug(f"PrismaClient: update_data, table_name: {table_name}") + verbose_proxy_logger.debug("PrismaClient: update_data, table_name: %s", table_name) start_time = time.time() try: db_data = self.jsonify_object(data=data) @@ -5062,7 +5063,7 @@ class PrismaClient: try: return await _fetch_row_count() except Exception as e: - verbose_proxy_logger.error(f"Error getting LiteLLM_SpendLogs row count: {e}") + verbose_proxy_logger.error("Error getting LiteLLM_SpendLogs row count: %s", e) return 0 @backoff.on_exception( @@ -5095,7 +5096,7 @@ class PrismaClient: value = float(response_time_ms) return value if value == value and value not in (float("inf"), float("-inf")) else None except (ValueError, TypeError): - verbose_proxy_logger.warning(f"Invalid response_time_ms value: {response_time_ms}") + verbose_proxy_logger.warning("Invalid response_time_ms value: %s", response_time_ms) return None def _clean_details(self, details: dict | None) -> dict | None: @@ -5105,7 +5106,7 @@ class PrismaClient: try: return safe_json_loads(safe_dumps(details)) except Exception as e: - verbose_proxy_logger.warning(f"Failed to clean details JSON: {e}") + verbose_proxy_logger.warning("Failed to clean details JSON: %s", e) return None async def save_health_check_result( @@ -5142,11 +5143,11 @@ class PrismaClient: # Add only non-None optional fields health_check_data.update({k: v for k, v in optional_fields.items() if v is not None}) - verbose_proxy_logger.debug(f"Saving health check data: {health_check_data}") + verbose_proxy_logger.debug("Saving health check data: %s", health_check_data) return await HealthCheckRepository(self).table.create(data=health_check_data) except Exception as e: - verbose_proxy_logger.error(f"Error saving health check result for model {model_name}: {e}") + verbose_proxy_logger.error("Error saving health check result for model %s: %s", model_name, e) return None async def get_health_check_history( @@ -5174,7 +5175,7 @@ class PrismaClient: ) return results except Exception as e: - verbose_proxy_logger.error(f"Error getting health check history: {e}") + verbose_proxy_logger.error("Error getting health check history: %s", e) return [] async def get_all_latest_health_checks(self): @@ -5194,7 +5195,7 @@ class PrismaClient: ], ) except Exception as e: - verbose_proxy_logger.error(f"Error getting all latest health checks: {e}") + verbose_proxy_logger.error("Error getting all latest health checks: %s", e) return [] @@ -5451,7 +5452,7 @@ class ProxyUpdateSpend: if len(logs_to_process) > 0 and base_url is not None and db_writer_client is not None: if not base_url.endswith("/"): base_url += "/" - verbose_proxy_logger.debug(f"base_url: {base_url}") + verbose_proxy_logger.debug("base_url: %s", base_url) json_data = json.dumps(logs_to_process) response = await db_writer_client.post( url=base_url + "spend/update", @@ -5475,7 +5476,7 @@ class ProxyUpdateSpend: statement_rows, isolation_budget, ) - verbose_proxy_logger.debug(f"Flushed {len(batch)} logs to the DB.") + verbose_proxy_logger.debug("Flushed %s logs to the DB.", len(batch)) # Explicitly clear batch memory del batch, batch_with_dates @@ -5483,7 +5484,7 @@ class ProxyUpdateSpend: async with prisma_client._spend_log_transactions_lock: remaining_count = len(prisma_client.spend_log_transactions) verbose_proxy_logger.debug( - f"{len(logs_to_process)} logs processed. Remaining in queue: {remaining_count}" + "%s logs processed. Remaining in queue: %s", len(logs_to_process), remaining_count ) break except DB_CONNECTION_ERROR_TYPES as e: @@ -5551,7 +5552,7 @@ async def update_spend( # Check queue size with lock protection async with prisma_client._spend_log_transactions_lock: queue_size = len(prisma_client.spend_log_transactions) - verbose_proxy_logger.debug(f"Spend Logs transactions: {queue_size}") + verbose_proxy_logger.debug("Spend Logs transactions: %s", queue_size) async with prisma_client._tool_usage_transactions_lock: tool_usage_queue_size = len(prisma_client.tool_usage_transactions) @@ -5611,7 +5612,7 @@ async def update_daily_tag_spend( # the active exception's traceback whenever the suppression env var # is unset, which would be a regression for operators who never saw # one here before. - verbose_proxy_logger.error(f"Error updating daily tag spend: {e}") + verbose_proxy_logger.error("Error updating daily tag spend: %s", e) async def update_spend_logs_job( @@ -5713,7 +5714,7 @@ async def _monitor_spend_logs_queue( current_interval = base_interval verbose_proxy_logger.info( - f"Starting spend logs queue monitor (threshold: {threshold}, poll_interval: {base_interval}s)" + "Starting spend logs queue monitor (threshold: %s, poll_interval: %ss)", threshold, base_interval ) while True: @@ -5729,13 +5730,17 @@ async def _monitor_spend_logs_queue( if queue_size > 0: if queue_size >= threshold: verbose_proxy_logger.debug( - f"Spend logs queue size ({queue_size}) reached threshold ({threshold}), triggering processing" + "Spend logs queue size (%s) reached threshold (%s), triggering processing", + queue_size, + threshold, ) # Reset to base interval when threshold is reached current_interval = base_interval else: verbose_proxy_logger.debug( - f"Spend logs queue size ({queue_size}) below threshold ({threshold}), processing with backoff" + "Spend logs queue size (%s) below threshold (%s), processing with backoff", + queue_size, + threshold, ) # Exponential backoff when below threshold but still processing current_interval = min(current_interval * backoff_multiplier, max_backoff) @@ -6121,7 +6126,7 @@ def handle_exception_on_proxy(e: Exception) -> ProxyException: """ from fastapi import status - verbose_proxy_logger.exception(f"Exception: {e}") + verbose_proxy_logger.exception("Exception: %s", e) if isinstance(e, HTTPException): return ProxyException( diff --git a/litellm/proxy/vector_store_endpoints/management_endpoints.py b/litellm/proxy/vector_store_endpoints/management_endpoints.py index 6176ae03d3d..d6d3392a7b4 100644 --- a/litellm/proxy/vector_store_endpoints/management_endpoints.py +++ b/litellm/proxy/vector_store_endpoints/management_endpoints.py @@ -207,11 +207,11 @@ def _resolve_embedding_config_from_router(embedding_model: str, llm_router) -> d # Only return config if we have at least api_key or api_base if embedding_config: verbose_proxy_logger.debug( - f"Resolved embedding config from router model {model_name}: {list(embedding_config.keys())}" + "Resolved embedding config from router model %s: %s", model_name, list(embedding_config.keys()) ) return embedding_config except Exception as e: - verbose_proxy_logger.debug(f"Error resolving embedding config from router for model {model_name}: {e}") + verbose_proxy_logger.debug("Error resolving embedding config from router for model %s: %s", model_name, e) continue return None @@ -295,11 +295,13 @@ async def _resolve_embedding_config_from_db(embedding_model: str, prisma_client) # Only return config if we have at least api_key or api_base if embedding_config: verbose_proxy_logger.debug( - f"Resolved embedding config from database model {model_name}: {list(embedding_config.keys())}" + "Resolved embedding config from database model %s: %s", + model_name, + list(embedding_config.keys()), ) return embedding_config except Exception as e: - verbose_proxy_logger.debug(f"Error resolving embedding config for model {model_name}: {e}") + verbose_proxy_logger.debug("Error resolving embedding config for model %s: %s", model_name, e) continue return None @@ -344,7 +346,7 @@ async def _resolve_embedding_config(embedding_model: str, prisma_client, llm_rou if llm_router is not None: router_config = _resolve_embedding_config_from_router(embedding_model=embedding_model, llm_router=llm_router) if router_config: - verbose_proxy_logger.debug(f"Resolved embedding config from router for model {embedding_model}") + verbose_proxy_logger.debug("Resolved embedding config from router for model %s", embedding_model) cache.set_cache(embedding_model, router_config) return router_config @@ -354,12 +356,12 @@ async def _resolve_embedding_config(embedding_model: str, prisma_client, llm_rou embedding_model=embedding_model, prisma_client=prisma_client ) if db_config: - verbose_proxy_logger.debug(f"Resolved embedding config from database for model {embedding_model}") + verbose_proxy_logger.debug("Resolved embedding config from database for model %s", embedding_model) cache.set_cache(embedding_model, db_config) return db_config verbose_proxy_logger.debug( - f"Could not resolve embedding config for model {embedding_model} from router or database" + "Could not resolve embedding config for model %s from router or database", embedding_model ) return None @@ -469,7 +471,7 @@ async def create_vector_store_in_db( if litellm.vector_store_registry is not None: litellm.vector_store_registry.add_vector_store_to_registry(vector_store=new_vector_store) - verbose_proxy_logger.info(f"Vector store {vector_store_id} created in database successfully") + verbose_proxy_logger.info("Vector store %s created in database successfully", vector_store_id) return new_vector_store @@ -542,7 +544,7 @@ async def new_vector_store( "vector_store": response_vs, } except Exception as e: - verbose_proxy_logger.exception(f"Error creating vector store: {e}") + verbose_proxy_logger.exception("Error creating vector store: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -604,7 +606,8 @@ async def list_vector_stores( # If vector store is in memory but NOT in database, it was deleted if vector_store_id not in db_vector_store_ids: verbose_proxy_logger.info( - f"Vector store {vector_store_id} exists in memory but not in database - marking for deletion from cache" + "Vector store %s exists in memory but not in database - marking for deletion from cache", + vector_store_id, ) vector_stores_to_delete_from_memory.append(vector_store_id) # If not in our map yet, add it (only in-memory, not in DB) @@ -615,7 +618,7 @@ async def list_vector_stores( # 1. Remove deleted vector stores from memory for vs_id in vector_stores_to_delete_from_memory: litellm.vector_store_registry.delete_vector_store_from_registry(vector_store_id=vs_id) - verbose_proxy_logger.debug(f"Removed deleted vector store {vs_id} from in-memory registry") + verbose_proxy_logger.debug("Removed deleted vector store %s from in-memory registry", vs_id) # 2. Update in-memory registry with database versions (for updates) for vector_store in vector_stores_from_db: @@ -647,7 +650,7 @@ async def list_vector_stores( return response except Exception as e: - verbose_proxy_logger.exception(f"Error listing vector stores: {e}") + verbose_proxy_logger.exception("Error listing vector stores: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -727,7 +730,7 @@ async def delete_vector_store( except HTTPException: raise except Exception as e: - verbose_proxy_logger.exception(f"Error deleting vector store: {e}") + verbose_proxy_logger.exception("Error deleting vector store: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -799,7 +802,7 @@ async def get_vector_store_info( # the catch-all below would otherwise rewrite them as 500. raise except Exception as e: - verbose_proxy_logger.exception(f"Error getting vector store info: {e}") + verbose_proxy_logger.exception("Error getting vector store info: %s", e) raise HTTPException(status_code=500, detail=str(e)) @@ -868,7 +871,7 @@ async def update_vector_store( updated_data=updated_vs, ) verbose_proxy_logger.debug( - f"Updated vector store {vector_store_id} in both database and in-memory registry" + "Updated vector store %s in both database and in-memory registry", vector_store_id ) # The DB row is returned in full, so the response would otherwise @@ -888,5 +891,5 @@ async def update_vector_store( # as 500 with the original status code embedded in the detail. raise except Exception as e: - verbose_proxy_logger.exception(f"Error updating vector store: {e}") + verbose_proxy_logger.exception("Error updating vector store: %s", e) raise HTTPException(status_code=500, detail=str(e)) diff --git a/litellm/proxy/vector_store_files_endpoints/endpoints.py b/litellm/proxy/vector_store_files_endpoints/endpoints.py index 06bcc524ea7..feaefece266 100644 --- a/litellm/proxy/vector_store_files_endpoints/endpoints.py +++ b/litellm/proxy/vector_store_files_endpoints/endpoints.py @@ -71,7 +71,7 @@ def _update_request_data_with_managed_file_id( if decoded_id: # This is a unified managed file ID - verbose_logger.debug(f"Processing unified managed file ID: {file_id}") + verbose_logger.debug("Processing unified managed file ID: %s", file_id) # Parse the unified ID to extract components parsed_id = parse_unified_id(file_id) @@ -90,7 +90,9 @@ def _update_request_data_with_managed_file_id( pass verbose_logger.debug( - f"Decoded unified file ID - target_model_names: {target_model_names}, llm_output_file_id: {llm_output_file_id}" + "Decoded unified file ID - target_model_names: %s, llm_output_file_id: %s", + target_model_names, + llm_output_file_id, ) # Set the model for routing @@ -108,14 +110,17 @@ def _update_request_data_with_managed_file_id( file_id=llm_output_file_id, # Use the actual provider file ID ) verbose_logger.info( - f"Routing vector store file operation to model: {routing_model}, file_id: {file_id} -> {llm_output_file_id}" + "Routing vector store file operation to model: %s, file_id: %s -> %s", + routing_model, + file_id, + llm_output_file_id, ) return data, file_id # Return original managed file ID # If we extracted the provider file ID but no routing, still use it if llm_output_file_id: data["file_id"] = llm_output_file_id - verbose_logger.debug(f"Replaced unified file ID with provider file ID: {llm_output_file_id}") + verbose_logger.debug("Replaced unified file ID with provider file ID: %s", llm_output_file_id) return data, file_id # Return original managed file ID return data, file_id if decoded_id else None @@ -361,7 +366,7 @@ def _update_request_data_with_litellm_managed_vector_store_registry( if decoded_id: # This is a managed vector store - decode and extract routing information - verbose_logger.debug(f"Processing managed vector store ID: {vector_store_id}") + verbose_logger.debug("Processing managed vector store ID: %s", vector_store_id) parsed_id = parse_unified_id(vector_store_id) @@ -371,7 +376,10 @@ def _update_request_data_with_litellm_managed_vector_store_registry( target_model_names = parsed_id.get("target_model_names", []) verbose_logger.debug( - f"Decoded vector store - model_id: {model_id}, provider_resource_id: {provider_resource_id}, target_model_names: {target_model_names}" + "Decoded vector store - model_id: %s, provider_resource_id: %s, target_model_names: %s", + model_id, + provider_resource_id, + target_model_names, ) # Set the model for routing - this tells the router which deployment to use @@ -384,13 +392,13 @@ def _update_request_data_with_litellm_managed_vector_store_registry( if routing_model: data["model"] = routing_model - verbose_logger.info(f"Routing vector store files operation to model: {routing_model}") + verbose_logger.info("Routing vector store files operation to model: %s", routing_model) # Replace unified vector store ID with provider resource ID if provider_resource_id: data["vector_store_id"] = provider_resource_id verbose_logger.debug( - f"Replaced unified vector store ID with provider resource ID: {provider_resource_id}" + "Replaced unified vector store ID with provider resource ID: %s", provider_resource_id ) return data diff --git a/litellm/rag/ingestion/base_ingestion.py b/litellm/rag/ingestion/base_ingestion.py index 76e6a4c574c..201baa2f471 100644 --- a/litellm/rag/ingestion/base_ingestion.py +++ b/litellm/rag/ingestion/base_ingestion.py @@ -365,7 +365,7 @@ class BaseRAGIngestion(ABC): ) except Exception as e: - verbose_logger.exception(f"RAG Pipeline failed: {e}") + verbose_logger.exception("RAG Pipeline failed: %s", e) return RAGIngestResponse( id=self.ingest_id, status="failed", diff --git a/litellm/rag/ingestion/bedrock_ingestion.py b/litellm/rag/ingestion/bedrock_ingestion.py index 10dc3af4319..45a3b64810f 100644 --- a/litellm/rag/ingestion/bedrock_ingestion.py +++ b/litellm/rag/ingestion/bedrock_ingestion.py @@ -138,7 +138,7 @@ class BedrockRAGIngestion(BaseRAGIngestion, BaseAWSLLM): def _auto_detect_config(self): """Auto-detect data source ID and S3 bucket from existing Knowledge Base.""" - verbose_logger.debug(f"Auto-detecting data source and S3 bucket for KB={self.knowledge_base_id}") + verbose_logger.debug("Auto-detecting data source and S3 bucket for KB=%s", self.knowledge_base_id) bedrock_agent = self._get_boto3_client("bedrock-agent") @@ -157,7 +157,7 @@ class BedrockRAGIngestion(BaseRAGIngestion, BaseAWSLLM): self.data_source_id = self._data_source_id else: self.data_source_id = data_sources[0]["dataSourceId"] - verbose_logger.info(f"Auto-detected data source: {self.data_source_id}") + verbose_logger.info("Auto-detected data source: %s", self.data_source_id) # Get data source details for S3 bucket ds_details = bedrock_agent.get_data_source( @@ -171,7 +171,7 @@ class BedrockRAGIngestion(BaseRAGIngestion, BaseAWSLLM): if bucket_arn: # Extract bucket name from ARN: arn:aws:s3:::bucket-name self.s3_bucket = self._s3_bucket or bucket_arn.split(":")[-1] - verbose_logger.info(f"Auto-detected S3 bucket: {self.s3_bucket}") + verbose_logger.info("Auto-detected S3 bucket: %s", self.s3_bucket) # Use inclusion prefix if available prefixes = s3_config.get("inclusionPrefixes", []) @@ -218,8 +218,10 @@ class BedrockRAGIngestion(BaseRAGIngestion, BaseAWSLLM): self.data_source_id = self._create_data_source(kb_name) verbose_logger.info( - f"Created KB infrastructure: kb_id={self.knowledge_base_id}, " - f"ds_id={self.data_source_id}, bucket={self.s3_bucket}" + "Created KB infrastructure: kb_id=%s, ds_id=%s, bucket=%s", + self.knowledge_base_id, + self.data_source_id, + self.s3_bucket, ) def _create_s3_bucket(self, unique_id: str) -> str: @@ -227,7 +229,7 @@ class BedrockRAGIngestion(BaseRAGIngestion, BaseAWSLLM): s3 = self._get_boto3_client("s3") bucket_name = f"litellm-kb-{unique_id}" - verbose_logger.debug(f"Creating S3 bucket: {bucket_name}") + verbose_logger.debug("Creating S3 bucket: %s", bucket_name) create_params: dict[str, Any] = {"Bucket": bucket_name} if self.aws_region_name != "us-east-1": @@ -236,7 +238,7 @@ class BedrockRAGIngestion(BaseRAGIngestion, BaseAWSLLM): s3.create_bucket(**create_params) self._created_resources["s3_bucket"] = bucket_name - verbose_logger.info(f"Created S3 bucket: {bucket_name}") + verbose_logger.info("Created S3 bucket: %s", bucket_name) return bucket_name async def _create_opensearch_collection(self, unique_id: str, account_id: str, caller_arn: str) -> tuple[str, str]: @@ -244,7 +246,7 @@ class BedrockRAGIngestion(BaseRAGIngestion, BaseAWSLLM): oss = self._get_boto3_client("opensearchserverless") collection_name = f"litellm-kb-{unique_id}" - verbose_logger.debug(f"Creating OpenSearch Serverless collection: {collection_name}") + verbose_logger.debug("Creating OpenSearch Serverless collection: %s", collection_name) # Create encryption policy oss.create_security_policy( @@ -290,7 +292,7 @@ class BedrockRAGIngestion(BaseRAGIngestion, BaseAWSLLM): # This ensures the credentials being used have access to the collection # Normalize the caller ARN (convert assumed-role ARN to IAM role ARN if needed) normalized_caller_arn = _normalize_principal_arn(caller_arn, account_id) - verbose_logger.debug(f"Caller ARN: {caller_arn}, Normalized: {normalized_caller_arn}") + verbose_logger.debug("Caller ARN: %s, Normalized: %s", caller_arn, normalized_caller_arn) principals = [f"arn:aws:iam::{account_id}:root", normalized_caller_arn] # Deduplicate in case caller is root @@ -340,7 +342,7 @@ class BedrockRAGIngestion(BaseRAGIngestion, BaseAWSLLM): raise TimeoutError("OpenSearch collection did not become active in time") collection_arn = status_response["collectionDetails"][0]["arn"] - verbose_logger.info(f"Created OpenSearch collection: {collection_name}") + verbose_logger.info("Created OpenSearch collection: %s", collection_name) # Wait for data access policy to propagate before returning # AWS recommends waiting 60+ seconds for policy propagation @@ -412,15 +414,17 @@ class BedrockRAGIngestion(BaseRAGIngestion, BaseAWSLLM): for attempt in range(max_retries): try: client.indices.create(index=index_name, body=index_body) - verbose_logger.info(f"Created OpenSearch index: {index_name}") + verbose_logger.info("Created OpenSearch index: %s", index_name) return except Exception as e: last_error = e error_str = str(e) if "authorization_exception" in error_str.lower() or "security_exception" in error_str.lower(): verbose_logger.warning( - f"OpenSearch index creation attempt {attempt + 1}/{max_retries} failed due to authorization. " - f"Waiting {retry_delay}s for policy propagation..." + "OpenSearch index creation attempt %s/%s failed due to authorization. Waiting %ss for policy propagation...", + attempt + 1, + max_retries, + retry_delay, ) await asyncio.sleep(retry_delay) else: @@ -438,7 +442,7 @@ class BedrockRAGIngestion(BaseRAGIngestion, BaseAWSLLM): iam = self._get_boto3_client("iam") role_name = f"litellm-bedrock-kb-{unique_id}" - verbose_logger.debug(f"Creating IAM role: {role_name}") + verbose_logger.debug("Creating IAM role: %s", role_name) trust_policy = { "Version": "2012-10-17", @@ -498,14 +502,14 @@ class BedrockRAGIngestion(BaseRAGIngestion, BaseAWSLLM): # Wait for role to propagate (use asyncio.sleep to avoid blocking) await asyncio.sleep(10) - verbose_logger.info(f"Created IAM role: {role_arn}") + verbose_logger.info("Created IAM role: %s", role_arn) return role_arn async def _create_knowledge_base(self, kb_name: str, role_arn: str, collection_arn: str) -> str: """Create Bedrock Knowledge Base.""" bedrock_agent = self._get_boto3_client("bedrock-agent") - verbose_logger.debug(f"Creating Knowledge Base: {kb_name}") + verbose_logger.debug("Creating Knowledge Base: %s", kb_name) response = bedrock_agent.create_knowledge_base( name=kb_name, @@ -543,14 +547,14 @@ class BedrockRAGIngestion(BaseRAGIngestion, BaseAWSLLM): else: raise TimeoutError("Knowledge Base did not become active in time") - verbose_logger.info(f"Created Knowledge Base: {kb_id}") + verbose_logger.info("Created Knowledge Base: %s", kb_id) return kb_id def _create_data_source(self, kb_name: str) -> str: """Create Data Source for the Knowledge Base.""" bedrock_agent = self._get_boto3_client("bedrock-agent") - verbose_logger.debug(f"Creating Data Source for KB: {self.knowledge_base_id}") + verbose_logger.debug("Creating Data Source for KB: %s", self.knowledge_base_id) response = bedrock_agent.create_data_source( knowledgeBaseId=self.knowledge_base_id, @@ -566,7 +570,7 @@ class BedrockRAGIngestion(BaseRAGIngestion, BaseAWSLLM): ds_id = response["dataSource"]["dataSourceId"] self._created_resources["data_source"] = ds_id - verbose_logger.info(f"Created Data Source: {ds_id}") + verbose_logger.info("Created Data Source: %s", ds_id) return ds_id def _get_boto3_client(self, service_name: str): @@ -652,25 +656,25 @@ class BedrockRAGIngestion(BaseRAGIngestion, BaseAWSLLM): s3_client = self._get_boto3_client("s3") s3_key = f"{self.s3_prefix.rstrip('/')}/{filename}" - verbose_logger.debug(f"Uploading file to s3://{self.s3_bucket}/{s3_key}") + verbose_logger.debug("Uploading file to s3://%s/%s", self.s3_bucket, s3_key) s3_client.put_object( Bucket=self.s3_bucket, Key=s3_key, Body=file_content, ContentType=content_type or "application/octet-stream", ) - verbose_logger.info(f"Uploaded file to s3://{self.s3_bucket}/{s3_key}") + verbose_logger.info("Uploaded file to s3://%s/%s", self.s3_bucket, s3_key) # Step 2: Start ingestion job bedrock_agent = self._get_boto3_client("bedrock-agent") - verbose_logger.debug(f"Starting ingestion job for KB={self.knowledge_base_id}, DS={self.data_source_id}") + verbose_logger.debug("Starting ingestion job for KB=%s, DS=%s", self.knowledge_base_id, self.data_source_id) ingestion_response = bedrock_agent.start_ingestion_job( knowledgeBaseId=self.knowledge_base_id, dataSourceId=self.data_source_id, ) job_id = ingestion_response["ingestionJob"]["ingestionJobId"] - verbose_logger.info(f"Started ingestion job: {job_id}") + verbose_logger.info("Started ingestion job: %s", job_id) # Step 3: Wait for ingestion (optional) - use asyncio.sleep to avoid blocking if self.wait_for_ingestion: @@ -684,22 +688,22 @@ class BedrockRAGIngestion(BaseRAGIngestion, BaseAWSLLM): ingestionJobId=job_id, ) status = job_status["ingestionJob"]["status"] - verbose_logger.debug(f"Ingestion job {job_id} status: {status}") + verbose_logger.debug("Ingestion job %s status: %s", job_id, status) if status == "COMPLETE": stats = job_status["ingestionJob"].get("statistics", {}) verbose_logger.info( - f"Ingestion complete: {stats.get('numberOfNewDocumentsIndexed', 0)} docs indexed" + "Ingestion complete: %s docs indexed", stats.get("numberOfNewDocumentsIndexed", 0) ) break elif status == "FAILED": failure_reasons = job_status["ingestionJob"].get("failureReasons", []) - verbose_logger.error(f"Ingestion failed: {failure_reasons}") + verbose_logger.error("Ingestion failed: %s", failure_reasons) break elif status in ("STARTING", "IN_PROGRESS"): await asyncio.sleep(2) else: - verbose_logger.warning(f"Unknown ingestion status: {status}") + verbose_logger.warning("Unknown ingestion status: %s", status) break return str(self.knowledge_base_id) if self.knowledge_base_id else None, s3_key diff --git a/litellm/rag/ingestion/file_parsers/pdf_parser.py b/litellm/rag/ingestion/file_parsers/pdf_parser.py index 2b4e07b224f..0301c5d6e03 100644 --- a/litellm/rag/ingestion/file_parsers/pdf_parser.py +++ b/litellm/rag/ingestion/file_parsers/pdf_parser.py @@ -35,7 +35,7 @@ def extract_text_from_pdf(file_content: bytes) -> str | None: if text_parts: extracted_text = "\n\n".join(text_parts) - verbose_logger.debug(f"Extracted {len(extracted_text)} characters from PDF using pypdf") + verbose_logger.debug("Extracted %s characters from PDF using pypdf", len(extracted_text)) return extracted_text except ImportError: @@ -56,13 +56,13 @@ def extract_text_from_pdf(file_content: bytes) -> str | None: if text_parts: extracted_text = "\n\n".join(text_parts) - verbose_logger.debug(f"Extracted {len(extracted_text)} characters from PDF using PyPDF2") + verbose_logger.debug("Extracted %s characters from PDF using PyPDF2", len(extracted_text)) return extracted_text except ImportError: verbose_logger.debug("PyPDF2 not available, PDF extraction requires OCR or pypdf/PyPDF2 library") except Exception as e: - verbose_logger.debug(f"PDF text extraction failed: {e}") + verbose_logger.debug("PDF text extraction failed: %s", e) return None diff --git a/litellm/rag/ingestion/gemini_ingestion.py b/litellm/rag/ingestion/gemini_ingestion.py index 5722936b742..f007e6282b9 100644 --- a/litellm/rag/ingestion/gemini_ingestion.py +++ b/litellm/rag/ingestion/gemini_ingestion.py @@ -162,7 +162,7 @@ class GeminiRAGIngestion(BaseRAGIngestion): response_data = response.json() store_name = response_data.get("name", "") - verbose_logger.debug(f"Created File Search store: {store_name}") + verbose_logger.debug("Created File Search store: %s", store_name) return store_name async def _upload_to_file_search_store( @@ -259,7 +259,7 @@ class GeminiRAGIngestion(BaseRAGIngestion): "x-goog-api-key": api_key, } - verbose_logger.debug(f"Initiating resumable upload: {url}") + verbose_logger.debug("Initiating resumable upload: %s", url) client = get_async_httpx_client( llm_provider=httpxSpecialProvider.RAG, @@ -275,13 +275,13 @@ class GeminiRAGIngestion(BaseRAGIngestion): error_msg = f"Failed to initiate upload: {response.text}" verbose_logger.error(error_msg) raise Exception(error_msg) - verbose_logger.debug(f"Initiate resumable upload response: {response.headers}") + verbose_logger.debug("Initiate resumable upload response: %s", response.headers) # Extract upload URL from response headers upload_url = response.headers.get("x-goog-upload-url") if not upload_url: raise Exception("No upload URL returned in response headers") - verbose_logger.debug(f"Got upload URL: {upload_url}") + verbose_logger.debug("Got upload URL: %s", upload_url) return upload_url async def _upload_file_content( @@ -301,7 +301,7 @@ class GeminiRAGIngestion(BaseRAGIngestion): "X-Goog-Upload-Command": "upload, finalize", } - verbose_logger.debug(f"Uploading file content ({len(file_content)} bytes)") + verbose_logger.debug("Uploading file content (%s bytes)", len(file_content)) client = get_async_httpx_client( llm_provider=httpxSpecialProvider.RAG, @@ -323,9 +323,9 @@ class GeminiRAGIngestion(BaseRAGIngestion): response_data = response.json() # The response should contain the document name or file reference file_id = response_data.get("name", "") or response_data.get("file", {}).get("name", "") - verbose_logger.debug(f"Upload complete. File ID: {file_id}") + verbose_logger.debug("Upload complete. File ID: %s", file_id) return file_id except Exception as e: - verbose_logger.warning(f"Could not parse upload response: {e}") + verbose_logger.warning("Could not parse upload response: %s", e) # Return a placeholder if we can't get the ID return "uploaded" diff --git a/litellm/rag/ingestion/s3_vectors_ingestion.py b/litellm/rag/ingestion/s3_vectors_ingestion.py index 6abd0737ba6..b50e798a7c9 100644 --- a/litellm/rag/ingestion/s3_vectors_ingestion.py +++ b/litellm/rag/ingestion/s3_vectors_ingestion.py @@ -105,7 +105,7 @@ class S3VectorsRAGIngestion(BaseRAGIngestion, BaseAWSLLM): try: model_name = self.embedding_config["model"] - verbose_logger.debug(f"Auto-detecting dimension by making test embedding request to {model_name}") + verbose_logger.debug("Auto-detecting dimension by making test embedding request to %s", model_name) # Make a test embedding request test_input = "test" @@ -117,12 +117,13 @@ class S3VectorsRAGIngestion(BaseRAGIngestion, BaseAWSLLM): # Get dimension from the response if response.data and len(response.data) > 0: dimension = len(response.data[0]["embedding"]) - verbose_logger.debug(f"Auto-detected dimension {dimension} for embedding model {model_name}") + verbose_logger.debug("Auto-detected dimension %s for embedding model %s", dimension, model_name) return dimension except Exception as e: verbose_logger.warning( - f"Could not auto-detect dimension from embedding model: {e}. " - f"Using default dimension of {S3_VECTORS_DEFAULT_DIMENSION}." + "Could not auto-detect dimension from embedding model: %s. Using default dimension of %s.", + e, + S3_VECTORS_DEFAULT_DIMENSION, ) return S3_VECTORS_DEFAULT_DIMENSION @@ -236,7 +237,7 @@ class S3VectorsRAGIngestion(BaseRAGIngestion, BaseAWSLLM): async def _ensure_vector_bucket_exists(self): """Create vector bucket if it doesn't exist using GetVectorBucket and CreateVectorBucket APIs.""" - verbose_logger.debug(f"Ensuring S3 vector bucket exists: {self.vector_bucket_name}") + verbose_logger.debug("Ensuring S3 vector bucket exists: %s", self.vector_bucket_name) # Validate bucket name (AWS S3 naming rules) if len(self.vector_bucket_name) < 3: @@ -259,34 +260,34 @@ class S3VectorsRAGIngestion(BaseRAGIngestion, BaseAWSLLM): try: response = await self._sign_and_execute_request("POST", get_url, data=get_body) if response.status_code == 200: - verbose_logger.debug(f"Vector bucket {self.vector_bucket_name} exists") + verbose_logger.debug("Vector bucket %s exists", self.vector_bucket_name) return except Exception as e: - verbose_logger.debug(f"Bucket check failed (may not exist): {e}, attempting to create") + verbose_logger.debug("Bucket check failed (may not exist): %s, attempting to create", e) # Create vector bucket using CreateVectorBucket API try: - verbose_logger.debug(f"Creating vector bucket: {self.vector_bucket_name}") + verbose_logger.debug("Creating vector bucket: %s", self.vector_bucket_name) create_url = f"https://s3vectors.{self.aws_region_name}.api.aws/CreateVectorBucket" create_body = safe_dumps({"vectorBucketName": self.vector_bucket_name}) response = await self._sign_and_execute_request("POST", create_url, data=create_body) if response.status_code in (200, 201): - verbose_logger.info(f"Created vector bucket: {self.vector_bucket_name}") + verbose_logger.info("Created vector bucket: %s", self.vector_bucket_name) elif response.status_code == 409: # Bucket already exists (ConflictException) - verbose_logger.debug(f"Vector bucket {self.vector_bucket_name} already exists") + verbose_logger.debug("Vector bucket %s already exists", self.vector_bucket_name) else: - verbose_logger.error(f"CreateVectorBucket failed: {response.status_code} - {response.text}") + verbose_logger.error("CreateVectorBucket failed: %s - %s", response.status_code, response.text) response.raise_for_status() except Exception as e: - verbose_logger.exception(f"Error creating vector bucket: {e}") + verbose_logger.exception("Error creating vector bucket: %s", e) raise async def _ensure_vector_index_exists(self): """Create vector index if it doesn't exist using GetIndex and CreateIndex APIs.""" - verbose_logger.debug(f"Ensuring vector index exists: {self.vector_bucket_name}/{self.index_name}") + verbose_logger.debug("Ensuring vector index exists: %s/%s", self.vector_bucket_name, self.index_name) # Try to get index info using GetIndex API get_url = f"https://s3vectors.{self.aws_region_name}.api.aws/GetIndex" @@ -295,15 +296,18 @@ class S3VectorsRAGIngestion(BaseRAGIngestion, BaseAWSLLM): try: response = await self._sign_and_execute_request("POST", get_url, data=get_body) if response.status_code == 200: - verbose_logger.debug(f"Vector index {self.index_name} exists") + verbose_logger.debug("Vector index %s exists", self.index_name) return except Exception as e: - verbose_logger.debug(f"Index check failed (may not exist): {e}, attempting to create") + verbose_logger.debug("Index check failed (may not exist): %s, attempting to create", e) # Create vector index using CreateIndex API try: verbose_logger.debug( - f"Creating vector index: {self.index_name} with dimension={self.dimension}, metric={self.distance_metric}" + "Creating vector index: %s with dimension=%s, metric=%s", + self.index_name, + self.dimension, + self.distance_metric, ) # Prepare index configuration per AWS API docs @@ -322,14 +326,14 @@ class S3VectorsRAGIngestion(BaseRAGIngestion, BaseAWSLLM): response = await self._sign_and_execute_request("POST", create_url, data=safe_dumps(index_config)) if response.status_code in (200, 201): - verbose_logger.info(f"Created vector index: {self.index_name}") + verbose_logger.info("Created vector index: %s", self.index_name) elif response.status_code == 409: - verbose_logger.debug(f"Vector index {self.index_name} already exists") + verbose_logger.debug("Vector index %s already exists", self.index_name) else: - verbose_logger.error(f"CreateIndex failed: {response.status_code} - {response.text}") + verbose_logger.error("CreateIndex failed: %s - %s", response.status_code, response.text) response.raise_for_status() except Exception as e: - verbose_logger.exception(f"Error creating vector index: {e}") + verbose_logger.exception("Error creating vector index: %s", e) raise async def _put_vectors(self, vectors: list[dict[str, Any]]): @@ -339,7 +343,7 @@ class S3VectorsRAGIngestion(BaseRAGIngestion, BaseAWSLLM): Args: vectors: List of vector objects with keys: "key", "data", "metadata" """ - verbose_logger.debug(f"Storing {len(vectors)} vectors in {self.vector_bucket_name}/{self.index_name}") + verbose_logger.debug("Storing %s vectors in %s/%s", len(vectors), self.vector_bucket_name, self.index_name) url = f"https://s3vectors.{self.aws_region_name}.api.aws/PutVectors" @@ -354,12 +358,12 @@ class S3VectorsRAGIngestion(BaseRAGIngestion, BaseAWSLLM): response = await self._sign_and_execute_request("POST", url, data=safe_dumps(request_body)) if response.status_code in (200, 201): - verbose_logger.info(f"Successfully stored {len(vectors)} vectors in index {self.index_name}") + verbose_logger.info("Successfully stored %s vectors in index %s", len(vectors), self.index_name) else: - verbose_logger.error(f"PutVectors failed with status {response.status_code}: {response.text}") + verbose_logger.error("PutVectors failed with status %s: %s", response.status_code, response.text) response.raise_for_status() except Exception as e: - verbose_logger.exception(f"Error storing vectors: {e}") + verbose_logger.exception("Error storing vectors: %s", e) raise async def embed( @@ -381,7 +385,7 @@ class S3VectorsRAGIngestion(BaseRAGIngestion, BaseAWSLLM): embedding_model = self.embedding_config.get("model", "text-embedding-3-small") - verbose_logger.debug(f"Generating embeddings for {len(chunks)} chunks using {embedding_model}") + verbose_logger.debug("Generating embeddings for %s chunks using %s", len(chunks), embedding_model) # Convert to list to ensure type compatibility input_chunks: list[str] = list(chunks) @@ -476,7 +480,7 @@ class S3VectorsRAGIngestion(BaseRAGIngestion, BaseAWSLLM): Returns: Query results with vectors and metadata """ - verbose_logger.debug(f"Querying index {vector_store_id} with query: {query}") + verbose_logger.debug("Querying index %s with query: %s", vector_store_id, query) # Generate query embedding if not self.embedding_config: @@ -504,7 +508,7 @@ class S3VectorsRAGIngestion(BaseRAGIngestion, BaseAWSLLM): if response.status_code == 200: results = response.json() - verbose_logger.debug(f"Query returned {len(results.get('vectors', []))} results") + verbose_logger.debug("Query returned %s results", len(results.get("vectors", []))) # Check if query terms appear in results if results.get("vectors"): @@ -517,8 +521,8 @@ class S3VectorsRAGIngestion(BaseRAGIngestion, BaseAWSLLM): # Return results even if exact match not found return results else: - verbose_logger.error(f"QueryVectors failed with status {response.status_code}: {response.text}") + verbose_logger.error("QueryVectors failed with status %s: %s", response.status_code, response.text) return None except Exception as e: - verbose_logger.exception(f"Error querying vectors: {e}") + verbose_logger.exception("Error querying vectors: %s", e) return None diff --git a/litellm/rag/ingestion/vertex_ai_ingestion.py b/litellm/rag/ingestion/vertex_ai_ingestion.py index ababca1a955..43c3ed1ac29 100644 --- a/litellm/rag/ingestion/vertex_ai_ingestion.py +++ b/litellm/rag/ingestion/vertex_ai_ingestion.py @@ -169,8 +169,8 @@ class VertexAIRAGIngestion(BaseRAGIngestion, VertexBase): "vertexPredictionEndpoint": {"endpoint": embedding_model} } - verbose_logger.debug(f"Creating RAG corpus: {url}") - verbose_logger.debug(f"Request body: {json.dumps(request_body, indent=2)}") + verbose_logger.debug("Creating RAG corpus: %s", url) + verbose_logger.debug("Request body: %s", json.dumps(request_body, indent=2)) client = get_async_httpx_client( llm_provider=httpxSpecialProvider.RAG, @@ -191,7 +191,7 @@ class VertexAIRAGIngestion(BaseRAGIngestion, VertexBase): raise Exception(error_msg) response_data = response.json() - verbose_logger.debug(f"Create corpus response: {json.dumps(response_data, indent=2)}") + verbose_logger.debug("Create corpus response: %s", json.dumps(response_data, indent=2)) # The response is a long-running operation # Check if it's already done or if we need to poll @@ -201,13 +201,13 @@ class VertexAIRAGIngestion(BaseRAGIngestion, VertexBase): else: # Need to poll the operation operation_name = response_data.get("name", "") - verbose_logger.debug(f"Polling operation: {operation_name}") + verbose_logger.debug("Polling operation: %s", operation_name) corpus_name = await self._poll_operation( operation_name=operation_name, access_token=access_token, ) - verbose_logger.debug(f"Created RAG corpus: {corpus_name}") + verbose_logger.debug("Created RAG corpus: %s", corpus_name) return corpus_name async def _poll_operation( @@ -272,7 +272,7 @@ class VertexAIRAGIngestion(BaseRAGIngestion, VertexBase): else: raise Exception(f"No corpus name in operation response: {operation_data}") - verbose_logger.debug(f"Operation not done yet, attempt {attempt + 1}/{max_retries}") + verbose_logger.debug("Operation not done yet, attempt %s/%s", attempt + 1, max_retries) await asyncio.sleep(retry_delay) raise Exception(f"Operation timed out after {max_retries} attempts") @@ -342,8 +342,8 @@ class VertexAIRAGIngestion(BaseRAGIngestion, VertexBase): if chunk_overlap: chunking_config["chunk_overlap"] = chunk_overlap - verbose_logger.debug(f"Uploading file to RAG corpus: {url}") - verbose_logger.debug(f"Metadata: {json.dumps(metadata, indent=2)}") + verbose_logger.debug("Uploading file to RAG corpus: %s", url) + verbose_logger.debug("Metadata: %s", json.dumps(metadata, indent=2)) # Prepare multipart form data files = { @@ -381,10 +381,10 @@ class VertexAIRAGIngestion(BaseRAGIngestion, VertexBase): if not file_id: file_id = response_data.get("name", "") - verbose_logger.debug(f"Upload complete. File ID: {file_id}") + verbose_logger.debug("Upload complete. File ID: %s", file_id) return file_id except Exception as e: - verbose_logger.warning(f"Could not parse upload response: {e}") + verbose_logger.warning("Could not parse upload response: %s", e) return "uploaded" async def _import_files_from_gcs( @@ -433,8 +433,8 @@ class VertexAIRAGIngestion(BaseRAGIngestion, VertexBase): if max_embedding_qpm: request_body["importRagFilesConfig"]["maxEmbeddingRequestsPerMin"] = max_embedding_qpm - verbose_logger.debug(f"Importing files from GCS: {url}") - verbose_logger.debug(f"Request body: {json.dumps(request_body, indent=2)}") + verbose_logger.debug("Importing files from GCS: %s", url) + verbose_logger.debug("Request body: %s", json.dumps(request_body, indent=2)) client = get_async_httpx_client( llm_provider=httpxSpecialProvider.RAG, @@ -458,5 +458,5 @@ class VertexAIRAGIngestion(BaseRAGIngestion, VertexBase): response_data = response.json() operation_name = response_data.get("name", "") - verbose_logger.debug(f"Import operation started: {operation_name}") + verbose_logger.debug("Import operation started: %s", operation_name) return operation_name diff --git a/litellm/repositories/config_repository.py b/litellm/repositories/config_repository.py index bc3e7fbaf9f..5d2a6b1421d 100644 --- a/litellm/repositories/config_repository.py +++ b/litellm/repositories/config_repository.py @@ -197,7 +197,7 @@ class ConfigRepository: param_name = response.param_name param_value = response.param_value - verbose_proxy_logger.debug(f"param_name={param_name}, param_value={param_value}") + verbose_proxy_logger.debug("param_name=%s, param_value=%s", param_name, param_value) if param_name is not None and param_value is not None: config = self._update_config_fields( diff --git a/litellm/rerank_api/main.py b/litellm/rerank_api/main.py index 2733fed744a..aa7ade5fdd9 100644 --- a/litellm/rerank_api/main.py +++ b/litellm/rerank_api/main.py @@ -159,7 +159,7 @@ def rerank( instruction=instruction, non_default_params=kwargs, ) - verbose_logger.debug(f"optional_rerank_params: {optional_rerank_params}") + verbose_logger.debug("optional_rerank_params: %s", optional_rerank_params) if isinstance(optional_params.timeout, str): optional_params.timeout = float(optional_params.timeout) @@ -534,5 +534,5 @@ def rerank( # Placeholder return return response except Exception as e: - verbose_logger.error(f"Error in rerank: {e}") + verbose_logger.error("Error in rerank: %s", e) raise exception_type(model=model, custom_llm_provider=custom_llm_provider, original_exception=e) diff --git a/litellm/responses/mcp/chat_completions_handler.py b/litellm/responses/mcp/chat_completions_handler.py index 8c0328fe5f0..357c2d25c22 100644 --- a/litellm/responses/mcp/chat_completions_handler.py +++ b/litellm/responses/mcp/chat_completions_handler.py @@ -376,7 +376,7 @@ async def acompletion_with_mcp( chunk = await self.follow_up_iterator.__anext__() from litellm._logging import verbose_logger - verbose_logger.debug(f"Follow-up chunk yielded: {chunk}") + verbose_logger.debug("Follow-up chunk yielded: %s", chunk) return chunk except StopAsyncIteration: self.follow_up_exhausted = True @@ -476,7 +476,7 @@ async def acompletion_with_mcp( from litellm._logging import verbose_logger verbose_logger.warning( - f"Follow-up response is not a CustomStreamWrapper: {type(follow_up_response)}" + "Follow-up response is not a CustomStreamWrapper: %s", type(follow_up_response) ) self.follow_up_stream = None diff --git a/litellm/responses/mcp/litellm_proxy_mcp_handler.py b/litellm/responses/mcp/litellm_proxy_mcp_handler.py index 39881277a10..0777f86d52b 100644 --- a/litellm/responses/mcp/litellm_proxy_mcp_handler.py +++ b/litellm/responses/mcp/litellm_proxy_mcp_handler.py @@ -171,7 +171,7 @@ class LiteLLM_Proxy_MCP_Handler: ) return user_api_key_auth.model_copy(update={"object_permission": updated_op}) except Exception as _e: - verbose_logger.debug(f"Could not apply toolset permissions: {_e}") + verbose_logger.debug("Could not apply toolset permissions: %s", _e) return user_api_key_auth @staticmethod @@ -238,14 +238,16 @@ class LiteLLM_Proxy_MCP_Handler: # None means no grants configured → deny (consistent with # fetch_mcp_toolsets which returns [] for unconfigured keys) if granted is None or toolset.toolset_id not in granted: - verbose_logger.debug(f"Key does not have access to toolset '{name}', skipping.") + verbose_logger.debug( + "Key does not have access to toolset '%s', skipping.", name + ) continue resolved_toolset_ids.append(toolset.toolset_id) # Don't add to resolved_mcp_servers — toolset scope # restricts via object_permission, not server name filter. continue except Exception as _e: - verbose_logger.debug(f"Could not resolve '{name}' as toolset: {_e}") + verbose_logger.debug("Could not resolve '%s' as toolset: %s", name, _e) resolved_mcp_servers.append(name) # Apply all resolved toolsets at once (union), avoiding permission overwrite. @@ -664,7 +666,7 @@ class LiteLLM_Proxy_MCP_Handler: ) = LiteLLM_Proxy_MCP_Handler._extract_tool_call_details(tool_call) if not tool_name: - verbose_logger.warning(f"Tool call missing name: {tool_call}") + verbose_logger.warning("Tool call missing name: %s", tool_call) continue parsed_arguments = LiteLLM_Proxy_MCP_Handler._parse_tool_arguments(tool_arguments) @@ -844,7 +846,7 @@ class LiteLLM_Proxy_MCP_Handler: request_data=logging_request_data, error=e, ) - verbose_logger.error(f"BlockedPiiEntityError in MCP tool call: {e}") + verbose_logger.error("BlockedPiiEntityError in MCP tool call: %s", e) error_message = f"Tool call blocked: PII entity '{getattr(e, 'entity_type', 'unknown')}' detected by guardrail '{getattr(e, 'guardrail_name', 'unknown')}'. {e}" tool_results.append( { @@ -860,7 +862,7 @@ class LiteLLM_Proxy_MCP_Handler: request_data=logging_request_data, error=e, ) - verbose_logger.error(f"GuardrailRaisedException in MCP tool call: {e}") + verbose_logger.error("GuardrailRaisedException in MCP tool call: %s", e) error_message = ( f"Tool call blocked: Guardrail '{getattr(e, 'guardrail_name', 'unknown')}' violation. {e}" ) @@ -878,7 +880,7 @@ class LiteLLM_Proxy_MCP_Handler: request_data=logging_request_data, error=e, ) - verbose_logger.error(f"HTTPException in MCP tool call: {e}") + verbose_logger.error("HTTPException in MCP tool call: %s", e) error_message = f"Tool call failed: {str(e.detail) if hasattr(e, 'detail') else str(e)}" tool_results.append( { @@ -894,7 +896,7 @@ class LiteLLM_Proxy_MCP_Handler: request_data=logging_request_data, error=e, ) - verbose_logger.exception(f"Error executing MCP tool call: {e}") + verbose_logger.exception("Error executing MCP tool call: %s", e) tool_results.append( { "tool_call_id": tool_call_id, diff --git a/litellm/responses/mcp/mcp_streaming_iterator.py b/litellm/responses/mcp/mcp_streaming_iterator.py index c68628429da..c384dd86f5e 100644 --- a/litellm/responses/mcp/mcp_streaming_iterator.py +++ b/litellm/responses/mcp/mcp_streaming_iterator.py @@ -124,10 +124,10 @@ async def create_mcp_list_tools_events( ) events.append(output_item_done_event) - verbose_logger.debug(f"Created {len(events)} MCP discovery events") + verbose_logger.debug("Created %s MCP discovery events", len(events)) except Exception as e: - verbose_logger.error(f"Error creating MCP list tools events: {e}") + verbose_logger.error("Error creating MCP list tools events: %s", e) import traceback traceback.print_exc() @@ -513,7 +513,7 @@ class MCPEnhancedStreamingIterator(BaseResponsesAPIStreamingIterator): response_obj = getattr(chunk, "response", None) if response_obj and hasattr(response_obj, "id"): self._cached_response_id = response_obj.id - verbose_logger.debug(f"Cached response ID: {self._cached_response_id}") + verbose_logger.debug("Cached response ID: %s", self._cached_response_id) # After emitting response.output_item.added, transition to MCP discovery if not self.initial_events_emitted and hasattr(chunk, "type"): @@ -576,7 +576,9 @@ class MCPEnhancedStreamingIterator(BaseResponsesAPIStreamingIterator): response_obj = getattr(chunk, "response", None) if response_obj and hasattr(response_obj, "id"): if response_obj.id != self._cached_response_id: - verbose_logger.debug(f"Updating response ID from {response_obj.id} to {self._cached_response_id}") + verbose_logger.debug( + "Updating response ID from %s to %s", response_obj.id, self._cached_response_id + ) response_obj.id = self._cached_response_id # If auto-execution is enabled, check for completed responses @@ -607,7 +609,7 @@ class MCPEnhancedStreamingIterator(BaseResponsesAPIStreamingIterator): params_for_llm[key] = value # Copy all params as-is since tools are already processed tools_count = len(params_for_llm.get("tools", [])) if params_for_llm.get("tools") else 0 - verbose_logger.debug(f"Making LLM call with {tools_count} tools") + verbose_logger.debug("Making LLM call with %s tools", tools_count) response = await aresponses(**params_for_llm) # Set the base iterator @@ -617,15 +619,15 @@ class MCPEnhancedStreamingIterator(BaseResponsesAPIStreamingIterator): self.model = getattr(response, "model", self.model) self.litellm_metadata = getattr(response, "litellm_metadata", {}) self.custom_llm_provider = getattr(response, "custom_llm_provider", self.custom_llm_provider) - verbose_logger.debug(f"Created base iterator: {type(self.base_iterator)}") + verbose_logger.debug("Created base iterator: %s", type(self.base_iterator)) else: # Non-streaming response - this shouldn't happen but handle it - verbose_logger.warning(f"Got non-streaming response: {type(response)}") + verbose_logger.warning("Got non-streaming response: %s", type(response)) self.base_iterator = None self.phase = "finished" except Exception as e: - verbose_logger.error(f"Error creating initial response iterator: {e}") + verbose_logger.error("Error creating initial response iterator: %s", e) import traceback traceback.print_exc() @@ -742,7 +744,7 @@ class MCPEnhancedStreamingIterator(BaseResponsesAPIStreamingIterator): self._tool_results_for_response = self.collected_response except Exception as e: - verbose_logger.error(f"Error in tool execution: {e}") + verbose_logger.error("Error in tool execution: %s", e) import traceback traceback.print_exc() @@ -807,7 +809,7 @@ class MCPEnhancedStreamingIterator(BaseResponsesAPIStreamingIterator): self._cached_response_id = None except Exception as e: - verbose_logger.error(f"Error creating follow-up iterator: {e}") + verbose_logger.error("Error creating follow-up iterator: %s", e) import traceback traceback.print_exc() diff --git a/litellm/responses/utils.py b/litellm/responses/utils.py index 5d4cfcaf06f..6eb1b7819d9 100644 --- a/litellm/responses/utils.py +++ b/litellm/responses/utils.py @@ -535,7 +535,7 @@ class ResponsesAPIRequestUtils: response_id=decoded_response_id, ) except Exception as e: - verbose_logger.debug(f"Error decoding response_id '{response_id}': {e}") + verbose_logger.debug("Error decoding response_id '%s': %s", response_id, e) return DecodedResponseId( custom_llm_provider=None, model_id=None, @@ -648,7 +648,7 @@ class ResponsesAPIRequestUtils: response_id=original_container_id, ) except Exception as e: - verbose_logger.debug(f"Error decoding container_id '{container_id}': {e}") + verbose_logger.debug("Error decoding container_id '%s': %s", container_id, e) return DecodedResponseId( custom_llm_provider=None, model_id=None, diff --git a/litellm/router.py b/litellm/router.py index 6bf1bdfc670..7d6499cf7d2 100644 --- a/litellm/router.py +++ b/litellm/router.py @@ -721,7 +721,8 @@ class Router: self.retry_policy = retry_policy if self.retry_policy is not None: verbose_router_logger.info( - f"\033[32mRouter Custom Retry Policy Set:\n{self.retry_policy.model_dump(exclude_none=True)}\033[0m" + "\x1b[32mRouter Custom Retry Policy Set:\n%s\x1b[0m", + self.retry_policy.model_dump(exclude_none=True), ) self.model_group_retry_policy: dict[str, RetryPolicy] | None = model_group_retry_policy @@ -736,7 +737,8 @@ class Router: if self.allowed_fails_policy is not None: verbose_router_logger.info( - f"\033[32mRouter Custom Allowed Fails Policy Set:\n{self.allowed_fails_policy.model_dump(exclude_none=True)}\033[0m" + "\x1b[32mRouter Custom Allowed Fails Policy Set:\n%s\x1b[0m", + self.allowed_fails_policy.model_dump(exclude_none=True), ) self.alerting_config: AlertingConfig | None = alerting_config @@ -941,7 +943,7 @@ class Router: litellm.input_callback = [c for c in litellm.input_callback if id(c) not in selector_ids] def routing_strategy_init(self, routing_strategy: RoutingStrategy | str, routing_strategy_args: dict): - verbose_router_logger.info(f"Routing strategy: {routing_strategy}") + verbose_router_logger.info("Routing strategy: %s", routing_strategy) self._validate_routing_strategy(routing_strategy) self._reset_custom_routing_strategy() @@ -1721,7 +1723,7 @@ class Router: return _deployment_copy except Exception as e: - verbose_router_logger.debug(f"Error occurred while printing deployment - {e}") + verbose_router_logger.debug("Error occurred while printing deployment - %s", e) raise e ### COMPLETION, EMBEDDING, IMG GENERATION FUNCTIONS @@ -1732,7 +1734,7 @@ class Router: response = router.completion(model="gpt-3.5-turbo", messages=[{"role": "user", "content": "Hey, how's it going?"}] """ try: - verbose_router_logger.debug(f"router.completion(model={model},..)") + verbose_router_logger.debug("router.completion(model=%s,..)", model) kwargs["model"] = model kwargs["messages"] = messages kwargs["original_function"] = self._completion @@ -1806,7 +1808,7 @@ class Router: **kwargs, } response = litellm.completion(**input_kwargs) - verbose_router_logger.info(f"litellm.completion(model={model_name})\033[32m 200 OK\033[0m") + verbose_router_logger.info("litellm.completion(model=%s)\x1b[32m 200 OK\x1b[0m", model_name) ## CHECK CONTENT FILTER ERROR ## if isinstance(response, ModelResponse): @@ -1829,7 +1831,7 @@ class Router: return response except Exception as e: - verbose_router_logger.info(f"litellm.completion(model={model_name})\033[31m Exception {e}\033[0m") + verbose_router_logger.info("litellm.completion(model=%s)\x1b[31m Exception %s\x1b[0m", model_name, e) # Set per-deployment num_retries on exception for retry logic if deployment is not None: self._set_deployment_num_retries_on_exception(e, deployment) @@ -1892,7 +1894,7 @@ class Router: messages = copy.deepcopy(messages) - verbose_router_logger.info(f"Starting silent experiment for model {silent_model}") + verbose_router_logger.info("Starting silent experiment for model %s", silent_model) silent_kwargs = self._get_silent_experiment_kwargs(**kwargs) @@ -1924,7 +1926,7 @@ class Router: finally: loop.close() except Exception as e: - verbose_router_logger.error(f"Silent experiment failed for model {silent_model}: {e}") + verbose_router_logger.error("Silent experiment failed for model %s: %s", silent_model, e) # fmt: off @@ -2160,7 +2162,7 @@ class Router: except Exception as fallback_error: # If fallback also fails, log and re-raise original error - verbose_router_logger.error(f"Fallback also failed: {fallback_error}") + verbose_router_logger.error("Fallback also failed: %s", fallback_error) # No fallback handled the mid-stream error, so surface the # real provider exception (e.g. RateLimitError) instead of # leaking the internal MidStreamFallbackError to the client @@ -2579,7 +2581,7 @@ class Router: else: yield fallback_response except Exception as fallback_error: - verbose_router_logger.error(f"Responses streaming fallback also failed: {fallback_error}") + verbose_router_logger.error("Responses streaming fallback also failed: %s", fallback_error) if ( isinstance(fallback_error, MidStreamFallbackError) and fallback_error.original_exception is not None @@ -2704,7 +2706,7 @@ class Router: yield None except Exception as fallback_error: - verbose_router_logger.error(f"Fallback also failed: {fallback_error}") + verbose_router_logger.error("Fallback also failed: %s", fallback_error) if ( isinstance(fallback_error, MidStreamFallbackError) and fallback_error.original_exception is not None @@ -2742,7 +2744,7 @@ class Router: messages = copy.deepcopy(messages) - verbose_router_logger.info(f"Starting silent experiment for model {silent_model}") + verbose_router_logger.info("Starting silent experiment for model %s", silent_model) silent_kwargs = self._get_silent_experiment_kwargs(**kwargs) # Override model_group to correctly attribute metrics to the silent model @@ -2755,7 +2757,7 @@ class Router: **silent_kwargs, ) except Exception as e: - verbose_router_logger.error(f"Silent experiment failed for model {silent_model}: {e}") + verbose_router_logger.error("Silent experiment failed for model %s: %s", silent_model, e) async def _acompletion( self, model: str, messages: list[dict[str, str]], **kwargs @@ -2879,7 +2881,7 @@ class Router: ) self.success_calls[model_name] += 1 - verbose_router_logger.info(f"litellm.acompletion(model={model_name})\033[32m 200 OK\033[0m") + verbose_router_logger.info("litellm.acompletion(model=%s)\x1b[32m 200 OK\x1b[0m", model_name) # debug how often this deployment picked self._track_deployment_metrics( deployment=deployment, @@ -2908,7 +2910,7 @@ class Router: self._set_failed_deployment_id_on_exception(e, deployment) raise e except Exception as e: - verbose_router_logger.info(f"litellm.acompletion(model={model_name})\033[31m Exception {e}\033[0m") + verbose_router_logger.info("litellm.acompletion(model=%s)\x1b[31m Exception %s\x1b[0m", model_name, e) if model_name is not None: self.fail_calls[model_name] += 1 # Set per-deployment num_retries on exception for retry logic @@ -3363,7 +3365,7 @@ class Router: result = await self.acompletion(model=model, messages=messages, stream=stream, **kwargs) # type: ignore return result except asyncio.CancelledError: - verbose_router_logger.debug(f"Received 'task.cancel'. Cancelling call w/ model={model}.") + verbose_router_logger.debug("Received 'task.cancel'. Cancelling call w/ model=%s.", model) raise except Exception as e: return e @@ -3665,7 +3667,7 @@ class Router: def _image_generation(self, prompt: str, model: str, **kwargs): model_name = "" try: - verbose_router_logger.debug(f"Inside _image_generation()- model: {model}; kwargs: {kwargs}") + verbose_router_logger.debug("Inside _image_generation()- model: %s; kwargs: %s", model, kwargs) deployment = self.get_available_deployment( model=model, messages=[{"role": "user", "content": "prompt"}], @@ -3694,10 +3696,10 @@ class Router: } ) self.success_calls[model_name] += 1 - verbose_router_logger.info(f"litellm.image_generation(model={model_name})\033[32m 200 OK\033[0m") + verbose_router_logger.info("litellm.image_generation(model=%s)\x1b[32m 200 OK\x1b[0m", model_name) return response except Exception as e: - verbose_router_logger.info(f"litellm.image_generation(model={model_name})\033[31m Exception {e}\033[0m") + verbose_router_logger.info("litellm.image_generation(model=%s)\x1b[31m Exception %s\x1b[0m", model_name, e) if model_name is not None: self.fail_calls[model_name] += 1 raise e @@ -3725,7 +3727,7 @@ class Router: async def _aimage_generation(self, prompt: str, model: str, **kwargs): model_name = model try: - verbose_router_logger.debug(f"Inside _image_generation()- model: {model}; kwargs: {kwargs}") + verbose_router_logger.debug("Inside _image_generation()- model: %s; kwargs: %s", model, kwargs) parent_otel_span = _get_parent_otel_span_from_kwargs(kwargs) deployment = await self.async_get_available_deployment( model=model, @@ -3778,10 +3780,10 @@ class Router: response = await response self.success_calls[model_name] += 1 - verbose_router_logger.info(f"litellm.aimage_generation(model={model_name})\033[32m 200 OK\033[0m") + verbose_router_logger.info("litellm.aimage_generation(model=%s)\x1b[32m 200 OK\x1b[0m", model_name) return response except Exception as e: - verbose_router_logger.info(f"litellm.aimage_generation(model={model_name})\033[31m Exception {e}\033[0m") + verbose_router_logger.info("litellm.aimage_generation(model=%s)\x1b[31m Exception %s\x1b[0m", model_name, e) if model_name is not None: self.fail_calls[model_name] += 1 raise e @@ -3831,7 +3833,7 @@ class Router: async def _atranscription(self, file: FileTypes, model: str, **kwargs): model_name = model try: - verbose_router_logger.debug(f"Inside _atranscription()- model: {model}; kwargs: {kwargs}") + verbose_router_logger.debug("Inside _atranscription()- model: %s; kwargs: %s", model, kwargs) parent_otel_span = _get_parent_otel_span_from_kwargs(kwargs) deployment = await self.async_get_available_deployment( model=model, @@ -3882,10 +3884,10 @@ class Router: response = await response self.success_calls[model_name] += 1 - verbose_router_logger.info(f"litellm.atranscription(model={model_name})\033[32m 200 OK\033[0m") + verbose_router_logger.info("litellm.atranscription(model=%s)\x1b[32m 200 OK\x1b[0m", model_name) return response except Exception as e: - verbose_router_logger.info(f"litellm.atranscription(model={model_name})\033[31m Exception {e}\033[0m") + verbose_router_logger.info("litellm.atranscription(model=%s)\x1b[31m Exception %s\x1b[0m", model_name, e) if model_name is not None: self.fail_calls[model_name] += 1 raise e @@ -3945,7 +3947,7 @@ class Router: async def _aspeech(self, model: str, input: str, voice: str, **kwargs): model_name = model try: - verbose_router_logger.debug(f"Inside _aspeech()- model: {model}; kwargs: {kwargs}") + verbose_router_logger.debug("Inside _aspeech()- model: %s; kwargs: %s", model, kwargs) parent_otel_span = _get_parent_otel_span_from_kwargs(kwargs) deployment = await self.async_get_available_deployment( model=model, @@ -3996,10 +3998,10 @@ class Router: response = await response self.success_calls[model_name] += 1 - verbose_router_logger.info(f"litellm.aspeech(model={model_name})\033[32m 200 OK\033[0m") + verbose_router_logger.info("litellm.aspeech(model=%s)\x1b[32m 200 OK\x1b[0m", model_name) return response except Exception as e: - verbose_router_logger.info(f"litellm.aspeech(model={model_name})\033[31m Exception {e}\033[0m") + verbose_router_logger.info("litellm.aspeech(model=%s)\x1b[31m Exception %s\x1b[0m", model_name, e) if model_name is not None: self.fail_calls[model_name] += 1 raise e @@ -4028,7 +4030,7 @@ class Router: async def _arerank(self, model: str, **kwargs): model_name = None try: - verbose_router_logger.debug(f"Inside _rerank()- model: {model}; kwargs: {kwargs}") + verbose_router_logger.debug("Inside _rerank()- model: %s; kwargs: %s", model, kwargs) deployment = await self.async_get_available_deployment( model=model, specific_deployment=kwargs.pop("specific_deployment", None), @@ -4054,10 +4056,10 @@ class Router: ) self.success_calls[model_name] += 1 - verbose_router_logger.info(f"litellm.arerank(model={model_name})\033[32m 200 OK\033[0m") + verbose_router_logger.info("litellm.arerank(model=%s)\x1b[32m 200 OK\x1b[0m", model_name) return response except Exception as e: - verbose_router_logger.info(f"litellm.arerank(model={model_name})\033[31m Exception {e}\033[0m") + verbose_router_logger.info("litellm.arerank(model=%s)\x1b[31m Exception %s\x1b[0m", model_name, e) if model_name is not None: self.fail_calls[model_name] += 1 raise e @@ -4136,7 +4138,7 @@ class Router: async def _atext_completion(self, model: str, prompt: str, **kwargs): try: - verbose_router_logger.debug(f"Inside _atext_completion()- model: {model}; kwargs: {kwargs}") + verbose_router_logger.debug("Inside _atext_completion()- model: %s; kwargs: %s", model, kwargs) parent_otel_span = _get_parent_otel_span_from_kwargs(kwargs) deployment = await self.async_get_available_deployment( model=model, @@ -4188,10 +4190,10 @@ class Router: response = await response self.success_calls[model_name] += 1 - verbose_router_logger.info(f"litellm.atext_completion(model={model_name})\033[32m 200 OK\033[0m") + verbose_router_logger.info("litellm.atext_completion(model=%s)\x1b[32m 200 OK\x1b[0m", model_name) return response except Exception as e: - verbose_router_logger.info(f"litellm.atext_completion(model={model})\033[31m Exception {e}\033[0m") + verbose_router_logger.info("litellm.atext_completion(model=%s)\x1b[31m Exception %s\x1b[0m", model, e) if model is not None: self.fail_calls[model] += 1 raise e @@ -4226,7 +4228,7 @@ class Router: async def _aadapter_completion(self, adapter_id: str, model: str, **kwargs): try: - verbose_router_logger.debug(f"Inside _aadapter_completion()- model: {model}; kwargs: {kwargs}") + verbose_router_logger.debug("Inside _aadapter_completion()- model: %s; kwargs: %s", model, kwargs) parent_otel_span = _get_parent_otel_span_from_kwargs(kwargs) deployment = await self.async_get_available_deployment( model=model, @@ -4278,10 +4280,10 @@ class Router: response = await response # type: ignore self.success_calls[model_name] += 1 - verbose_router_logger.info(f"litellm.aadapter_completion(model={model_name})\033[32m 200 OK\033[0m") + verbose_router_logger.info("litellm.aadapter_completion(model=%s)\x1b[32m 200 OK\x1b[0m", model_name) return response except Exception as e: - verbose_router_logger.info(f"litellm.aadapter_completion(model={model})\033[31m Exception {e}\033[0m") + verbose_router_logger.info("litellm.aadapter_completion(model=%s)\x1b[31m Exception %s\x1b[0m", model, e) if model is not None: self.fail_calls[model] += 1 raise e @@ -4338,7 +4340,7 @@ class Router: kwargs=kwargs, metadata_variable_name="litellm_metadata", ) - verbose_router_logger.debug(f"Inside aguardrail() - guardrail_name: {guardrail_name}; kwargs: {kwargs}") + verbose_router_logger.debug("Inside aguardrail() - guardrail_name: %s; kwargs: %s", guardrail_name, kwargs) response = await self.async_function_with_fallbacks(**kwargs) return response @@ -4363,7 +4365,7 @@ class Router: ) verbose_router_logger.debug( - f"Selected guardrail deployment: {selected_guardrail.get('litellm_params', {}).get('guardrail')}" + "Selected guardrail deployment: %s", selected_guardrail.get("litellm_params", {}).get("guardrail") ) # Pass the selected guardrail config to the original function @@ -4413,7 +4415,9 @@ class Router: kwargs["original_generic_function"] = original_function kwargs["original_function"] = self._ageneric_api_call_with_fallbacks_helper self._update_kwargs_before_fallbacks(model=model, kwargs=kwargs, metadata_variable_name="litellm_metadata") - verbose_router_logger.debug(f"Inside ageneric_api_call_with_fallbacks() - model: {model}; kwargs: {kwargs}") + verbose_router_logger.debug( + "Inside ageneric_api_call_with_fallbacks() - model: %s; kwargs: %s", model, kwargs + ) response = await self.async_function_with_fallbacks(**kwargs) return response @@ -4536,11 +4540,13 @@ class Router: response = await response # type: ignore self.success_calls[model_name] += 1 - verbose_router_logger.info(f"ageneric_api_call_with_fallbacks(model={model_name})\033[32m 200 OK\033[0m") + verbose_router_logger.info("ageneric_api_call_with_fallbacks(model=%s)\x1b[32m 200 OK\x1b[0m", model_name) return response except Exception as e: - verbose_router_logger.info(f"ageneric_api_call_with_fallbacks(model={model})\033[31m Exception {e}\033[0m") + verbose_router_logger.info( + "ageneric_api_call_with_fallbacks(model=%s)\x1b[31m Exception %s\x1b[0m", model, e + ) if model is not None: self.fail_calls[model] += 1 raise e @@ -4607,7 +4613,7 @@ class Router: metadata_variable_name = _get_router_metadata_variable_name(function_name="generic_api_call") try: verbose_router_logger.debug( - f"Inside _generic_api_call() - handler: {handler_name}, model: {model}; kwargs: {kwargs}" + "Inside _generic_api_call() - handler: %s, model: %s; kwargs: %s", handler_name, model, kwargs ) self._update_kwargs_before_fallbacks( model=model, @@ -4657,10 +4663,10 @@ class Router: ) self.success_calls[model_name] += 1 - verbose_router_logger.info(f"{handler_name}(model={model_name})\033[32m 200 OK\033[0m") + verbose_router_logger.info("%s(model=%s)\x1b[32m 200 OK\x1b[0m", handler_name, model_name) return response except Exception as e: - verbose_router_logger.info(f"{handler_name}(model={model})\033[31m Exception {e}\033[0m") + verbose_router_logger.info("%s(model=%s)\x1b[31m Exception %s\x1b[0m", handler_name, model, e) if model is not None: self.fail_calls[model] += 1 raise e @@ -4685,7 +4691,7 @@ class Router: def _embedding(self, input: str | list, model: str, **kwargs): model_name = None try: - verbose_router_logger.debug(f"Inside embedding()- model: {model}; kwargs: {kwargs}") + verbose_router_logger.debug("Inside embedding()- model: %s; kwargs: %s", model, kwargs) deployment = self.get_available_deployment( model=model, input=input, @@ -4722,10 +4728,10 @@ class Router: } ) self.success_calls[model_name] += 1 - verbose_router_logger.info(f"litellm.embedding(model={model_name})\033[32m 200 OK\033[0m") + verbose_router_logger.info("litellm.embedding(model=%s)\x1b[32m 200 OK\x1b[0m", model_name) return response except Exception as e: - verbose_router_logger.info(f"litellm.embedding(model={model_name})\033[31m Exception {e}\033[0m") + verbose_router_logger.info("litellm.embedding(model=%s)\x1b[31m Exception %s\x1b[0m", model_name, e) if model_name is not None: self.fail_calls[model_name] += 1 raise e @@ -4758,7 +4764,7 @@ class Router: async def _aembedding(self, input: str | list, model: str, **kwargs): model_name = None try: - verbose_router_logger.debug(f"Inside _aembedding()- model: {model}; kwargs: {kwargs}") + verbose_router_logger.debug("Inside _aembedding()- model: %s; kwargs: %s", model, kwargs) parent_otel_span = _get_parent_otel_span_from_kwargs(kwargs) deployment = await self.async_get_available_deployment( model=model, @@ -4809,10 +4815,10 @@ class Router: response = await response self.success_calls[model_name] += 1 - verbose_router_logger.info(f"litellm.aembedding(model={model_name})\033[32m 200 OK\033[0m") + verbose_router_logger.info("litellm.aembedding(model=%s)\x1b[32m 200 OK\x1b[0m", model_name) return response except Exception as e: - verbose_router_logger.info(f"litellm.aembedding(model={model_name})\033[31m Exception {e}\033[0m") + verbose_router_logger.info("litellm.aembedding(model=%s)\x1b[31m Exception %s\x1b[0m", model_name, e) if model_name is not None: self.fail_calls[model_name] += 1 raise e @@ -4849,7 +4855,7 @@ class Router: try: from litellm.router_utils.common_utils import add_model_file_id_mappings - verbose_router_logger.debug(f"Inside _atext_completion()- model: {model}; kwargs: {kwargs}") + verbose_router_logger.debug("Inside _atext_completion()- model: %s; kwargs: %s", model, kwargs) parent_otel_span = _get_parent_otel_span_from_kwargs(kwargs) healthy_deployments = await self.async_get_healthy_deployments( model=model, @@ -4940,7 +4946,7 @@ class Router: response = await response # type: ignore self.success_calls[model_name] += 1 - verbose_router_logger.info(f"litellm.acreate_file(model={model_name})\033[32m 200 OK\033[0m") + verbose_router_logger.info("litellm.acreate_file(model=%s)\x1b[32m 200 OK\x1b[0m", model_name) return response @@ -4965,7 +4971,7 @@ class Router: return returned_response except Exception as e: verbose_router_logger.exception( - f"litellm.acreate_file(model={model}, {kwargs})\033[31m Exception {e}\033[0m" + "litellm.acreate_file(model=%s, %s)\x1b[31m Exception %s\x1b[0m", model, kwargs, e ) if model is not None: self.fail_calls[model] += 1 @@ -5056,11 +5062,13 @@ class Router: response = await response self.success_calls[model_name] += 1 - verbose_router_logger.info(f"litellm.avector_store_create(model={model_name})\033[32m 200 OK\033[0m") + verbose_router_logger.info("litellm.avector_store_create(model=%s)\x1b[32m 200 OK\x1b[0m", model_name) return response except Exception as e: - verbose_router_logger.exception(f"litellm.avector_store_create(model={model})\033[31m Exception {e}\033[0m") + verbose_router_logger.exception( + "litellm.avector_store_create(model=%s)\x1b[31m Exception %s\x1b[0m", model, e + ) if model is not None: self.fail_calls[model] += 1 raise e @@ -5110,7 +5118,7 @@ class Router: **kwargs, ) -> LiteLLMBatch: try: - verbose_router_logger.debug(f"Inside _acreate_batch()- model: {model}; kwargs: {kwargs}") + verbose_router_logger.debug("Inside _acreate_batch()- model: %s; kwargs: %s", model, kwargs) parent_otel_span = _get_parent_otel_span_from_kwargs(kwargs) deployment = await self.async_get_available_deployment( model=model, @@ -5170,12 +5178,12 @@ class Router: response = await response # type: ignore self.success_calls[model_name] += 1 - verbose_router_logger.info(f"litellm.acreate_batch(model={model_name})\033[32m 200 OK\033[0m") + verbose_router_logger.info("litellm.acreate_batch(model=%s)\x1b[32m 200 OK\x1b[0m", model_name) return response # type: ignore except Exception as e: verbose_router_logger.exception( - f"litellm._acreate_batch(model={model}, {kwargs})\033[31m Exception {e}\033[0m" + "litellm._acreate_batch(model=%s, %s)\x1b[31m Exception %s\x1b[0m", model, kwargs, e ) if model is not None: self.fail_calls[model] += 1 @@ -5325,7 +5333,7 @@ class Router: **kwargs, ) -> LiteLLMBatch: try: - verbose_router_logger.debug(f"Inside _acancel_batch()- model: {model}; kwargs: {kwargs}") + verbose_router_logger.debug("Inside _acancel_batch()- model: %s; kwargs: %s", model, kwargs) parent_otel_span = _get_parent_otel_span_from_kwargs(kwargs) deployment = await self.async_get_available_deployment( model=model, @@ -5392,12 +5400,12 @@ class Router: response = await response # type: ignore self.success_calls[model_name] += 1 - verbose_router_logger.info(f"litellm.acancel_batch(model={model_name})\033[32m 200 OK\033[0m") + verbose_router_logger.info("litellm.acancel_batch(model=%s)\x1b[32m 200 OK\x1b[0m", model_name) return response # type: ignore except Exception as e: verbose_router_logger.exception( - f"litellm._acancel_batch(model={model}, {kwargs})\033[31m Exception {e}\033[0m" + "litellm._acancel_batch(model=%s, %s)\x1b[31m Exception %s\x1b[0m", model, kwargs, e ) if model is not None: self.fail_calls[model] += 1 @@ -6061,8 +6069,10 @@ class Router: return None verbose_router_logger.debug( - f"Weighted failover: exclude={excluded!r}, remaining={len(remaining)} " - f"for model_group={original_model_group!r}" + "Weighted failover: exclude=%r, remaining=%s for model_group=%r", + excluded, + len(remaining), + original_model_group, ) meta["_failover_excluded_ids"] = list(excluded) @@ -6107,7 +6117,7 @@ class Router: """ Common utilities for async_function_with_fallbacks """ - verbose_router_logger.debug(f"Traceback{traceback.format_exc()}") + verbose_router_logger.debug("Traceback%s", traceback.format_exc()) original_exception = e fallback_model_group = None original_model_group: str | None = kwargs.get("model") # type: ignore @@ -6284,7 +6294,7 @@ class Router: if litellm.expose_router_debug_in_errors: e.message += f"\n{error_message}" if fallbacks is not None and model_group is not None: - verbose_router_logger.debug(f"inside model fallbacks: {mask_sensitive_structure(fallbacks)}") + verbose_router_logger.debug("inside model fallbacks: %s", mask_sensitive_structure(fallbacks)) ( fallback_model_group, generic_fallback_idx, @@ -6299,7 +6309,9 @@ class Router: if fallback_model_group is None: masked_fallbacks = mask_sensitive_structure(fallbacks) verbose_router_logger.info( - f"No fallback model group found for original model_group={model_group}. Fallbacks={masked_fallbacks}" + "No fallback model group found for original model_group=%s. Fallbacks=%s", + model_group, + masked_fallbacks, ) if hasattr(original_exception, "message") and litellm.expose_router_debug_in_errors: original_exception.message += f"No fallback model group found for original model_group={model_group}. Fallbacks={masked_fallbacks}" # type: ignore @@ -6374,7 +6386,7 @@ class Router: else: response = await self.async_function_with_retries(*args, **kwargs) if verbose_router_logger.isEnabledFor(logging.DEBUG): - verbose_router_logger.debug(f"Async Response: {response}") + verbose_router_logger.debug("Async Response: %s", response) response = add_fallback_headers_to_response( response=response, attempted_fallbacks=0, @@ -6466,7 +6478,7 @@ class Router: _metadata.update({"model_group_size": len(model_list)}) verbose_router_logger.debug( - f"async function w/ retries: original_function - {original_function}, num_retries - {num_retries}" + "async function w/ retries: original_function - %s, num_retries - %s", original_function, num_retries ) ## ADD RETRY TRACKING TO METADATA - used for spend logs retry tracking _metadata["attempted_retries"] = 0 @@ -6538,7 +6550,7 @@ class Router: else: raise - verbose_router_logger.debug(f"Retrying request with num_retries: {num_retries}") + verbose_router_logger.debug("Retrying request with num_retries: %s", num_retries) # decides how long to sleep before retry retry_after = self._time_to_sleep_before_retry( e=original_exception, @@ -6655,7 +6667,7 @@ class Router: if mock_testing_rate_limit_error is not None and mock_testing_rate_limit_error is True: verbose_router_logger.info( - f"litellm.router.py::_mock_rate_limit_error() - Raising mock RateLimitError for model={model_group}" + "litellm.router.py::_mock_rate_limit_error() - Raising mock RateLimitError for model=%s", model_group ) raise litellm.RateLimitError( model=model_group, @@ -6945,7 +6957,7 @@ class Router: except Exception as e: verbose_router_logger.debug( - f"litellm.router.Router::deployment_callback_on_success(): Exception occured - {e}" + "litellm.router.Router::deployment_callback_on_success(): Exception occured - %s", e ) def sync_deployment_callback_on_success( @@ -7198,7 +7210,9 @@ class Router: return True verbose_router_logger.debug( - f"Content Policy Error occurred. No available fallbacks. Returning original response. model={model}, content_policy_fallbacks={content_policy_fallbacks}" + "Content Policy Error occurred. No available fallbacks. Returning original response. model=%s, content_policy_fallbacks=%s", + model, + content_policy_fallbacks, ) return False @@ -7537,7 +7551,9 @@ class Router: ## Check if LLM Deployment is allowed for this deployment if self.deployment_is_active_for_environment(deployment=deployment) is not True: verbose_router_logger.warning( - f"Ignoring deployment {deployment.model_name} as it is not active for environment {deployment.model_info['supported_environments']}" + "Ignoring deployment %s as it is not active for environment %s", + deployment.model_name, + deployment.model_info["supported_environments"], ) return None @@ -7561,7 +7577,7 @@ class Router: except Exception as e: if self.ignore_invalid_deployments: verbose_router_logger.exception( - f"Error creating deployment: {e}, ignoring and continuing with other deployments." + "Error creating deployment: %s, ignoring and continuing with other deployments.", e ) return None else: @@ -8014,7 +8030,7 @@ class Router: _model_info=_model_info, ) - verbose_router_logger.debug(f"\nInitialized Model List {self.get_model_names()}") + verbose_router_logger.debug("\nInitialized Model List %s", self.get_model_names()) self.model_names = {m["model_name"] for m in model_list} # Note: model_name_to_deployment_indices is already built incrementally @@ -8436,8 +8452,10 @@ class Router: except Exception as e: if self.ignore_invalid_deployments: verbose_router_logger.warning( - f"Error upserting deployment {deployment.model_name} (id={deployment.model_info.id}): {e}. " - "Dropping it and continuing with other deployments." + "Error upserting deployment %s (id=%s): %s. Dropping it and continuing with other deployments.", + deployment.model_name, + deployment.model_info.id, + e, ) return None else: @@ -8710,7 +8728,7 @@ class Router: ) if not credential_values: verbose_router_logger.warning( - f"Credential '{deployment.litellm_params.litellm_credential_name}' not found in credential_list" + "Credential '%s' not found in credential_list", deployment.litellm_params.litellm_credential_name ) credentials.update(credential_values) # Remove the credential name since we've resolved it @@ -8795,7 +8813,8 @@ class Router: ## SET MODEL TO 'model=' - if base_model is None + not azure if custom_llm_provider == "azure" and base_model is None: verbose_router_logger.error( - f"Could not identify azure model '{_model}'. Set azure 'base_model' for accurate max tokens, cost tracking, etc.- https://docs.litellm.ai/docs/proxy/cost_tracking#spend-tracking-for-azure-openai-models" + "Could not identify azure model '%s'. Set azure 'base_model' for accurate max tokens, cost tracking, etc.- https://docs.litellm.ai/docs/proxy/cost_tracking#spend-tracking-for-azure-openai-models", + _model, ) elif custom_llm_provider != "azure": model = _model @@ -9011,7 +9030,7 @@ class Router: custom_llm_provider=litellm_params.custom_llm_provider, ) except litellm.exceptions.BadRequestError as e: - verbose_router_logger.error(f"litellm.router.py::get_model_group_info() - {e}") + verbose_router_logger.error("litellm.router.py::get_model_group_info() - %s", e) if model_info is None: supported_openai_params = litellm.get_supported_openai_params( @@ -10073,7 +10092,7 @@ class Router: relink_lar1_from_args = True setattr(self, var, value) else: - verbose_router_logger.debug(f"Setting {var} is not allowed") + verbose_router_logger.debug("Setting %s is not allowed", var) if relink_lar1_from_args and self._normalize_strategy(self.routing_strategy) == "lar1": from litellm.router_strategy.lar1_routing import apply_lar1_routing_strategy @@ -10082,7 +10101,7 @@ class Router: if rebuild_routing_groups: self._init_routing_groups(self._routing_groups_input) - verbose_router_logger.debug(f"Updated Router settings: {self.get_settings()}") + verbose_router_logger.debug("Updated Router settings: %s", self.get_settings()) def _get_client(self, deployment, kwargs, client_type=None): """ @@ -10173,7 +10192,7 @@ class Router: - [TODO] function call and model doesn't support function calling """ - verbose_router_logger.debug(f"Starting Pre-call checks for deployments in model={model}") + verbose_router_logger.debug("Starting Pre-call checks for deployments in model=%s", model) # Optimized: Use list() shallow copy instead of deepcopy # We only pop from the list, not modify deployment dicts - 100x+ faster on hot path (every request) @@ -10225,7 +10244,8 @@ class Router: ) except Exception as e: verbose_router_logger.error( - f"litellm.router.py::_pre_call_checks: failed to count tokens. Returning initial list of deployments. Got - {e}" + "litellm.router.py::_pre_call_checks: failed to count tokens. Returning initial list of deployments. Got - %s", + e, ) return _returned_deployments if input_tokens > max_input_tokens: @@ -10236,7 +10256,7 @@ class Router: ) continue except Exception as e: - verbose_router_logger.exception(f"An error occurs - {e}") + verbose_router_logger.exception("An error occurs - %s", e) model_id = _model_info.get("id", "") ## RPM CHECK ## @@ -10297,7 +10317,7 @@ class Router: for k, v in non_default_params.items(): if k not in supported_openai_params and k in special_params: # if not -> invalid model - verbose_router_logger.debug(f"INVALID MODEL INDEX @ REQUEST KWARG FILTERING, k={k}") + verbose_router_logger.debug("INVALID MODEL INDEX @ REQUEST KWARG FILTERING, k=%s", k) invalid_model_indices.add(idx) if len(invalid_model_indices) == len(_returned_deployments): @@ -10490,7 +10510,7 @@ class Router: _access_group_filter_emptied_candidates = True if verbose_router_logger.isEnabledFor(logging.DEBUG): - verbose_router_logger.debug(f"initial list of deployments: {healthy_deployments}") + verbose_router_logger.debug("initial list of deployments: %s", healthy_deployments) if len(healthy_deployments) == 0: # Check for default fallbacks if no deployments are found for the requested model @@ -10501,7 +10521,7 @@ class Router: fallback_model = self._get_first_default_fallback() if fallback_model: verbose_router_logger.info( - f"Model '{model}' not found. Attempting to use default fallback model '{fallback_model}'." + "Model '%s' not found. Attempting to use default fallback model '%s'.", model, fallback_model ) # Re-assign model to the fallback and try to get deployments again model = fallback_model @@ -10618,7 +10638,7 @@ class Router: ) if verbose_router_logger.isEnabledFor(logging.DEBUG): - verbose_router_logger.debug(f"healthy_deployments after team filter: {healthy_deployments}") + verbose_router_logger.debug("healthy_deployments after team filter: %s", healthy_deployments) healthy_deployments = filter_web_search_deployments( healthy_deployments=healthy_deployments, @@ -10626,7 +10646,7 @@ class Router: ) if verbose_router_logger.isEnabledFor(logging.DEBUG): - verbose_router_logger.debug(f"healthy_deployments after web search filter: {healthy_deployments}") + verbose_router_logger.debug("healthy_deployments after web search filter: %s", healthy_deployments) if isinstance(healthy_deployments, dict): if (healthy_deployments.get("model_info") or {}).get("blocked") is True: @@ -10647,7 +10667,7 @@ class Router: litellm_router_instance=self, parent_otel_span=parent_otel_span ) if verbose_router_logger.isEnabledFor(logging.DEBUG): - verbose_router_logger.debug(f"cooldown deployments: {cooldown_deployments}") + verbose_router_logger.debug("cooldown deployments: %s", cooldown_deployments) _pre_cooldown_deployments = healthy_deployments healthy_deployments = self._filter_cooldown_deployments( healthy_deployments=healthy_deployments, @@ -10810,7 +10830,10 @@ class Router: ) raise exception verbose_router_logger.info( - f"get_available_deployment for model: {model}, Selected deployment: {self.print_deployment(deployment)} for model: {model}" + "get_available_deployment for model: %s, Selected deployment: %s for model: %s", + model, + self.print_deployment(deployment), + model, ) end_time = time.time() @@ -10939,7 +10962,9 @@ class Router: raise exception verbose_router_logger.info( - f"async_get_available_deployment_for_pass_through model: {model}, selected deployment: {self.print_deployment(deployment)}" + "async_get_available_deployment_for_pass_through model: %s, selected deployment: %s", + model, + self.print_deployment(deployment), ) end_time = time.perf_counter() @@ -11312,7 +11337,7 @@ class Router: ) if deployment is None: - verbose_router_logger.info(f"get_available_deployment for model: {model}, No deployment available") + verbose_router_logger.info("get_available_deployment for model: %s, No deployment available", model) model_ids = self.get_model_ids(model_name=model) _cooldown_time = self.cooldown_cache.get_min_cooldown( model_ids=model_ids, parent_otel_span=parent_otel_span @@ -11325,7 +11350,10 @@ class Router: cooldown_list=_cooldown_list, ) verbose_router_logger.info( - f"get_available_deployment for model: {model}, Selected deployment: {self.print_deployment(deployment)} for model: {model}" + "get_available_deployment for model: %s, Selected deployment: %s for model: %s", + model, + self.print_deployment(deployment), + model, ) return deployment @@ -11452,7 +11480,7 @@ class Router: if deployment is None: verbose_router_logger.info( - f"get_available_deployment_for_pass_through model: {model}, no available deployments" + "get_available_deployment_for_pass_through model: %s, no available deployments", model ) model_ids = self.get_model_ids(model_name=model) _cooldown_time = self.cooldown_cache.get_min_cooldown( @@ -11467,7 +11495,9 @@ class Router: ) verbose_router_logger.info( - f"get_available_deployment_for_pass_through model: {model}, selected deployment: {self.print_deployment(deployment)}" + "get_available_deployment_for_pass_through model: %s, selected deployment: %s", + model, + self.print_deployment(deployment), ) return deployment @@ -11485,7 +11515,7 @@ class Router: List of healthy deployments """ if verbose_router_logger.isEnabledFor(logging.DEBUG): - verbose_router_logger.debug(f"cooldown deployments: {cooldown_deployments}") + verbose_router_logger.debug("cooldown deployments: %s", cooldown_deployments) # Convert to set for O(1) lookup and use list comprehension for O(n) filtering cooldown_set = set(cooldown_deployments) return [deployment for deployment in healthy_deployments if deployment["model_info"]["id"] not in cooldown_set] @@ -11587,7 +11617,7 @@ class Router: List[Dict]: Only includes a list of deployments that support pass-through """ verbose_router_logger.debug( - f"Filter pass-through deployments from {len(healthy_deployments)} healthy deployments" + "Filter pass-through deployments from %s healthy deployments", len(healthy_deployments) ) pass_through_deployments = [ @@ -11596,7 +11626,7 @@ class Router: if deployment.get("litellm_params", {}).get("use_in_pass_through", False) ] - verbose_router_logger.debug(f"Found {len(pass_through_deployments)} deployments with pass-through enabled") + verbose_router_logger.debug("Found %s deployments with pass-through enabled", len(pass_through_deployments)) return pass_through_deployments @@ -11611,7 +11641,7 @@ class Router: if model_id is not None: self._update_usage(model_id, parent_otel_span) # update in-memory cache for tracking except Exception as e: - verbose_router_logger.error(f"Error in _track_deployment_metrics: {e}") + verbose_router_logger.error("Error in _track_deployment_metrics: %s", e) def get_num_retries_from_retry_policy(self, exception: Exception, model_group: str | None = None): return _get_num_retries_from_retry_policy( diff --git a/litellm/router_strategy/auto_router/auto_router.py b/litellm/router_strategy/auto_router/auto_router.py index d959eb3ef73..4ea3389381c 100644 --- a/litellm/router_strategy/auto_router/auto_router.py +++ b/litellm/router_strategy/auto_router/auto_router.py @@ -147,7 +147,7 @@ class AutoRouter(CustomLogger): message_content = self._extract_text_from_messages(messages) route_choice: RouteChoice | list[RouteChoice] | None = routelayer(text=message_content) - verbose_router_logger.debug(f"route_choice: {route_choice}") + verbose_router_logger.debug("route_choice: %s", route_choice) if isinstance(route_choice, RouteChoice): model = route_choice.name or self.default_model elif isinstance(route_choice, list): diff --git a/litellm/router_strategy/base_routing_strategy.py b/litellm/router_strategy/base_routing_strategy.py index 70e1c12665d..9752c96fa5b 100644 --- a/litellm/router_strategy/base_routing_strategy.py +++ b/litellm/router_strategy/base_routing_strategy.py @@ -97,7 +97,7 @@ class BaseRoutingStrategy(ABC): default_sync_interval ) # Wait for DEFAULT_REDIS_SYNC_INTERVAL seconds before next sync except Exception as e: - verbose_router_logger.error(f"Error in periodic sync task: {e}") + verbose_router_logger.error("Error in periodic sync task: %s", e) await asyncio.sleep( default_sync_interval ) # Still wait DEFAULT_REDIS_SYNC_INTERVAL seconds on error before retrying @@ -146,7 +146,7 @@ class BaseRoutingStrategy(ABC): return return_result except Exception as e: - verbose_router_logger.error(f"Error syncing in-memory cache with Redis: {e}") + verbose_router_logger.error("Error syncing in-memory cache with Redis: %s", e) self.redis_increment_operation_queue = [] def add_to_in_memory_keys_to_update(self, key: str): @@ -226,4 +226,4 @@ class BaseRoutingStrategy(ABC): await self.dual_cache.in_memory_cache.async_set_cache(key=key, value=merged) except Exception as e: - verbose_router_logger.exception(f"Error syncing in-memory cache with Redis: {e}") + verbose_router_logger.exception("Error syncing in-memory cache with Redis: %s", e) diff --git a/litellm/router_strategy/budget_limiter.py b/litellm/router_strategy/budget_limiter.py index 3b8a75f4e49..0d8980b6f16 100644 --- a/litellm/router_strategy/budget_limiter.py +++ b/litellm/router_strategy/budget_limiter.py @@ -499,7 +499,7 @@ class RouterBudgetLimiting(CustomLogger): spend_key=spend_key, response_cost=response_cost, ttl=ttl_for_increment ) - verbose_router_logger.debug(f"Incremented spend for {spend_key} by {response_cost}") + verbose_router_logger.debug("Incremented spend for %s by %s", spend_key, response_cost) async def periodic_sync_in_memory_spend_with_redis(self): """ @@ -514,7 +514,7 @@ class RouterBudgetLimiting(CustomLogger): DEFAULT_REDIS_SYNC_INTERVAL ) # Wait for DEFAULT_REDIS_SYNC_INTERVAL seconds before next sync except Exception as e: - verbose_router_logger.error(f"Error in periodic sync task: {e}") + verbose_router_logger.error("Error in periodic sync task: %s", e) await asyncio.sleep( DEFAULT_REDIS_SYNC_INTERVAL ) # Still wait DEFAULT_REDIS_SYNC_INTERVAL seconds on error before retrying @@ -545,7 +545,7 @@ class RouterBudgetLimiting(CustomLogger): self.redis_increment_operation_queue = [] except Exception as e: - verbose_router_logger.error(f"Error syncing in-memory cache with Redis: {e}") + verbose_router_logger.error("Error syncing in-memory cache with Redis: %s", e) async def _sync_in_memory_spend_with_redis(self): """ @@ -597,10 +597,10 @@ class RouterBudgetLimiting(CustomLogger): for key, value in redis_values.items(): if value is not None: await self.dual_cache.in_memory_cache.async_set_cache(key=key, value=float(value)) - verbose_router_logger.debug(f"Updated in-memory cache for {key}: {value}") + verbose_router_logger.debug("Updated in-memory cache for %s: %s", key, value) except Exception as e: - verbose_router_logger.error(f"Error syncing in-memory cache with Redis: {e}") + verbose_router_logger.error("Error syncing in-memory cache with Redis: %s", e) def _get_budget_config_for_deployment( self, @@ -639,7 +639,7 @@ class RouterBudgetLimiting(CustomLogger): litellm_params=provider_resolution_params, ) except Exception: - verbose_router_logger.error(f"Error getting LLM provider for deployment: {deployment}") + verbose_router_logger.error("Error getting LLM provider for deployment: %s", deployment) return None return custom_llm_provider @@ -772,7 +772,7 @@ class RouterBudgetLimiting(CustomLogger): ) ) - verbose_router_logger.debug(f"Initalized Provider budget config: {self.provider_budget_config}") + verbose_router_logger.debug("Initalized Provider budget config: %s", self.provider_budget_config) def _init_deployment_budgets( self, @@ -788,7 +788,10 @@ class RouterBudgetLimiting(CustomLogger): _budget_duration = _litellm_params.get("budget_duration") verbose_router_logger.debug( - f"Init Deployment Budget: max_budget: {_max_budget}, budget_duration: {_budget_duration}, model_id: {_model_id}" + "Init Deployment Budget: max_budget: %s, budget_duration: %s, model_id: %s", + _max_budget, + _budget_duration, + _model_id, ) if _max_budget is not None and _budget_duration is not None and _model_id is not None: _budget_config = GenericBudgetInfo( @@ -799,7 +802,7 @@ class RouterBudgetLimiting(CustomLogger): self.deployment_budget_config = {} self.deployment_budget_config[_model_id] = _budget_config - verbose_router_logger.debug(f"Initialized Deployment Budget Config: {self.deployment_budget_config}") + verbose_router_logger.debug("Initialized Deployment Budget Config: %s", self.deployment_budget_config) def register_deployment_budget( self, @@ -837,4 +840,4 @@ class RouterBudgetLimiting(CustomLogger): ) self.tag_budget_config[_tag] = _generic_budget_config - verbose_router_logger.debug(f"Initialized Tag Budget Config: {self.tag_budget_config}") + verbose_router_logger.debug("Initialized Tag Budget Config: %s", self.tag_budget_config) diff --git a/litellm/router_strategy/complexity_router/complexity_router.py b/litellm/router_strategy/complexity_router/complexity_router.py index 6f2bf61834b..6a9ce1303d3 100644 --- a/litellm/router_strategy/complexity_router/complexity_router.py +++ b/litellm/router_strategy/complexity_router/complexity_router.py @@ -422,7 +422,7 @@ class ComplexityRouter(CustomLogger): self._model_tiers: dict[str, tuple[ComplexityTier, ...]] = {} self._adaptive_init_attempted = False - verbose_router_logger.debug(f"ComplexityRouter initialized for {model_name} with tiers: {self.config.tiers}") + verbose_router_logger.debug("ComplexityRouter initialized for %s with tiers: %s", model_name, self.config.tiers) def _estimate_tokens(self, text: str) -> int: """ @@ -710,7 +710,7 @@ class ComplexityRouter(CustomLogger): ) except Exception as e: # noqa: BLE001 -- external LLM call can fail in many distinct ways (timeout, provider error, validation, parse error); any failure must fall back to the heuristic scorer verbose_router_logger.warning( - f"ComplexityRouter: LLM classifier failed ({e}), falling back to heuristic scoring" + "ComplexityRouter: LLM classifier failed (%s), falling back to heuristic scoring", e ) tier, score, signals, cause = self._score_and_classify(prompt, system_prompt) return ClassificationOutcome(tier=tier, score=score, signals=signals, cause=cause) @@ -1288,7 +1288,7 @@ class ComplexityRouter(CustomLogger): semantic_tier = await self._semantic_tier_override(user_message, request_kwargs) except Exception as e: # noqa: BLE001 -- embedding call can fail many ways (timeout, provider/network/parse error); any failure must fall back to scoring, never fail the request verbose_router_logger.warning( - f"ComplexityRouter: semantic keyword matching failed ({e}), falling back to complexity scoring" + "ComplexityRouter: semantic keyword matching failed (%s), falling back to complexity scoring", e ) return None if semantic_tier is None: @@ -1427,7 +1427,7 @@ class ComplexityRouter(CustomLogger): escalated = routed_model != pinned_model cause: RoutingDecisionCause = "session_affinity_escalation" if escalated else "session_affinity_pin" verbose_router_logger.info( - f"ComplexityRouter: routing decision cause={cause}, routed_model={routed_model}" + "ComplexityRouter: routing decision cause=%s, routed_model=%s", cause, routed_model ) has_original_messages = messages is not None and len(messages) > 0 return PreRoutingHookResponse( @@ -1524,8 +1524,11 @@ class ComplexityRouter(CustomLogger): "semantic_keyword_match" if self.config.semantic_keyword_matching else "literal_keyword_match" ) verbose_router_logger.info( - f"ComplexityRouter: routing decision cause={keyword_cause}, escalated={keyword_escalated}, " - f"tier={routed_tier.value}, routed_model={routed_model}" + "ComplexityRouter: routing decision cause=%s, escalated=%s, tier=%s, routed_model=%s", + keyword_cause, + keyword_escalated, + routed_tier.value, + routed_model, ) return PreRoutingHookResponse( model=routed_model, @@ -1558,15 +1561,22 @@ class ComplexityRouter(CustomLogger): chosen_key = getattr(self, "_adaptive_chosen_model_key", "adaptive_router_chosen_model") kwargs_metadata[chosen_key] = routed_model verbose_router_logger.info( - f"ComplexityRouter[adaptive]: routing decision cause={outcome.cause}, " - f"tier={tier.value}, score={score_repr}, " - f"signals={signals}, routed_model={routed_model}" + "ComplexityRouter[adaptive]: routing decision cause=%s, tier=%s, score=%s, signals=%s, routed_model=%s", + outcome.cause, + tier.value, + score_repr, + signals, + routed_model, ) else: routed_model = await self._pick_model_for_tier(tier, messages, resolved_messages, request_kwargs) verbose_router_logger.info( - f"ComplexityRouter: routing decision cause={outcome.cause}, tier={tier.value}, " - f"score={score_repr}, signals={signals}, routed_model={routed_model}" + "ComplexityRouter: routing decision cause=%s, tier=%s, score=%s, signals=%s, routed_model=%s", + outcome.cause, + tier.value, + score_repr, + signals, + routed_model, ) classifier_model = ( diff --git a/litellm/router_strategy/lar1_routing.py b/litellm/router_strategy/lar1_routing.py index acd7ac63225..99a26926558 100644 --- a/litellm/router_strategy/lar1_routing.py +++ b/litellm/router_strategy/lar1_routing.py @@ -68,12 +68,12 @@ def _normalize_thresholds(thresholds: dict[str, float] | None) -> dict[str, floa def _parse_lar1_metadata(request_kwargs: dict) -> LAR1Metadata: lar1_raw = request_kwargs.get("metadata", {}).get("lar1", {}) if not isinstance(lar1_raw, dict): - verbose_router_logger.warning(f"[LAR-1] Invalid lar1 metadata type: {type(lar1_raw).__name__}. Using defaults") + verbose_router_logger.warning("[LAR-1] Invalid lar1 metadata type: %s. Using defaults", type(lar1_raw).__name__) return LAR1Metadata() try: return LAR1Metadata.model_validate(lar1_raw) except ValidationError as exc: - verbose_router_logger.warning(f"[LAR-1] Invalid lar1 metadata: {exc}. Using defaults") + verbose_router_logger.warning("[LAR-1] Invalid lar1 metadata: %s. Using defaults", exc) return LAR1Metadata() @@ -123,11 +123,11 @@ class LAR1RoutingStrategy(CustomRoutingStrategyBase): if selected is None: return None if exact_match: - verbose_router_logger.info(f"[LAR-1] confidence={confidence} -> {target}") + verbose_router_logger.info("[LAR-1] confidence=%s -> %s", confidence, target) else: actual_type = selected.get("model_info", {}).get("type", "unknown") verbose_router_logger.warning( - f"[LAR-1] No deployment for type '{target}', fallback to deployment type '{actual_type}'" + "[LAR-1] No deployment for type '%s', fallback to deployment type '%s'", target, actual_type ) return selected diff --git a/litellm/router_strategy/lowest_cost.py b/litellm/router_strategy/lowest_cost.py index ba7d32c42ad..7a2970d053a 100644 --- a/litellm/router_strategy/lowest_cost.py +++ b/litellm/router_strategy/lowest_cost.py @@ -91,7 +91,7 @@ class LowestCostLoggingHandler(CustomLogger): self.logged_success += 1 except Exception as e: verbose_logger.exception( - f"litellm.router_strategy.lowest_cost.py::log_success_event(): Exception occured - {e}" + "litellm.router_strategy.lowest_cost.py::log_success_event(): Exception occured - %s", e ) async def async_log_success_event(self, kwargs, response_obj, start_time, end_time): @@ -170,7 +170,7 @@ class LowestCostLoggingHandler(CustomLogger): self.logged_success += 1 except Exception as e: verbose_logger.exception( - f"litellm.proxy.hooks.prompt_injection_detection.py::async_pre_call_hook(): Exception occured - {e}" + "litellm.proxy.hooks.prompt_injection_detection.py::async_pre_call_hook(): Exception occured - %s", e ) async def async_get_available_deployments( @@ -269,7 +269,11 @@ class LowestCostLoggingHandler(CustomLogger): item_tpm = item_map.get(precise_minute, {}).get("tpm", 0) verbose_router_logger.debug( - f"item_cost: {item_cost}, item_tpm: {item_tpm}, item_rpm: {item_rpm}, model_id: {_deployment.get('model_info', {}).get('id')}" + "item_cost: %s, item_tpm: %s, item_rpm: %s, model_id: %s", + item_cost, + item_tpm, + item_rpm, + _deployment.get("model_info", {}).get("id"), ) # -------------- # diff --git a/litellm/router_strategy/lowest_latency.py b/litellm/router_strategy/lowest_latency.py index 0adcdebcbf2..294409d042c 100644 --- a/litellm/router_strategy/lowest_latency.py +++ b/litellm/router_strategy/lowest_latency.py @@ -160,7 +160,7 @@ class LowestLatencyLoggingHandler(CustomLogger): self.logged_success += 1 except Exception as e: verbose_logger.exception( - f"litellm.proxy.hooks.prompt_injection_detection.py::async_pre_call_hook(): Exception occured - {e}" + "litellm.proxy.hooks.prompt_injection_detection.py::async_pre_call_hook(): Exception occured - %s", e ) async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time): @@ -217,7 +217,7 @@ class LowestLatencyLoggingHandler(CustomLogger): return except Exception as e: verbose_logger.exception( - f"litellm.proxy.hooks.prompt_injection_detection.py::async_pre_call_hook(): Exception occured - {e}" + "litellm.proxy.hooks.prompt_injection_detection.py::async_pre_call_hook(): Exception occured - %s", e ) async def async_log_success_event(self, kwargs, response_obj, start_time, end_time): @@ -350,7 +350,7 @@ class LowestLatencyLoggingHandler(CustomLogger): self.logged_success += 1 except Exception as e: verbose_logger.exception( - f"litellm.router_strategy.lowest_latency.py::async_log_success_event(): Exception occured - {e}" + "litellm.router_strategy.lowest_latency.py::async_log_success_event(): Exception occured - %s", e ) def _get_available_deployments( diff --git a/litellm/router_strategy/lowest_tpm_rpm.py b/litellm/router_strategy/lowest_tpm_rpm.py index f8e7e93eb54..7375658f982 100644 --- a/litellm/router_strategy/lowest_tpm_rpm.py +++ b/litellm/router_strategy/lowest_tpm_rpm.py @@ -73,7 +73,7 @@ class LowestTPMLoggingHandler(CustomLogger): self.logged_success += 1 except Exception as e: verbose_router_logger.error( - f"litellm.router_strategy.lowest_tpm_rpm.py::async_log_success_event(): Exception occured - {e}" + "litellm.router_strategy.lowest_tpm_rpm.py::async_log_success_event(): Exception occured - %s", e ) verbose_router_logger.debug(traceback.format_exc()) @@ -135,7 +135,7 @@ class LowestTPMLoggingHandler(CustomLogger): self.logged_success += 1 except Exception as e: verbose_router_logger.exception( - f"litellm.router_strategy.lowest_tpm_rpm.py::async_log_success_event(): Exception occured - {e}" + "litellm.router_strategy.lowest_tpm_rpm.py::async_log_success_event(): Exception occured - %s", e ) verbose_router_logger.debug(traceback.format_exc()) @@ -151,7 +151,9 @@ class LowestTPMLoggingHandler(CustomLogger): """ # get list of potential deployments verbose_router_logger.debug( - f"get_available_deployments - Usage Based. model_group: {model_group}, healthy_deployments: {healthy_deployments}" + "get_available_deployments - Usage Based. model_group: %s, healthy_deployments: %s", + model_group, + healthy_deployments, ) current_minute = datetime.now().strftime("%H-%M") tpm_key = f"{model_group}:tpm:{current_minute}" @@ -160,12 +162,12 @@ class LowestTPMLoggingHandler(CustomLogger): tpm_dict = self.router_cache.get_cache(key=tpm_key) rpm_dict = self.router_cache.get_cache(key=rpm_key) - verbose_router_logger.debug(f"tpm_key={tpm_key}, tpm_dict: {tpm_dict}, rpm_dict: {rpm_dict}") + verbose_router_logger.debug("tpm_key=%s, tpm_dict: %s, rpm_dict: %s", tpm_key, tpm_dict, rpm_dict) try: input_tokens = token_counter(messages=messages, text=input) except Exception: input_tokens = 0 - verbose_router_logger.debug(f"input_tokens={input_tokens}") + verbose_router_logger.debug("input_tokens=%s", input_tokens) # ----------------------- # Find lowest used model # ---------------------- diff --git a/litellm/router_strategy/lowest_tpm_rpm_v2.py b/litellm/router_strategy/lowest_tpm_rpm_v2.py index a81428fd5fa..1d4703f6026 100644 --- a/litellm/router_strategy/lowest_tpm_rpm_v2.py +++ b/litellm/router_strategy/lowest_tpm_rpm_v2.py @@ -245,7 +245,7 @@ class LowestTPMLoggingHandler_v2(BaseRoutingStrategy, CustomLogger): self.logged_success += 1 except Exception as e: verbose_logger.exception( - f"litellm.proxy.hooks.lowest_tpm_rpm_v2.py::log_success_event(): Exception occured - {e}" + "litellm.proxy.hooks.lowest_tpm_rpm_v2.py::log_success_event(): Exception occured - %s", e ) async def async_log_success_event(self, kwargs, response_obj, start_time, end_time): @@ -289,7 +289,7 @@ class LowestTPMLoggingHandler_v2(BaseRoutingStrategy, CustomLogger): self.logged_success += 1 except Exception as e: verbose_logger.exception( - f"litellm.proxy.hooks.lowest_tpm_rpm_v2.py::async_log_success_event(): Exception occured - {e}" + "litellm.proxy.hooks.lowest_tpm_rpm_v2.py::async_log_success_event(): Exception occured - %s", e ) def _return_potential_deployments( @@ -375,7 +375,7 @@ class LowestTPMLoggingHandler_v2(BaseRoutingStrategy, CustomLogger): input_tokens = token_counter(messages=messages, text=input) except Exception: input_tokens = 0 - verbose_router_logger.debug(f"input_tokens={input_tokens}") + verbose_router_logger.debug("input_tokens=%s", input_tokens) # ----------------------- # Find lowest used model # ---------------------- @@ -420,7 +420,9 @@ class LowestTPMLoggingHandler_v2(BaseRoutingStrategy, CustomLogger): """ # get list of potential deployments verbose_router_logger.debug( - f"get_available_deployments - Usage Based. model_group: {model_group}, healthy_deployments: {healthy_deployments}" + "get_available_deployments - Usage Based. model_group: %s, healthy_deployments: %s", + model_group, + healthy_deployments, ) dt = get_utc_datetime() @@ -535,7 +537,9 @@ class LowestTPMLoggingHandler_v2(BaseRoutingStrategy, CustomLogger): """ # get list of potential deployments verbose_router_logger.debug( - f"get_available_deployments - Usage Based. model_group: {model_group}, healthy_deployments: {healthy_deployments}" + "get_available_deployments - Usage Based. model_group: %s, healthy_deployments: %s", + model_group, + healthy_deployments, ) dt = get_utc_datetime() diff --git a/litellm/router_strategy/quality_router/quality_router.py b/litellm/router_strategy/quality_router/quality_router.py index da6825a5741..a84ee70864a 100644 --- a/litellm/router_strategy/quality_router/quality_router.py +++ b/litellm/router_strategy/quality_router/quality_router.py @@ -85,9 +85,10 @@ class QualityRouter(CustomLogger): self._tier_to_models_cache: dict[int, list[str]] | None = None verbose_router_logger.debug( - f"QualityRouter initialized for {model_name} with " - f"available_models={self.config.available_models}, " - f"default_model={self.config.default_model}" + "QualityRouter initialized for %s with available_models=%s, default_model=%s", + model_name, + self.config.available_models, + self.config.default_model, ) @property @@ -371,10 +372,11 @@ class QualityRouter(CustomLogger): if keyword_match is not None: routed_model, matched_keyword = keyword_match verbose_router_logger.info( - f"QualityRouter: keyword override matched='{matched_keyword}' " - f"routed_model={routed_model} " - f"(quality_tier={self._model_quality.get(routed_model)}, " - f"input_cost_per_token={self._model_cost.get(routed_model)})" + "QualityRouter: keyword override matched='%s' routed_model=%s (quality_tier=%s, input_cost_per_token=%s)", + matched_keyword, + routed_model, + self._model_quality.get(routed_model), + self._model_cost.get(routed_model), ) self._stash_decision( request_kwargs, diff --git a/litellm/router_strategy/simple_shuffle.py b/litellm/router_strategy/simple_shuffle.py index ab2fab09a0d..1a2abac4b05 100644 --- a/litellm/router_strategy/simple_shuffle.py +++ b/litellm/router_strategy/simple_shuffle.py @@ -44,7 +44,7 @@ def simple_shuffle( weight = healthy_deployments[0].get("litellm_params").get(weight_by, None) if weight is not None: weights = [m["litellm_params"].get(weight_by, 0) for m in healthy_deployments] - verbose_router_logger.debug(f"\nweight {weights}") + verbose_router_logger.debug("\nweight %s", weights) total_weight = sum(weights) if total_weight <= 0: # All remaining candidates have weight 0 for this metric (e.g. @@ -54,13 +54,16 @@ def simple_shuffle( # through to the uniform random pick at the end. continue weights = [weight / total_weight for weight in weights] - verbose_router_logger.debug(f"\n weights {weights} by {weight_by}") + verbose_router_logger.debug("\n weights %s by %s", weights, weight_by) # Perform weighted random pick selected_index = random.choices(range(len(weights)), weights=weights)[0] - verbose_router_logger.debug(f"\n selected index, {selected_index}") + verbose_router_logger.debug("\n selected index, %s", selected_index) deployment = healthy_deployments[selected_index] verbose_router_logger.info( - f"get_available_deployment for model: {model}, Selected deployment: {llm_router_instance.print_deployment(deployment) or deployment[0]} for model: {model}" + "get_available_deployment for model: %s, Selected deployment: %s for model: %s", + model, + llm_router_instance.print_deployment(deployment) or deployment[0], + model, ) return deployment or deployment[0] diff --git a/litellm/router_utils/batch_utils.py b/litellm/router_utils/batch_utils.py index eefacb7c9e6..c968e8dfde8 100644 --- a/litellm/router_utils/batch_utils.py +++ b/litellm/router_utils/batch_utils.py @@ -52,7 +52,7 @@ def parse_jsonl_with_embedded_newlines(content: str) -> list[dict]: json_object = json.loads(buffer.strip()) json_objects.append(json_object) except json.JSONDecodeError as e: - verbose_logger.error(f"error parsing final buffer: {buffer[:100]}..., error: {e}") + verbose_logger.error("error parsing final buffer: %s..., error: %s", buffer[:100], e) raise e return json_objects @@ -128,7 +128,7 @@ def replace_model_in_jsonl(file_content: FileTypes, new_model_name: str) -> File # that followed it). Returning the partial `output` would silently # drop those rows; return the unchanged original so the provider # rejects the batch loudly instead of accepting a truncated one. - verbose_logger.error(f"error parsing trailing batch content: {buffer[:100]}...") + verbose_logger.error("error parsing trailing batch content: %s...", buffer[:100]) if hasattr(source, "seek"): try: source.seek(0) # type: ignore[attr-defined] diff --git a/litellm/router_utils/cooldown_cache.py b/litellm/router_utils/cooldown_cache.py index 4e9a11a4bfd..4681609b9d7 100644 --- a/litellm/router_utils/cooldown_cache.py +++ b/litellm/router_utils/cooldown_cache.py @@ -58,7 +58,7 @@ class CooldownCache: return cooldown_key, cooldown_data except Exception as e: - verbose_logger.error(f"CooldownCache::_common_add_cooldown_logic - Exception occurred - {e}") + verbose_logger.error("CooldownCache::_common_add_cooldown_logic - Exception occurred - %s", e) raise e def add_deployment_to_cooldown( @@ -92,7 +92,7 @@ class CooldownCache: ttl=_cooldown_time, ) except Exception as e: - verbose_logger.error(f"CooldownCache::add_deployment_to_cooldown - Exception occurred - {e}") + verbose_logger.error("CooldownCache::add_deployment_to_cooldown - Exception occurred - %s", e) raise e @staticmethod diff --git a/litellm/router_utils/cooldown_callbacks.py b/litellm/router_utils/cooldown_callbacks.py index acd1c5b47ad..94e2847121b 100644 --- a/litellm/router_utils/cooldown_callbacks.py +++ b/litellm/router_utils/cooldown_callbacks.py @@ -34,7 +34,8 @@ async def router_cooldown_event_callback( _deployment = litellm_router_instance.get_deployment(model_id=deployment_id) if _deployment is None: verbose_logger.warning( - f"in router_cooldown_event_callback but _deployment is None for deployment_id={deployment_id}. Doing nothing" + "in router_cooldown_event_callback but _deployment is None for deployment_id=%s. Doing nothing", + deployment_id, ) return _litellm_params = _deployment["litellm_params"] diff --git a/litellm/router_utils/cooldown_handlers.py b/litellm/router_utils/cooldown_handlers.py index 380689e653b..ca5fe198abb 100644 --- a/litellm/router_utils/cooldown_handlers.py +++ b/litellm/router_utils/cooldown_handlers.py @@ -281,7 +281,7 @@ def _set_cooldown_deployments( return False exception_status_int = cast_exception_status_to_int(exception_status) - verbose_router_logger.debug(f"Attempting to add {deployment} to cooldown list") + verbose_router_logger.debug("Attempting to add %s to cooldown list", deployment) if _should_cooldown_deployment( litellm_router_instance=litellm_router_instance, @@ -331,7 +331,7 @@ async def _async_get_cooldown_deployments( ): cached_value_deployment_ids = [cv[0] for cv in cooldown_models] - verbose_router_logger.debug(f"retrieve cooldown models: {cooldown_models}") + verbose_router_logger.debug("retrieve cooldown models: %s", cooldown_models) return cached_value_deployment_ids @@ -347,7 +347,7 @@ async def _async_get_cooldown_deployments_with_debug_info( model_ids=model_ids, parent_otel_span=parent_otel_span ) - verbose_router_logger.debug(f"retrieve cooldown models: {cooldown_models}") + verbose_router_logger.debug("retrieve cooldown models: %s", cooldown_models) return cooldown_models @@ -432,7 +432,7 @@ def cast_exception_status_to_int(exception_status: str | int) -> int: exception_status = int(exception_status) except Exception: verbose_router_logger.debug( - f"Unable to cast exception status to int {exception_status}. Defaulting to status=500." + "Unable to cast exception status to int %s. Defaulting to status=500.", exception_status ) exception_status = 500 return exception_status diff --git a/litellm/router_utils/fallback_event_handlers.py b/litellm/router_utils/fallback_event_handlers.py index 3fad860fa7d..e2fcd9109d2 100644 --- a/litellm/router_utils/fallback_event_handlers.py +++ b/litellm/router_utils/fallback_event_handlers.py @@ -127,7 +127,7 @@ async def run_async_fallback( try: # LOGGING kwargs = litellm_router.log_retry(kwargs=kwargs, e=original_exception) - verbose_router_logger.info(f"Falling back to model_group = {mask_sensitive_structure(mg)}") + verbose_router_logger.info("Falling back to model_group = %s", mask_sensitive_structure(mg)) if isinstance(mg, str): kwargs["model"] = mg elif isinstance(mg, dict): @@ -190,7 +190,7 @@ async def log_success_fallback_event(original_model_group: str, kwargs: dict, or original_exception=original_exception, ) except Exception as e: - verbose_router_logger.error(f"Error in log_success_fallback_event: {e}") + verbose_router_logger.error("Error in log_success_fallback_event: %s", e) async def log_failure_fallback_event(original_model_group: str, kwargs: dict, original_exception: Exception): @@ -218,7 +218,7 @@ async def log_failure_fallback_event(original_model_group: str, kwargs: dict, or original_exception=original_exception, ) except Exception as e: - verbose_router_logger.error(f"Error in log_failure_fallback_event: {e}") + verbose_router_logger.error("Error in log_failure_fallback_event: %s", e) def _check_non_standard_fallback_format(fallbacks: list[Any] | None) -> bool: diff --git a/litellm/router_utils/handle_error.py b/litellm/router_utils/handle_error.py index b38d6605ed2..c25238a89b3 100644 --- a/litellm/router_utils/handle_error.py +++ b/litellm/router_utils/handle_error.py @@ -74,7 +74,7 @@ async def async_raise_no_deployment_exception( """ Raises a RouterRateLimitError if no deployment is found for the given model. """ - verbose_router_logger.info(f"get_available_deployment for model: {model}, No deployment available") + verbose_router_logger.info("get_available_deployment for model: %s, No deployment available", model) model_ids = litellm_router_instance.get_model_ids(model_name=model) _cooldown_time = litellm_router_instance.cooldown_cache.get_min_cooldown( model_ids=model_ids, parent_otel_span=parent_otel_span @@ -84,7 +84,7 @@ async def async_raise_no_deployment_exception( parent_otel_span=parent_otel_span, ) verbose_router_logger.info( - f"No deployment found for model: {model}, cooldown_list with debug info: {_cooldown_list}" + "No deployment found for model: %s, cooldown_list with debug info: %s", model, _cooldown_list ) cooldown_list_ids = [cooldown_model[0] for cooldown_model in (_cooldown_list or [])] diff --git a/litellm/router_utils/pattern_match_deployments.py b/litellm/router_utils/pattern_match_deployments.py index 42704cea826..c8161529626 100644 --- a/litellm/router_utils/pattern_match_deployments.py +++ b/litellm/router_utils/pattern_match_deployments.py @@ -150,7 +150,7 @@ class PatternMatchRouter: matched_pattern=pattern_match, deployments=llm_deployments ) except Exception as e: - verbose_router_logger.debug(f"Error in PatternMatchRouter.route: {e}") + verbose_router_logger.debug("Error in PatternMatchRouter.route: %s", e) return None # No matching pattern found diff --git a/litellm/router_utils/pre_call_checks/io_token_rate_limit_check.py b/litellm/router_utils/pre_call_checks/io_token_rate_limit_check.py index 9561eafa900..4dd6944d791 100644 --- a/litellm/router_utils/pre_call_checks/io_token_rate_limit_check.py +++ b/litellm/router_utils/pre_call_checks/io_token_rate_limit_check.py @@ -551,16 +551,20 @@ def io_token_reconcile_success( ) else: verbose_router_logger.debug( - "[IO TOKEN LIMIT] usage missing; keeping reservation " - f"(itpm_reserved={itpm_reserved}, otpm_reserved={otpm_reserved})" + "[IO TOKEN LIMIT] usage missing; keeping reservation (itpm_reserved=%s, otpm_reserved=%s)", + itpm_reserved, + otpm_reserved, ) finally: _clear_reservation_from_kwargs(kwargs) verbose_router_logger.debug( - f"[IO TOKEN LIMIT] reconciled " - f"(usage_resolved={usage_resolved}, itpm_reserved={itpm_reserved}, " - f"billable_input={billable_input}, otpm_reserved={otpm_reserved}, output={completion_tokens})" + "[IO TOKEN LIMIT] reconciled (usage_resolved=%s, itpm_reserved=%s, billable_input=%s, otpm_reserved=%s, output=%s)", + usage_resolved, + itpm_reserved, + billable_input, + otpm_reserved, + completion_tokens, ) @@ -606,16 +610,20 @@ async def async_io_token_reconcile_success( ) else: verbose_router_logger.debug( - "[IO TOKEN LIMIT] usage missing; keeping reservation " - f"(itpm_reserved={itpm_reserved}, otpm_reserved={otpm_reserved})" + "[IO TOKEN LIMIT] usage missing; keeping reservation (itpm_reserved=%s, otpm_reserved=%s)", + itpm_reserved, + otpm_reserved, ) finally: _clear_reservation_from_kwargs(kwargs) verbose_router_logger.debug( - f"[IO TOKEN LIMIT] reconciled " - f"(usage_resolved={usage_resolved}, itpm_reserved={itpm_reserved}, " - f"billable_input={billable_input}, otpm_reserved={otpm_reserved}, output={completion_tokens})" + "[IO TOKEN LIMIT] reconciled (usage_resolved=%s, itpm_reserved=%s, billable_input=%s, otpm_reserved=%s, output=%s)", + usage_resolved, + itpm_reserved, + billable_input, + otpm_reserved, + completion_tokens, ) @@ -639,7 +647,7 @@ def io_token_refund_failure( ttl=RoutingArgsTTL, ) _clear_reservation_from_kwargs(kwargs) - verbose_router_logger.debug(f"[IO TOKEN LIMIT] refunded ITPM={itpm_reserved} OTPM={otpm_reserved}") + verbose_router_logger.debug("[IO TOKEN LIMIT] refunded ITPM=%s OTPM=%s", itpm_reserved, otpm_reserved) def refund_stale_reservation_before_retry(dual_cache: DualCache, kwargs: dict[str, Any] | None) -> None: @@ -693,7 +701,7 @@ async def async_io_token_refund_failure( parent_otel_span=parent_otel_span, ) _clear_reservation_from_kwargs(kwargs) - verbose_router_logger.debug(f"[IO TOKEN LIMIT] refunded ITPM={itpm_reserved} OTPM={otpm_reserved}") + verbose_router_logger.debug("[IO TOKEN LIMIT] refunded ITPM=%s OTPM=%s", itpm_reserved, otpm_reserved) def build_io_token_rate_limit_headers( diff --git a/litellm/router_utils/pre_call_checks/model_rate_limit_check.py b/litellm/router_utils/pre_call_checks/model_rate_limit_check.py index da8b452fa8a..416b53f3267 100644 --- a/litellm/router_utils/pre_call_checks/model_rate_limit_check.py +++ b/litellm/router_utils/pre_call_checks/model_rate_limit_check.py @@ -75,8 +75,8 @@ class ModelRateLimitingCheck(CustomLogger): return self._io_token_conflict_warned_ids.add(str(model_id)) verbose_router_logger.warning( - f"Deployment '{model_id}' configures itpm/otpm alongside tpm/rpm; " - "both limit types are enforced on this deployment" + "Deployment '%s' configures itpm/otpm alongside tpm/rpm; both limit types are enforced on this deployment", + model_id, ) def _refund_io_token_reservation_if_any(self) -> None: @@ -212,7 +212,7 @@ class ModelRateLimitingCheck(CustomLogger): self._refund_io_token_reservation_if_any() raise except Exception as e: - verbose_router_logger.debug(f"Error in ModelRateLimitingCheck.pre_call_check: {e}") + verbose_router_logger.debug("Error in ModelRateLimitingCheck.pre_call_check: %s", e) # Don't fail the request if rate limit check fails return deployment @@ -300,7 +300,7 @@ class ModelRateLimitingCheck(CustomLogger): await self._async_refund_io_token_reservation_if_any(parent_otel_span=parent_otel_span) raise except Exception as e: - verbose_router_logger.debug(f"Error in ModelRateLimitingCheck.async_pre_call_check: {e}") + verbose_router_logger.debug("Error in ModelRateLimitingCheck.async_pre_call_check: %s", e) # Don't fail the request if rate limit check fails return deployment @@ -341,7 +341,7 @@ class ModelRateLimitingCheck(CustomLogger): model = standard_logging_object.get("hidden_params", {}).get("litellm_model_name") verbose_router_logger.debug( - f"[TPM TRACKING] model_id={model_id}, total_tokens={total_tokens}, model={model}" + "[TPM TRACKING] model_id=%s, total_tokens=%s, model=%s", model_id, total_tokens, model ) if not model or not total_tokens: @@ -351,7 +351,7 @@ class ModelRateLimitingCheck(CustomLogger): current_minute = dt.strftime("%H-%M") tpm_key = f"{model_id}:{model}:tpm:{current_minute}" - verbose_router_logger.debug(f"[TPM TRACKING] Incrementing {tpm_key} by {total_tokens}") + verbose_router_logger.debug("[TPM TRACKING] Incrementing %s by %s", tpm_key, total_tokens) await self.dual_cache.async_increment_cache( key=tpm_key, @@ -360,7 +360,7 @@ class ModelRateLimitingCheck(CustomLogger): ) except Exception as e: - verbose_router_logger.debug(f"Error in ModelRateLimitingCheck.async_log_success_event: {e}") + verbose_router_logger.debug("Error in ModelRateLimitingCheck.async_log_success_event: %s", e) async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time): from litellm.litellm_core_utils.core_helpers import ( @@ -418,7 +418,7 @@ class ModelRateLimitingCheck(CustomLogger): ) except Exception as e: - verbose_router_logger.debug(f"Error in ModelRateLimitingCheck.log_success_event: {e}") + verbose_router_logger.debug("Error in ModelRateLimitingCheck.log_success_event: %s", e) def log_failure_event(self, kwargs, response_obj, start_time, end_time): with contextlib.suppress(Exception): diff --git a/litellm/router_utils/search_api_router.py b/litellm/router_utils/search_api_router.py index 0ce0d4229c1..5708b772970 100644 --- a/litellm/router_utils/search_api_router.py +++ b/litellm/router_utils/search_api_router.py @@ -57,7 +57,7 @@ class SearchAPIRouter: try: from litellm.types.router import SearchToolTypedDict - verbose_router_logger.debug(f"Adding {len(search_tools)} search tools to router") + verbose_router_logger.debug("Adding %s search tools to router", len(search_tools)) # Convert search tools to the format expected by the router router_search_tools: list = [] @@ -74,10 +74,10 @@ class SearchAPIRouter: # Update the router's search_tools list router_instance.search_tools = router_search_tools - verbose_router_logger.info(f"Successfully updated router with {len(router_search_tools)} search tool(s)") + verbose_router_logger.info("Successfully updated router with %s search tool(s)", len(router_search_tools)) except Exception as e: - verbose_router_logger.exception(f"Error updating router with search tools: {e}") + verbose_router_logger.exception("Error updating router with search tools: %s", e) raise e @staticmethod @@ -149,7 +149,10 @@ class SearchAPIRouter: available_search_tool_names = [tool.get("search_tool_name") for tool in router_instance.search_tools] verbose_router_logger.debug( - f"Inside SearchAPIRouter.async_search_with_fallbacks() - search_tool_name: {search_tool_name}, Available Search Tools: {available_search_tool_names}, kwargs: {kwargs}" + "Inside SearchAPIRouter.async_search_with_fallbacks() - search_tool_name: %s, Available Search Tools: %s, kwargs: %s", + search_tool_name, + available_search_tool_names, + kwargs, ) # Use the existing retry/fallback infrastructure @@ -212,7 +215,7 @@ class SearchAPIRouter: tool_litellm_params=litellm_params, ) - verbose_router_logger.debug(f"Selected search tool with provider: {search_provider}") + verbose_router_logger.debug("Selected search tool with provider: %s", search_provider) # Call the original search function with the provider config response = await original_generic_function( @@ -226,6 +229,6 @@ class SearchAPIRouter: except Exception as e: verbose_router_logger.error( - f"Error in SearchAPIRouter.async_search_with_fallbacks_helper for {search_tool_name}: {e}" + "Error in SearchAPIRouter.async_search_with_fallbacks_helper for %s: %s", search_tool_name, e ) raise e diff --git a/litellm/sandbox/main.py b/litellm/sandbox/main.py index eae7e5c097a..3210e327fef 100644 --- a/litellm/sandbox/main.py +++ b/litellm/sandbox/main.py @@ -141,4 +141,4 @@ async def acode_interpreter_tool( try: await config.adelete_sandbox(container=container, api_key=api_key, api_base=api_base, **forwarded) except Exception as e: - litellm._logging.verbose_logger.debug(f"sandbox: failed to delete ephemeral container: {e}") + litellm._logging.verbose_logger.debug("sandbox: failed to delete ephemeral container: %s", e) diff --git a/litellm/search/main.py b/litellm/search/main.py index 932a73c0955..af9b1f7a745 100644 --- a/litellm/search/main.py +++ b/litellm/search/main.py @@ -247,7 +247,7 @@ def search( if search_provider_config is None: raise ValueError(f"Search is not supported for provider: {search_provider}") - verbose_logger.debug(f"Search call - provider: {search_provider}") + verbose_logger.debug("Search call - provider: %s", search_provider) # Build optional_params from explicit parameters optional_params = _build_search_optional_params( @@ -265,7 +265,7 @@ def search( if key not in optional_params: optional_params[key] = value - verbose_logger.debug(f"Search optional_params: {optional_params}") + verbose_logger.debug("Search optional_params: %s", optional_params) # Validate environment and get headers headers = search_provider_config.validate_environment( diff --git a/litellm/secret_managers/cyberark_secret_manager.py b/litellm/secret_managers/cyberark_secret_manager.py index 6e7eb742088..0e8aa2a5b3a 100644 --- a/litellm/secret_managers/cyberark_secret_manager.py +++ b/litellm/secret_managers/cyberark_secret_manager.py @@ -143,17 +143,17 @@ class CyberArkSecretManager(BaseSecretManager): content=policy_yaml, ) resp.raise_for_status() - verbose_logger.debug(f"Created policy entry for variable: {secret_name}") + verbose_logger.debug("Created policy entry for variable: %s", secret_name) except httpx.HTTPStatusError as e: # Variable might already exist, which is fine if e.response.status_code in [409, 422]: - verbose_logger.debug(f"Variable {secret_name} already exists or policy conflict (expected)") + verbose_logger.debug("Variable %s already exists or policy conflict (expected)", secret_name) else: verbose_logger.warning( - f"Could not ensure variable exists: {e.response.status_code} - {e.response.text}" + "Could not ensure variable exists: %s - %s", e.response.status_code, e.response.text ) except Exception as e: - verbose_logger.warning(f"Error ensuring variable exists: {e}") + verbose_logger.warning("Error ensuring variable exists: %s", e) def get_url(self, secret_name: str) -> str: """ @@ -207,12 +207,12 @@ class CyberArkSecretManager(BaseSecretManager): except httpx.HTTPStatusError as e: if e.response.status_code == 404: - verbose_logger.debug(f"Secret {secret_name} not found in CyberArk Conjur") + verbose_logger.debug("Secret %s not found in CyberArk Conjur", secret_name) else: - verbose_logger.exception(f"Error reading secret from CyberArk Conjur: {e}") + verbose_logger.exception("Error reading secret from CyberArk Conjur: %s", e) return None except Exception as e: - verbose_logger.exception(f"Error reading secret from CyberArk Conjur: {e}") + verbose_logger.exception("Error reading secret from CyberArk Conjur: %s", e) return None def sync_read_secret( @@ -250,12 +250,12 @@ class CyberArkSecretManager(BaseSecretManager): except httpx.HTTPStatusError as e: if e.response.status_code == 404: - verbose_logger.debug(f"Secret {secret_name} not found in CyberArk Conjur") + verbose_logger.debug("Secret %s not found in CyberArk Conjur", secret_name) else: - verbose_logger.exception(f"Error reading secret from CyberArk Conjur: {e}") + verbose_logger.exception("Error reading secret from CyberArk Conjur: %s", e) return None except Exception as e: - verbose_logger.exception(f"Error reading secret from CyberArk Conjur: {e}") + verbose_logger.exception("Error reading secret from CyberArk Conjur: %s", e) return None async def async_write_secret( @@ -303,7 +303,7 @@ class CyberArkSecretManager(BaseSecretManager): "message": f"Secret {secret_name} written successfully", } except Exception as e: - verbose_logger.exception(f"Error writing secret to CyberArk Conjur: {e}") + verbose_logger.exception("Error writing secret to CyberArk Conjur: %s", e) return {"status": "error", "message": str(e)} async def async_delete_secret( diff --git a/litellm/secret_managers/get_azure_ad_token_provider.py b/litellm/secret_managers/get_azure_ad_token_provider.py index ed348865859..fc3841008f3 100644 --- a/litellm/secret_managers/get_azure_ad_token_provider.py +++ b/litellm/secret_managers/get_azure_ad_token_provider.py @@ -69,7 +69,7 @@ def get_azure_ad_token_provider( if azure_credential else None or os.environ.get("AZURE_CREDENTIAL") or infer_credential_type_from_environment() ) - verbose_logger.info(f"For Azure AD Token Provider, choosing credential type: {cred}") + verbose_logger.info("For Azure AD Token Provider, choosing credential type: %s", cred) credential: ( ClientSecretCredential | ManagedIdentityCredential | CertificateCredential | DefaultAzureCredential | Any | None ) = None diff --git a/litellm/secret_managers/hashicorp_secret_manager.py b/litellm/secret_managers/hashicorp_secret_manager.py index 3f15a4fe5f5..12dae2af706 100644 --- a/litellm/secret_managers/hashicorp_secret_manager.py +++ b/litellm/secret_managers/hashicorp_secret_manager.py @@ -135,7 +135,7 @@ class HashicorpSecretManager(BaseSecretManager): _lease_duration = auth_data["lease_duration"] verbose_logger.debug( - f"Successfully obtained Vault token via AppRole auth. Lease duration: {_lease_duration}s" + "Successfully obtained Vault token via AppRole auth. Lease duration: %ss", _lease_duration ) # Cache the token with its lease duration @@ -337,7 +337,7 @@ class HashicorpSecretManager(BaseSecretManager): return _value except Exception as e: - verbose_logger.exception(f"Error reading secret from Hashicorp Vault: {e}") + verbose_logger.exception("Error reading secret from Hashicorp Vault: %s", e) return None def sync_read_secret( @@ -368,7 +368,7 @@ class HashicorpSecretManager(BaseSecretManager): return _value except Exception as e: - verbose_logger.exception(f"Error reading secret from Hashicorp Vault: {e}") + verbose_logger.exception("Error reading secret from Hashicorp Vault: %s", e) return None async def async_write_secret( @@ -415,7 +415,7 @@ class HashicorpSecretManager(BaseSecretManager): response.raise_for_status() return response.json() except Exception as e: - verbose_logger.exception(f"Error writing secret to Hashicorp Vault: {e}") + verbose_logger.exception("Error writing secret to Hashicorp Vault: %s", e) return {"status": "error", "message": str(e)} async def async_rotate_secret( @@ -459,20 +459,20 @@ class HashicorpSecretManager(BaseSecretManager): # Secret exists, we can proceed except httpx.HTTPStatusError as e: if e.response.status_code == 404: - verbose_logger.exception(f"Current secret {current_secret_name} not found") + verbose_logger.exception("Current secret %s not found", current_secret_name) return { "status": "error", "message": f"Current secret {current_secret_name} not found", } verbose_logger.exception( - f"Error checking current secret existence: {e.response.text if hasattr(e, 'response') else str(e)}" + "Error checking current secret existence: %s", e.response.text if hasattr(e, "response") else str(e) ) return { "status": "error", "message": f"HTTP error occurred while checking current secret: {e.response.text if hasattr(e, 'response') else str(e)}", } except Exception as e: - verbose_logger.exception(f"Error checking current secret existence: {e}") + verbose_logger.exception("Error checking current secret existence: %s", e) return { "status": "error", "message": f"Error checking current secret: {e}", @@ -506,7 +506,9 @@ class HashicorpSecretManager(BaseSecretManager): new_secret_value_from_vault = json_resp.get("data", {}).get("data", {}).get(data_key, None) if new_secret_value_from_vault != new_secret_value: verbose_logger.exception( - f"New secret value mismatch. Expected: {new_secret_value}, Got: {new_secret_value_from_vault}" + "New secret value mismatch. Expected: %s, Got: %s", + new_secret_value, + new_secret_value_from_vault, ) return { "status": "error", @@ -514,20 +516,20 @@ class HashicorpSecretManager(BaseSecretManager): } except httpx.HTTPStatusError as e: if e.response.status_code == 404: - verbose_logger.exception(f"Failed to verify new secret {new_secret_name}") + verbose_logger.exception("Failed to verify new secret %s", new_secret_name) return { "status": "error", "message": f"Failed to verify new secret {new_secret_name}", } verbose_logger.exception( - f"Error verifying new secret: {e.response.text if hasattr(e, 'response') else str(e)}" + "Error verifying new secret: %s", e.response.text if hasattr(e, "response") else str(e) ) return { "status": "error", "message": f"HTTP error occurred while verifying new secret: {e.response.text if hasattr(e, 'response') else str(e)}", } except Exception as e: - verbose_logger.exception(f"Error verifying new secret: {e}") + verbose_logger.exception("Error verifying new secret: %s", e) return { "status": "error", "message": f"Error verifying new secret: {e}", @@ -546,7 +548,9 @@ class HashicorpSecretManager(BaseSecretManager): if isinstance(delete_response, dict) and delete_response.get("status") == "error": # Log the error but don't fail the rotation since new secret was created successfully verbose_logger.warning( - f"Failed to delete old secret {current_secret_name} after rotation: {delete_response.get('message')}" + "Failed to delete old secret %s after rotation: %s", + current_secret_name, + delete_response.get("message"), ) else: # Clear cache for the old secret only if deletion was successful @@ -561,7 +565,7 @@ class HashicorpSecretManager(BaseSecretManager): verbose_logger.exception("Timeout error occurred during secret rotation") return {"status": "error", "message": "Timeout error occurred"} except Exception as e: - verbose_logger.exception(f"Error rotating secret in Hashicorp Vault: {e}") + verbose_logger.exception("Error rotating secret in Hashicorp Vault: %s", e) return {"status": "error", "message": str(e)} async def async_delete_secret( @@ -604,7 +608,7 @@ class HashicorpSecretManager(BaseSecretManager): "message": f"Secret {target['secret_name']} deleted successfully", } except Exception as e: - verbose_logger.exception(f"Error deleting secret from Hashicorp Vault: {e}") + verbose_logger.exception("Error deleting secret from Hashicorp Vault: %s", e) return {"status": "error", "message": str(e)} def _get_secret_value_from_json_response(self, json_resp: dict | None) -> str | None: diff --git a/litellm/secret_managers/main.py b/litellm/secret_managers/main.py index 2982d30274b..a3094bc06a1 100644 --- a/litellm/secret_managers/main.py +++ b/litellm/secret_managers/main.py @@ -335,7 +335,10 @@ def get_secret( ) except Exception as e: # check if it's in os.environ verbose_logger.error( - f"Defaulting to os.environ value for key={secret_name}. An exception occurred - {e}.\n\n{traceback.format_exc()}" + "Defaulting to os.environ value for key=%s. An exception occurred - %s.\n\n%s", + secret_name, + e, + traceback.format_exc(), ) secret = os.getenv(secret_name) try: diff --git a/litellm/types/proxy/guardrails/guardrail_hooks/zscaler_ai_guard.py b/litellm/types/proxy/guardrails/guardrail_hooks/zscaler_ai_guard.py index f522f5b470a..c4eb5c39f1c 100644 --- a/litellm/types/proxy/guardrails/guardrail_hooks/zscaler_ai_guard.py +++ b/litellm/types/proxy/guardrails/guardrail_hooks/zscaler_ai_guard.py @@ -102,7 +102,7 @@ class ZscalerAIGuardConfigModel(GuardrailConfigModel): policy_id = int(env_policy) except ValueError: verbose_proxy_logger.warning( - f"ZSCALER_AI_GUARD_POLICY_ID env var is not a valid integer: {env_policy}" + "ZSCALER_AI_GUARD_POLICY_ID env var is not a valid integer: %s", env_policy ) # Check for configuration issues diff --git a/litellm/types/videos/utils.py b/litellm/types/videos/utils.py index f1b20618a74..1b701260f2f 100644 --- a/litellm/types/videos/utils.py +++ b/litellm/types/videos/utils.py @@ -105,7 +105,7 @@ def decode_video_id_with_provider(encoded_video_id: str) -> DecodedVideoId: video_id=decoded_video_id, ) except Exception as e: - verbose_logger.debug(f"Error decoding video_id '{encoded_video_id}': {e}") + verbose_logger.debug("Error decoding video_id '%s': %s", encoded_video_id, e) return DecodedVideoId( custom_llm_provider=None, model_id=None, @@ -182,7 +182,7 @@ def decode_character_id_with_provider(encoded_character_id: str) -> DecodedChara character_id=decoded_character_id, ) except Exception as e: - verbose_logger.debug(f"Error decoding character_id '{encoded_character_id}': {e}") + verbose_logger.debug("Error decoding character_id '%s': %s", encoded_character_id, e) return DecodedCharacterId( custom_llm_provider=None, model_id=None, diff --git a/litellm/utils.py b/litellm/utils.py index eb3e578b7e8..5dbff5070aa 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -513,7 +513,9 @@ def _add_custom_logger_callback_to_specific_event(callback: str, logging_event: if callback not in litellm._known_custom_logger_compatible_callbacks: verbose_logger.debug( - f"Callback {callback} is not a valid custom logger compatible callback. Known list - {litellm._known_custom_logger_compatible_callbacks}" + "Callback %s is not a valid custom logger compatible callback. Known list - %s", + callback, + litellm._known_custom_logger_compatible_callbacks, ) return @@ -947,7 +949,7 @@ def function_setup( except Exception as e: # Log the error but don't fail the request - verbose_logger.warning(f"Error removing thought signatures from tool call IDs: {e}") + verbose_logger.warning("Error removing thought signatures from tool call IDs: %s", e) elif call_type == CallTypes.embedding.value or call_type == CallTypes.aembedding.value: messages = args[1] if len(args) > 1 else kwargs.get("input", None) elif call_type == CallTypes.image_generation.value or call_type == CallTypes.aimage_generation.value: @@ -1004,7 +1006,7 @@ def function_setup( else: messages = "default-message-value" except Exception as e: - verbose_logger.debug(f"Error extracting messages from Google contents: {e}") + verbose_logger.debug("Error extracting messages from Google contents: %s", e) messages = "default-message-value" else: messages = "default-message-value" @@ -1951,7 +1953,7 @@ def _select_tokenizer_helper(model: str) -> SelectTokenizerResponse: if result is not None: return result except Exception as e: - verbose_logger.debug(f"Error selecting tokenizer: {e}") + verbose_logger.debug("Error selecting tokenizer: %s", e) # default - tiktoken return _return_openai_tokenizer(model) @@ -2064,7 +2066,7 @@ def create_pretrained_tokenizer(identifier: str, revision="main", auth_token: st auth_token=auth_token, # type: ignore ) except Exception as e: - verbose_logger.error(f"Error creating pretrained tokenizer: {e}. Defaulting to version without 'auth_token'.") + verbose_logger.error("Error creating pretrained tokenizer: %s. Defaulting to version without 'auth_token'.", e) tokenizer = Tokenizer.from_pretrained(identifier, revision=revision) return {"type": "huggingface_tokenizer", "tokenizer": tokenizer} @@ -2224,7 +2226,10 @@ def supports_native_streaming(model: str, custom_llm_provider: str | None) -> bo return supports_native_streaming except Exception as e: verbose_logger.debug( - f"Model not found or error in checking supports_native_streaming support. You passed model={model}, custom_llm_provider={custom_llm_provider}. Error: {e}" + "Model not found or error in checking supports_native_streaming support. You passed model=%s, custom_llm_provider=%s. Error: %s", + model, + custom_llm_provider, + e, ) return False @@ -2248,7 +2253,10 @@ def supports_response_schema(model: str, custom_llm_provider: str | None = None) model, custom_llm_provider, _, _ = get_llm_provider(model=model, custom_llm_provider=custom_llm_provider) except Exception as e: verbose_logger.debug( - f"Model not found or error in checking response schema support. You passed model={model}, custom_llm_provider={custom_llm_provider}. Error: {e}" + "Model not found or error in checking response schema support. You passed model=%s, custom_llm_provider=%s. Error: %s", + model, + custom_llm_provider, + e, ) return False @@ -2362,7 +2370,11 @@ def _supports_factory(model: str, custom_llm_provider: str | None, key: str) -> return False except Exception as e: verbose_logger.debug( - f"Model not found or error in checking {key} support. You passed model={model}, custom_llm_provider={custom_llm_provider}. Error: {e}" + "Model not found or error in checking %s support. You passed model=%s, custom_llm_provider=%s. Error: %s", + key, + model, + custom_llm_provider, + e, ) supported_by_provider = _supports_provider_info_factory(model, custom_llm_provider, key) @@ -2402,9 +2414,11 @@ def _is_explicitly_disabled_factory(model: str, custom_llm_provider: str | None, return False except Exception as e: verbose_logger.debug( - f"Model not found or error in checking {key} disabled state. " - f"You passed model={model}, custom_llm_provider={custom_llm_provider}. " - f"Error: {e}" + "Model not found or error in checking %s disabled state. You passed model=%s, custom_llm_provider=%s. Error: %s", + key, + model, + custom_llm_provider, + e, ) return False @@ -2537,7 +2551,10 @@ def get_supported_regions(model: str, custom_llm_provider: str | None = None) -> return None except Exception as e: verbose_logger.debug( - f"Model not found or error in checking supported_regions support. You passed model={model}, custom_llm_provider={custom_llm_provider}. Error: {e}" + "Model not found or error in checking supported_regions support. You passed model=%s, custom_llm_provider=%s. Error: %s", + model, + custom_llm_provider, + e, ) return None @@ -2720,10 +2737,8 @@ def register_model(model_cost: str | dict): and value.get("cache_read_input_token_cost") is None ): verbose_logger.warning( - f"register_model: model={key} not in built-in cost map and no " - "prefix/region variant matched; cache cost fields will default " - "to 0. To track cache cost, add cache_creation_input_token_cost " - "and cache_read_input_token_cost to model_info" + "register_model: model=%s not in built-in cost map and no prefix/region variant matched; cache cost fields will default to 0. To track cache cost, add cache_creation_input_token_cost and cache_read_input_token_cost to model_info", + key, ) # ``get_model_info`` returns ``litellm_provider: None`` when the # provider is unknown (e.g. custom deployments registered via @@ -2754,7 +2769,7 @@ def register_model(model_cost: str | dict): # Invalidate case-insensitive lookup map since model_cost was modified _invalidate_model_cost_lowercase_map() - verbose_logger.debug(f"added/updated model={model_cost_key} in litellm.model_cost: {model_cost_key}") + verbose_logger.debug("added/updated model=%s in litellm.model_cost: %s", model_cost_key, model_cost_key) # add new model names to provider lists if value.get("litellm_provider") == "openai": if key not in litellm.open_ai_chat_completion_models: @@ -3828,9 +3843,9 @@ def get_optional_params( Args: supported_params: List[str] - supported params from the litellm config """ - verbose_logger.info(f"\nLiteLLM completion() model= {model}; provider = {custom_llm_provider}") - verbose_logger.debug(f"\nLiteLLM: Params passed to completion() {passed_params}") - verbose_logger.debug(f"\nLiteLLM: Non-Default params passed to completion() {non_default_params}") + verbose_logger.info("\nLiteLLM completion() model= %s; provider = %s", model, custom_llm_provider) + verbose_logger.debug("\nLiteLLM: Params passed to completion() %s", passed_params) + verbose_logger.debug("\nLiteLLM: Non-Default params passed to completion() %s", non_default_params) unsupported_params = {} for k in non_default_params.keys(): if k not in supported_params: @@ -4571,7 +4586,7 @@ def _infer_model_region(litellm_params: LiteLLM_Params) -> AllowedModelRegion | model_region = _get_model_region(custom_llm_provider=custom_llm_provider, litellm_params=litellm_params) if model_region is None: - verbose_logger.debug(f"Cannot infer model region for model: {litellm_params.model}") + verbose_logger.debug("Cannot infer model region for model: %s", litellm_params.model) return None if custom_llm_provider == "azure": @@ -5238,7 +5253,7 @@ def _get_model_info_helper( ########################## potential_model_names = _get_potential_model_names(model=model, custom_llm_provider=custom_llm_provider) - verbose_logger.debug(f"checking potential_model_names in litellm.model_cost: {potential_model_names}") + verbose_logger.debug("checking potential_model_names in litellm.model_cost: %s", potential_model_names) combined_model_name = potential_model_names["combined_model_name"] stripped_model_name = potential_model_names["stripped_model_name"] @@ -5373,7 +5388,9 @@ def _get_model_info_helper( if _input_cost_per_token is None: # default value to 0, be noisy about this verbose_logger.debug( - f"model={model}, custom_llm_provider={custom_llm_provider} has no input_cost_per_token in model_cost_map. Defaulting to 0." + "model=%s, custom_llm_provider=%s has no input_cost_per_token in model_cost_map. Defaulting to 0.", + model, + custom_llm_provider, ) _input_cost_per_token = 0 @@ -5381,7 +5398,9 @@ def _get_model_info_helper( if _output_cost_per_token is None: # default value to 0, be noisy about this verbose_logger.debug( - f"model={model}, custom_llm_provider={custom_llm_provider} has no output_cost_per_token in model_cost_map. Defaulting to 0." + "model=%s, custom_llm_provider=%s has no output_cost_per_token in model_cost_map. Defaulting to 0.", + model, + custom_llm_provider, ) _output_cost_per_token = 0 @@ -5548,7 +5567,7 @@ def _get_model_info_helper( returned_model_info[cost_key] = cost_value # type: ignore[literal-required] return returned_model_info except Exception as e: - verbose_logger.debug(f"Error getting model info: {e}") + verbose_logger.debug("Error getting model info: %s", e) raise Exception( f"This model isn't mapped yet. model={model}, custom_llm_provider={custom_llm_provider}. Add it here - https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json." ) @@ -6663,13 +6682,13 @@ def process_messages(messages, max_tokens, model): messages = messages[::-1] final_messages = [] verbose_logger.debug( - f"calling process_messages with messages: {messages}, max_tokens: {max_tokens}, model: {model}" + "calling process_messages with messages: %s, max_tokens: %s, model: %s", messages, max_tokens, model ) for message in messages: - verbose_logger.debug(f"processing final_messages: {final_messages}") + verbose_logger.debug("processing final_messages: %s", final_messages) used_tokens = get_token_count(final_messages, model) available_tokens = max_tokens - used_tokens - verbose_logger.debug(f"used_tokens: {used_tokens}, available_tokens: {available_tokens}") + verbose_logger.debug("used_tokens: %s, available_tokens: %s", used_tokens, available_tokens) if available_tokens <= 3: break @@ -6680,15 +6699,15 @@ def process_messages(messages, max_tokens, model): max_tokens=max_tokens, model=model, ) - verbose_logger.debug(f"final_messages after attempt_message_addition: {final_messages}") - verbose_logger.debug(f"Final messages: {final_messages}") + verbose_logger.debug("final_messages after attempt_message_addition: %s", final_messages) + verbose_logger.debug("Final messages: %s", final_messages) return final_messages def attempt_message_addition(final_messages, message, available_tokens, max_tokens, model): temp_messages = [message] + final_messages temp_message_tokens = get_token_count(messages=temp_messages, model=model) - verbose_logger.debug(f"temp_message_tokens: {temp_message_tokens}, max_tokens: {max_tokens}") + verbose_logger.debug("temp_message_tokens: %s, max_tokens: %s", temp_message_tokens, max_tokens) if temp_message_tokens <= max_tokens: return temp_messages @@ -6735,12 +6754,12 @@ def shorten_message_to_fit_limit(message, tokens_needed, model: str | None, rais content = message["content"] attempts = 0 - verbose_logger.debug(f"content: {content}") + verbose_logger.debug("content: %s", content) while attempts < MAX_TOKEN_TRIMMING_ATTEMPTS: - verbose_logger.debug(f"getting token count for message: {message}") + verbose_logger.debug("getting token count for message: %s", message) total_tokens = get_token_count([message], model) - verbose_logger.debug(f"total_tokens: {total_tokens}, tokens_needed: {tokens_needed}") + verbose_logger.debug("total_tokens: %s, tokens_needed: %s", total_tokens, tokens_needed) if total_tokens <= tokens_needed: break @@ -6756,7 +6775,7 @@ def shorten_message_to_fit_limit(message, tokens_needed, model: str | None, rais trimmed_content = left_half + ".." + right_half message["content"] = trimmed_content - verbose_logger.debug(f"trimmed_content: {trimmed_content}") + verbose_logger.debug("trimmed_content: %s", trimmed_content) content = trimmed_content attempts += 1 @@ -6851,9 +6870,9 @@ def trim_messages( # we remove all system messages from the messages list messages = [message for message in messages if message["role"] != "system"] - verbose_logger.debug(f"Processed system message: {system_message_event}") + verbose_logger.debug("Processed system message: %s", system_message_event) final_messages = process_messages(messages=messages, max_tokens=max_tokens, model=model) - verbose_logger.debug(f"Processed messages: {final_messages}") + verbose_logger.debug("Processed messages: %s", final_messages) # Add system message to the beginning of the final messages if system_message_event: @@ -6862,13 +6881,13 @@ def trim_messages( if len(tool_messages) > 0: final_messages.extend(tool_messages) - verbose_logger.debug(f"Final messages: {final_messages}, return_response_tokens: {return_response_tokens}") + verbose_logger.debug("Final messages: %s, return_response_tokens: %s", final_messages, return_response_tokens) if return_response_tokens: # if user wants token count with new trimmed messages response_tokens = max_tokens - get_token_count(final_messages, model) return final_messages, response_tokens return final_messages except Exception as e: # [NON-Blocking, if error occurs just return final_messages - verbose_logger.exception(f"Got exception while token trimming - {e}") + verbose_logger.exception("Got exception while token trimming - %s", e) return original_messages @@ -6982,7 +7001,7 @@ def _get_valid_models_from_provider_api( _model_cache.set_cached_model_info(custom_llm_provider, litellm_params, models) return models except Exception as e: - verbose_logger.warning(f"Error getting valid models: {e}") + verbose_logger.warning("Error getting valid models: %s", e) return [] @@ -7056,7 +7075,7 @@ def get_valid_models( return valid_models except Exception as e: - verbose_logger.warning(f"Error getting valid models: {e}") + verbose_logger.warning("Error getting valid models: %s", e) return [] # NON-Blocking @@ -9112,7 +9131,7 @@ def is_prompt_caching_valid_prompt( min_token_count = get_prompt_cache_min_tokens(model=model) return token_count >= min_token_count except Exception as e: - verbose_logger.error(f"Error in is_prompt_caching_valid_prompt: {e}") + verbose_logger.error("Error in is_prompt_caching_valid_prompt: %s", e) return False diff --git a/litellm/vector_stores/vector_store_registry.py b/litellm/vector_stores/vector_store_registry.py index 1350e2b187e..37866a76797 100644 --- a/litellm/vector_stores/vector_store_registry.py +++ b/litellm/vector_stores/vector_store_registry.py @@ -235,7 +235,7 @@ class VectorStoreRegistry: self.add_vector_store_to_registry(vector_store=db_vector_store) return db_vector_store except Exception as e: - verbose_logger.debug(f"Error fetching vector store from database: {e}") + verbose_logger.debug("Error fetching vector store from database: %s", e) return None @@ -341,12 +341,13 @@ class VectorStoreRegistry: if db_vector_store is None: # Vector store was deleted from database, remove from cache verbose_logger.debug( - f"Vector store {vector_store_id} found in memory but deleted from database, removing from cache" + "Vector store %s found in memory but deleted from database, removing from cache", + vector_store_id, ) self.delete_vector_store_from_registry(vector_store_id=vector_store_id) vector_store = None except Exception as e: - verbose_logger.debug(f"Error verifying vector store {vector_store_id} in database: {e}") + verbose_logger.debug("Error verifying vector store %s in database: %s", vector_store_id, e) # Fall back to database if not found in memory (or was deleted) if vector_store is None and prisma_client is not None: @@ -355,7 +356,7 @@ class VectorStoreRegistry: vector_store_id=vector_store_id, prisma_client=prisma_client ) except Exception as e: - verbose_logger.debug(f"Error fetching vector store {vector_store_id} from database: {e}") + verbose_logger.debug("Error fetching vector store %s from database: %s", vector_store_id, e) if vector_store is not None: # Create a copy to avoid modifying the registry diff --git a/tests/test_litellm/test_logging.py b/tests/test_litellm/test_logging.py index fbed044445b..beba5794444 100644 --- a/tests/test_litellm/test_logging.py +++ b/tests/test_litellm/test_logging.py @@ -1,7 +1,9 @@ +import ast import asyncio import json import os import sys +from pathlib import Path from typing import List import pytest @@ -328,3 +330,66 @@ async def test_cache_hit_includes_custom_llm_provider(): # Clean up litellm.callbacks = original_callbacks litellm.cache = None + + +LITELLM_LOGGER_NAMES = frozenset( + {"verbose_logger", "verbose_proxy_logger", "verbose_router_logger", "logger", "logging"} +) +LOG_LEVEL_METHODS = frozenset({"debug", "info", "warning", "error", "exception", "critical"}) +LITELLM_PACKAGE_ROOT = Path(__file__).resolve().parents[2] / "litellm" + + +def _receiver_name(node: ast.expr) -> str: + if isinstance(node, ast.Name): + return node.id + if isinstance(node, ast.Attribute): + return node.attr + return "" + + +def _is_logging_call(node: ast.AST) -> bool: + return ( + isinstance(node, ast.Call) + and isinstance(node.func, ast.Attribute) + and node.func.attr in LOG_LEVEL_METHODS + and _receiver_name(node.func.value) in LITELLM_LOGGER_NAMES + ) + + +def _has_format_spec(message: ast.JoinedStr) -> bool: + return any(isinstance(value, ast.FormattedValue) and value.format_spec is not None for value in message.values) + + +def _eager_logging_calls(source: str, path: Path) -> tuple[str, ...]: + return tuple( + f"{path}:{node.lineno}" + for node in ast.walk(ast.parse(source)) + if _is_logging_call(node) + and node.args + and isinstance(node.args[0], ast.JoinedStr) + and not _has_format_spec(node.args[0]) + ) + + +def test_logging_calls_do_not_build_their_message_eagerly(): + """A discarded log record must not have cost anything to build. + + `log.debug(f"payload: {body}")` interpolates before the call runs, so the message is + built and thrown away on every request the level filters out; `log.debug("payload: %s", body)` + defers that to `record.getMessage()`, which only runs once the record passes the level check. + + f-strings carrying a format spec are exempt: `%`-style has no faithful equivalent for + specs like `{ratio:.1%}`, and those sites interpolate scalars rather than payloads. + """ + offenders = tuple( + offender + for path in sorted(LITELLM_PACKAGE_ROOT.rglob("*.py")) + for offender in _eager_logging_calls( + path.read_text(encoding="utf-8"), path.relative_to(LITELLM_PACKAGE_ROOT.parent) + ) + ) + + assert offenders == (), ( + "these logging calls build their message eagerly; pass the values as %-style arguments instead:\n" + + "\n".join(offenders) + )