mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-13 23:11:40 +00:00
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
This commit is contained in:
parent
c6a796a84b
commit
b248f7b39d
410 changed files with 3845 additions and 3119 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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."""
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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}",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
""" """
|
||||
|
|
|
|||
|
|
@ -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 []
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]:
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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]:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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"""
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:<WANDB_API_KEY>
|
||||
auth_header = _get_weave_authorization_header(api_key=api_key)
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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}",
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue