From b248f7b39d2771f1bba0484f69c223e3f9c7dbe1 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Mon, 3 Aug 2026 22:53:00 +0200 Subject: [PATCH] perf: build log messages lazily so filtered-out log records cost nothing litellm's loggers sit at INFO by default; the proxy sets that level explicitly and the SDK inherits root's WARNING, so every debug record is discarded. The message gets built anyway. 2877 logging calls interpolate their payload into an f-string before the call runs, so the work happens on every request and the result is thrown away. The expensive sites stringify a whole message list or kwargs dict, so the cost grows with conversation length Passing the values as %-style arguments hands them to record.getMessage(), which only runs once a record has passed the level check. With the level turned up the emitted lines are byte-identical, including f"{x=}" sites, which map to %r. A 60-message chat completion runs 22% faster through litellm.completion and allocates 163 kB less; a 20-message one runs 11% faster f-strings carrying a format spec are left as they are, since %-style has no faithful equivalent for something like {ratio:.1%}, and those sites interpolate scalars rather than payloads. The added test walks the package and fails on any new eager logging call --- litellm/_redis.py | 8 +- litellm/a2a_protocol/card_resolver.py | 4 +- .../a2a_protocol/exception_mapping_utils.py | 8 +- .../litellm_completion_bridge/handler.py | 14 +- .../transformation.py | 8 +- litellm/a2a_protocol/main.py | 20 +- .../providers/bedrock_agentcore/handler.py | 6 +- .../bedrock_agentcore/transformation.py | 2 +- .../providers/pydantic_ai_agents/handler.py | 4 +- .../pydantic_ai_agents/transformation.py | 10 +- .../providers/watsonx_orchestrate/handler.py | 6 +- .../watsonx_orchestrate/transformation.py | 2 +- litellm/a2a_protocol/streaming_iterator.py | 10 +- litellm/anthropic_beta_headers_manager.py | 8 +- litellm/batches/batch_utils.py | 4 +- litellm/batches/main.py | 4 +- litellm/caching/azure_blob_cache.py | 10 +- litellm/caching/caching.py | 6 +- litellm/caching/caching_handler.py | 2 +- litellm/caching/dual_cache.py | 6 +- litellm/caching/gcs_cache.py | 9 +- litellm/caching/redis_cache.py | 21 +- litellm/caching/redis_cluster_cache.py | 2 +- litellm/caching/redis_semantic_cache.py | 2 +- litellm/caching/s3_cache.py | 17 +- .../transformation.py | 42 +- litellm/cost_calculator.py | 33 +- litellm/experimental_mcp_client/client.py | 105 ++--- .../google_genai/adapters/transformation.py | 9 +- .../SlackAlerting/batching_handler.py | 4 +- .../SlackAlerting/slack_alerting.py | 10 +- .../anthropic_cache_control_hook.py | 10 +- litellm/integrations/argilla.py | 14 +- litellm/integrations/arize/_utils.py | 2 +- litellm/integrations/arize/arize_phoenix.py | 2 +- .../arize/arize_phoenix_prompt_manager.py | 2 +- .../azure_sentinel/azure_sentinel.py | 8 +- .../azure_storage/azure_storage.py | 34 +- .../bitbucket/bitbucket_prompt_manager.py | 2 +- .../integrations/braintrust_mock_client.py | 2 +- litellm/integrations/cloudzero/cloudzero.py | 18 +- litellm/integrations/custom_batch_logger.py | 2 +- litellm/integrations/custom_guardrail.py | 4 +- litellm/integrations/custom_logger.py | 20 +- litellm/integrations/custom_secret_manager.py | 2 +- litellm/integrations/datadog/datadog.py | 24 +- .../datadog/datadog_cost_management.py | 8 +- .../integrations/datadog/datadog_llm_obs.py | 38 +- .../integrations/datadog/datadog_metrics.py | 8 +- litellm/integrations/deepeval/api.py | 4 +- litellm/integrations/gcs_bucket/gcs_bucket.py | 12 +- .../gcs_bucket/gcs_bucket_mock_client.py | 4 +- litellm/integrations/gcs_pubsub/pub_sub.py | 6 +- .../generic_api/generic_api_callback.py | 37 +- .../gitlab/gitlab_prompt_manager.py | 2 +- litellm/integrations/lago.py | 8 +- litellm/integrations/langfuse/langfuse.py | 29 +- .../integrations/langfuse/langfuse_otel.py | 4 +- .../langfuse/langfuse_prompt_management.py | 4 +- litellm/integrations/langsmith.py | 20 +- litellm/integrations/literal_ai.py | 10 +- litellm/integrations/logfire_logger.py | 4 +- litellm/integrations/mlflow.py | 2 +- litellm/integrations/mock_client_factory.py | 18 +- litellm/integrations/newrelic/newrelic.py | 41 +- litellm/integrations/opentelemetry.py | 3 +- litellm/integrations/opik/opik.py | 20 +- .../opik/opik_payload_builder/extractors.py | 6 +- .../opik_payload_builder/payload_builders.py | 2 +- litellm/integrations/posthog.py | 30 +- litellm/integrations/prometheus.py | 69 ++-- litellm/integrations/prometheus_services.py | 2 +- litellm/integrations/rubrik.py | 57 +-- litellm/integrations/s3.py | 14 +- litellm/integrations/s3_v2.py | 59 +-- litellm/integrations/sqs.py | 12 +- litellm/integrations/traceloop.py | 4 +- .../vector_store_pre_call_hook.py | 20 +- litellm/integrations/weave/weave_otel.py | 4 +- .../websearch_interception/handler.py | 131 +++--- .../websearch_interception/transformation.py | 10 +- litellm/integrations/weights_biases.py | 4 +- litellm/interactions/streaming_iterator.py | 2 +- .../exception_mapping_utils.py | 12 +- litellm/litellm_core_utils/fallback_utils.py | 2 +- litellm/litellm_core_utils/litellm_logging.py | 83 ++-- .../litellm_core_utils/llm_cost_calc/utils.py | 12 +- .../llm_response_utils/get_api_base.py | 2 +- .../logging_callback_manager.py | 13 +- litellm/litellm_core_utils/logging_utils.py | 8 +- litellm/litellm_core_utils/logging_worker.py | 6 +- .../prompt_templates/factory.py | 15 +- .../litellm_core_utils/realtime_streaming.py | 12 +- .../litellm_core_utils/streaming_handler.py | 10 +- litellm/litellm_core_utils/token_counter.py | 21 +- litellm/llms/__init__.py | 14 +- .../chat/guardrail_translation/handler.py | 8 +- .../llms/anthropic/count_tokens/handler.py | 16 +- .../anthropic/count_tokens/token_counter.py | 4 +- .../adapters/streaming_iterator.py | 2 +- .../editors/clear_tool_uses.py | 4 +- .../messages/mcp_handler.py | 5 +- .../responses_adapters/streaming_iterator.py | 2 +- litellm/llms/anthropic/files/handler.py | 4 +- .../azure/chat/o_series_transformation.py | 2 +- litellm/llms/azure/common_utils.py | 13 +- litellm/llms/azure/cost_calculation.py | 5 +- .../llms/azure/image_generation/__init__.py | 2 +- .../responses/o_series_transformation.py | 2 +- .../llms/azure/responses/transformation.py | 10 +- litellm/llms/azure_ai/agents/handler.py | 24 +- .../llms/azure_ai/agents/transformation.py | 2 +- .../anthropic/count_tokens/handler.py | 16 +- .../anthropic/count_tokens/token_counter.py | 4 +- litellm/llms/azure_ai/chat/transformation.py | 2 +- litellm/llms/azure_ai/cost_calculator.py | 2 +- .../azure_ai/image_generation/__init__.py | 2 +- litellm/llms/azure_ai/ocr/common_utils.py | 4 +- .../document_intelligence/transformation.py | 12 +- litellm/llms/azure_ai/ocr/transformation.py | 12 +- .../files/azure_blob_storage_backend.py | 10 +- .../base_llm/files/storage_backend_factory.py | 2 +- .../base_managed_resource.py | 6 +- litellm/llms/bedrock/base_aws_llm.py | 32 +- .../bedrock/chat/agentcore/transformation.py | 53 +-- .../bedrock/chat/converse_transformation.py | 8 +- .../chat/invoke_agent/transformation.py | 24 +- litellm/llms/bedrock/chat/invoke_handler.py | 2 +- .../count_tokens/bedrock_token_counter.py | 4 +- litellm/llms/bedrock/count_tokens/handler.py | 20 +- litellm/llms/bedrock/files/transformation.py | 3 +- litellm/llms/bedrock/realtime/handler.py | 16 +- .../llms/bedrock/realtime/transformation.py | 10 +- .../bedrock_mantle/chat/transformation.py | 2 +- .../black_forest_labs/image_edit/handler.py | 8 +- .../image_generation/handler.py | 8 +- .../llms/custom_httpx/aiohttp_transport.py | 10 +- litellm/llms/custom_httpx/http_handler.py | 17 +- litellm/llms/custom_httpx/llm_http_handler.py | 46 ++- litellm/llms/databricks/common_utils.py | 2 +- litellm/llms/databricks/streaming_utils.py | 8 +- litellm/llms/gemini/files/transformation.py | 10 +- .../llms/gemini/realtime/transformation.py | 10 +- litellm/llms/gigachat/authenticator.py | 4 +- litellm/llms/gigachat/chat/transformation.py | 2 +- litellm/llms/gigachat/file_handler.py | 16 +- litellm/llms/github_copilot/authenticator.py | 34 +- .../embedding/transformation.py | 2 +- .../responses/transformation.py | 9 +- litellm/llms/groq/chat/transformation.py | 2 +- .../llms/huggingface/chat/transformation.py | 2 +- litellm/llms/langflow/chat/transformation.py | 6 +- litellm/llms/langgraph/chat/sse_iterator.py | 6 +- litellm/llms/langgraph/chat/transformation.py | 12 +- .../litellm_proxy/skills/code_execution.py | 12 +- litellm/llms/litellm_proxy/skills/handler.py | 10 +- .../litellm_proxy/skills/prompt_injection.py | 8 +- .../litellm_proxy/skills/sandbox_executor.py | 18 +- litellm/llms/manus/files/transformation.py | 6 +- .../llms/manus/responses/transformation.py | 10 +- litellm/llms/mistral/ocr/transformation.py | 6 +- litellm/llms/ollama/common_utils.py | 4 +- .../llms/ollama/completion/transformation.py | 2 +- .../openai/chat/o_series_transformation.py | 2 +- litellm/llms/openai/cost_calculation.py | 20 +- .../image_generation/cost_calculator.py | 2 +- litellm/llms/openai/openai.py | 2 +- .../openai/responses/count_tokens/handler.py | 14 +- .../responses/count_tokens/token_counter.py | 4 +- .../llms/openai/responses/transformation.py | 14 +- litellm/llms/openai_like/dynamic_config.py | 5 +- litellm/llms/openai_like/json_loader.py | 2 +- .../llms/perplexity/chat/transformation.py | 6 +- .../image_generation/transformation.py | 6 +- .../runwayml/text_to_speech/transformation.py | 6 +- litellm/llms/sagemaker/common_utils.py | 10 +- litellm/llms/sap/credentials.py | 8 +- litellm/llms/together_ai/chat.py | 2 +- .../vertex_ai/agent_engine/transformation.py | 14 +- litellm/llms/vertex_ai/common_utils.py | 3 +- litellm/llms/vertex_ai/cost_calculator.py | 6 +- .../vertex_and_google_ai_studio_gemini.py | 35 +- .../vertex_ai/ocr/deepseek_transformation.py | 4 +- litellm/llms/vertex_ai/ocr/transformation.py | 10 +- .../llms/vertex_ai/rag_engine/ingestion.py | 10 +- litellm/llms/vertex_ai/vertex_llm_base.py | 25 +- litellm/llms/watsonx/chat/transformation.py | 2 +- litellm/llms/xai/chat/transformation.py | 6 +- litellm/main.py | 18 +- litellm/ocr/main.py | 16 +- .../mcp_server/auth/user_api_key_auth_mcp.py | 100 ++--- litellm/proxy/_experimental/mcp_server/db.py | 2 +- .../mcp_server/discoverable_endpoints.py | 7 +- .../mcp_server/mcp_server_manager.py | 130 +++--- .../mcp_server/openapi_to_mcp_generator.py | 11 +- .../mcp_server/rest_endpoints.py | 26 +- .../mcp_server/semantic_tool_filter.py | 17 +- .../proxy/_experimental/mcp_server/server.py | 137 ++++--- .../_experimental/mcp_server/sse_transport.py | 22 +- .../_experimental/mcp_server/tool_registry.py | 4 +- .../_experimental/mcp_server/toolset_db.py | 2 +- .../mcp_server/ui_session_utils.py | 2 +- .../proxy/agent_endpoints/a2a_endpoints.py | 14 +- litellm/proxy/agent_endpoints/a2a_routing.py | 6 +- .../auth/agent_permission_handler.py | 14 +- litellm/proxy/agent_endpoints/endpoints.py | 28 +- .../agent_endpoints/model_list_helpers.py | 4 +- .../claude_code_marketplace.py | 26 +- .../proxy/anthropic_endpoints/endpoints.py | 4 +- litellm/proxy/auth/auth_checks.py | 47 ++- litellm/proxy/auth/auth_exception_handler.py | 4 +- litellm/proxy/auth/auth_utils.py | 23 +- litellm/proxy/auth/handle_jwt.py | 36 +- litellm/proxy/auth/litellm_license.py | 23 +- litellm/proxy/auth/model_checks.py | 8 +- litellm/proxy/auth/oauth2_proxy_hook.py | 2 +- litellm/proxy/auth/resolvers/store.py | 4 +- litellm/proxy/auth/route_checks.py | 5 +- litellm/proxy/auth/user_api_key_auth.py | 31 +- litellm/proxy/batches_endpoints/endpoints.py | 29 +- litellm/proxy/caching_routes.py | 4 +- litellm/proxy/client/cli/interface.py | 2 +- litellm/proxy/common_request_processing.py | 20 +- litellm/proxy/common_utils/callback_utils.py | 6 +- .../proxy/common_utils/custom_openapi_spec.py | 14 +- litellm/proxy/common_utils/debug_utils.py | 25 +- .../common_utils/encrypt_decrypt_utils.py | 4 +- .../expired_ui_session_key_cleanup_manager.py | 2 +- litellm/proxy/common_utils/get_routes.py | 2 +- .../proxy/common_utils/http_parsing_utils.py | 38 +- .../common_utils/key_rotation_manager.py | 8 +- .../proxy/common_utils/load_config_utils.py | 24 +- .../common_utils/openapi_schema_compat.py | 4 +- .../proxy/common_utils/performance_utils.py | 20 +- litellm/proxy/custom_prompt_management.py | 5 +- litellm/proxy/db/check_migration.py | 3 +- litellm/proxy/db/create_views.py | 2 +- litellm/proxy/db/db_spend_update_writer.py | 47 ++- .../db_transaction_queue/pod_lock_manager.py | 4 +- .../db_transaction_queue/spend_log_cleanup.py | 33 +- litellm/proxy/db/dynamo_db.py | 4 +- litellm/proxy/db/prisma_client.py | 23 +- .../example_config_yaml/custom_guardrail.py | 4 +- .../proxy/fine_tuning_endpoints/endpoints.py | 15 +- .../proxy/guardrails/guardrail_endpoints.py | 38 +- .../guardrails/guardrail_hooks/aim/aim.py | 4 +- .../guardrail_hooks/azure/prompt_shield.py | 4 +- .../guardrail_hooks/azure/text_moderation.py | 4 +- .../guardrail_hooks/bedrock_guardrails.py | 2 +- .../cato_networks/cato_networks.py | 4 +- .../crowdstrike_aidr/crowdstrike_aidr.py | 10 +- .../custom_code/custom_code_guardrail.py | 19 +- .../guardrail_hooks/custom_code/primitives.py | 20 +- .../hiddenlayer/hiddenlayer.py | 8 +- .../guardrails/guardrail_hooks/lasso/lasso.py | 27 +- .../litellm_content_filter/content_filter.py | 93 +++-- .../litellm_content_filter/patterns.py | 2 +- .../llm_as_a_judge/__init__.py | 6 +- .../mcp_end_user_permission.py | 11 +- .../guardrails/guardrail_hooks/noma/noma.py | 28 +- .../guardrails/guardrail_hooks/onyx/onyx.py | 10 +- .../guardrail_hooks/openai/moderations.py | 2 +- .../guardrail_hooks/pangea/pangea.py | 15 +- .../panw_prisma_airs/panw_prisma_airs.py | 82 ++-- .../guardrail_hooks/pillar/pillar.py | 34 +- .../guardrails/guardrail_hooks/presidio.py | 10 +- .../prompt_security/prompt_security.py | 8 +- .../guardrail_hooks/qualifire/qualifire.py | 8 +- .../semantic_guard/route_loader.py | 2 +- .../semantic_guard/semantic_guard.py | 9 +- .../guardrail_hooks/tool_permission.py | 16 +- .../zscaler_ai_guard/zscaler_ai_guard.py | 39 +- .../proxy/guardrails/guardrail_registry.py | 32 +- litellm/proxy/guardrails/init_guardrails.py | 6 +- .../health_endpoints/_health_endpoints.py | 20 +- litellm/proxy/hooks/azure_content_safety.py | 2 +- litellm/proxy/hooks/batch_rate_limiter.py | 16 +- litellm/proxy/hooks/batch_redis_get.py | 2 +- litellm/proxy/hooks/cache_control_check.py | 2 +- litellm/proxy/hooks/dynamic_rate_limiter.py | 10 +- .../proxy/hooks/dynamic_rate_limiter_v3.py | 24 +- .../proxy/hooks/key_management_event_hooks.py | 15 +- litellm/proxy/hooks/litellm_skills/main.py | 52 +-- litellm/proxy/hooks/max_budget_limiter.py | 2 +- .../proxy/hooks/mcp_semantic_filter/hook.py | 60 +-- .../proxy/hooks/model_max_budget_limiter.py | 4 +- .../proxy/hooks/parallel_request_limiter.py | 4 +- .../hooks/parallel_request_limiter_v3.py | 76 ++-- .../proxy/hooks/prompt_injection_detection.py | 2 +- .../proxy/hooks/proxy_track_cost_callback.py | 12 +- litellm/proxy/hooks/responses_id_security.py | 9 +- .../hooks/user_management_event_hooks.py | 2 +- litellm/proxy/image_endpoints/endpoints.py | 2 +- litellm/proxy/litellm_pre_call_utils.py | 54 +-- .../cache_settings_endpoints.py | 9 +- .../common_daily_activity.py | 4 +- .../management_endpoints/common_utils.py | 4 +- .../cost_tracking_settings.py | 20 +- .../customer_endpoints.py | 22 +- .../fallback_management_endpoints.py | 10 +- .../internal_user_endpoints.py | 36 +- .../key_management_endpoints.py | 56 +-- .../management_v1/budgets.py | 2 +- .../management_v1/spend_logs.py | 4 +- .../mcp_management_endpoints.py | 34 +- ...model_access_group_management_endpoints.py | 28 +- .../model_management_endpoints.py | 24 +- .../organization_endpoints.py | 8 +- .../policy_endpoints/endpoints.py | 2 +- .../router_settings_endpoints.py | 4 +- .../management_endpoints/scim/scim_v2.py | 38 +- .../sso/custom_microsoft_sso.py | 8 +- .../management_endpoints/sso/saml_sso.py | 4 +- .../tag_management_endpoints.py | 8 +- .../team_callback_endpoints.py | 6 +- .../management_endpoints/team_endpoints.py | 20 +- litellm/proxy/management_endpoints/ui_sso.py | 171 ++++---- .../proxy/management_helpers/audit_logs.py | 2 +- .../object_permission_utils.py | 6 +- litellm/proxy/ocr_endpoints/endpoints.py | 7 +- .../openai_files_endpoints/common_utils.py | 22 +- .../openai_files_endpoints/files_endpoints.py | 14 +- .../storage_backend_service.py | 8 +- .../llm_passthrough_endpoints.py | 16 +- .../anthropic_passthrough_logging_handler.py | 14 +- .../assembly_passthrough_logging_handler.py | 4 +- .../openai_passthrough_logging_handler.py | 12 +- ...tex_ai_live_passthrough_logging_handler.py | 12 +- .../vertex_passthrough_logging_handler.py | 14 +- .../pass_through_endpoints.py | 79 ++-- .../passthrough_endpoint_router.py | 8 +- .../streaming_handler.py | 6 +- .../policy_engine/attachment_registry.py | 34 +- .../policy_engine/condition_evaluator.py | 4 +- litellm/proxy/policy_engine/init_policies.py | 14 +- .../proxy/policy_engine/pipeline_executor.py | 11 +- .../proxy/policy_engine/policy_endpoints.py | 32 +- .../proxy/policy_engine/policy_registry.py | 46 ++- .../policy_engine/policy_resolve_endpoints.py | 4 +- .../proxy/policy_engine/policy_resolver.py | 16 +- .../proxy/policy_engine/policy_validator.py | 8 +- litellm/proxy/prisma_migration.py | 6 +- litellm/proxy/prometheus_cleanup.py | 8 +- litellm/proxy/prompts/init_prompts.py | 2 +- litellm/proxy/prompts/prompt_endpoints.py | 10 +- litellm/proxy/prompts/prompt_registry.py | 12 +- litellm/proxy/proxy_cli.py | 4 +- litellm/proxy/proxy_server.py | 386 ++++++++++-------- litellm/proxy/rag_endpoints/endpoints.py | 29 +- litellm/proxy/rerank_endpoints/endpoints.py | 2 +- .../proxy/response_api_endpoints/endpoints.py | 13 +- .../response_polling/background_streaming.py | 17 +- .../proxy/response_polling/polling_handler.py | 12 +- litellm/proxy/route_llm_request.py | 4 +- litellm/proxy/search_endpoints/endpoints.py | 11 +- .../search_tool_management.py | 30 +- .../search_endpoints/search_tool_registry.py | 12 +- .../spend_tracking/cloudzero_endpoints.py | 16 +- .../spend_management_endpoints.py | 12 +- .../proxy/spend_tracking/vantage_endpoints.py | 16 +- litellm/proxy/types_utils/utils.py | 13 +- .../proxy_setting_endpoints.py | 7 +- litellm/proxy/utils.py | 69 ++-- .../management_endpoints.py | 35 +- .../vector_store_files_endpoints/endpoints.py | 24 +- litellm/rag/ingestion/base_ingestion.py | 2 +- litellm/rag/ingestion/bedrock_ingestion.py | 58 +-- .../rag/ingestion/file_parsers/pdf_parser.py | 6 +- litellm/rag/ingestion/gemini_ingestion.py | 14 +- litellm/rag/ingestion/s3_vectors_ingestion.py | 62 +-- litellm/rag/ingestion/vertex_ai_ingestion.py | 26 +- litellm/repositories/config_repository.py | 2 +- litellm/rerank_api/main.py | 4 +- .../responses/mcp/chat_completions_handler.py | 4 +- .../mcp/litellm_proxy_mcp_handler.py | 18 +- .../responses/mcp/mcp_streaming_iterator.py | 22 +- litellm/responses/utils.py | 4 +- litellm/router.py | 236 ++++++----- .../auto_router/auto_router.py | 2 +- .../router_strategy/base_routing_strategy.py | 6 +- litellm/router_strategy/budget_limiter.py | 23 +- .../complexity_router/complexity_router.py | 32 +- litellm/router_strategy/lar1_routing.py | 8 +- litellm/router_strategy/lowest_cost.py | 10 +- litellm/router_strategy/lowest_latency.py | 6 +- litellm/router_strategy/lowest_tpm_rpm.py | 12 +- litellm/router_strategy/lowest_tpm_rpm_v2.py | 14 +- .../quality_router/quality_router.py | 16 +- litellm/router_strategy/simple_shuffle.py | 11 +- litellm/router_utils/batch_utils.py | 4 +- litellm/router_utils/cooldown_cache.py | 4 +- litellm/router_utils/cooldown_callbacks.py | 3 +- litellm/router_utils/cooldown_handlers.py | 8 +- .../router_utils/fallback_event_handlers.py | 6 +- litellm/router_utils/handle_error.py | 4 +- .../router_utils/pattern_match_deployments.py | 2 +- .../io_token_rate_limit_check.py | 32 +- .../pre_call_checks/model_rate_limit_check.py | 16 +- litellm/router_utils/search_api_router.py | 15 +- litellm/sandbox/main.py | 2 +- litellm/search/main.py | 4 +- .../cyberark_secret_manager.py | 22 +- .../get_azure_ad_token_provider.py | 2 +- .../hashicorp_secret_manager.py | 32 +- litellm/secret_managers/main.py | 5 +- .../guardrail_hooks/zscaler_ai_guard.py | 2 +- litellm/types/videos/utils.py | 4 +- litellm/utils.py | 103 +++-- .../vector_stores/vector_store_registry.py | 9 +- tests/test_litellm/test_logging.py | 65 +++ 410 files changed, 3845 insertions(+), 3119 deletions(-) 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) + )