style: format spend tracking utility with repository Ruff config

This commit is contained in:
Maximilian Rink 2026-10-16 12:16:28 +02:00
parent fb17450a3e
commit a48ea6d994

View file

@ -167,10 +167,7 @@ def _get_router_metadata_for_spend_log(
router_correlation_id: str | None,
) -> SpendLogsRouterMetadata | None:
model_info: Final = metadata.get("model_info") if metadata is not None else None
if (
not isinstance(model_info, Mapping)
or model_info.get("internal_router_model") is not True
):
if not isinstance(model_info, Mapping) or model_info.get("internal_router_model") is not True:
return None
return SpendLogsRouterMetadata(
requested_model=requested_model or None,
@ -207,8 +204,7 @@ def _get_spend_logs_metadata(
batch_successful_requests: int | None = None,
batch_failed_requests: int | None = None,
mcp_tool_call_metadata: StandardLoggingMCPToolCall | None = None,
vector_store_request_metadata: list[StandardLoggingVectorStoreRequest]
| None = None,
vector_store_request_metadata: list[StandardLoggingVectorStoreRequest] | None = None,
guardrail_information: list[StandardLoggingGuardrailInformation] | None = None,
usage_object: dict | None = None,
model_map_information: StandardLoggingModelInformation | None = None,
@ -277,11 +273,7 @@ def _get_spend_logs_metadata(
# Filter the metadata dictionary to include only the specified keys
clean_metadata: Final = SpendLogsMetadata(
**MappingProxyType(
{
key: metadata.get(key)
for key in SpendLogsMetadata.__annotations__
if key not in _STAMPED_METADATA_KEYS
}
{key: metadata.get(key) for key in SpendLogsMetadata.__annotations__ if key not in _STAMPED_METADATA_KEYS}
),
autorouter_savings=autorouter_savings,
autorouter_savings_estimate=autorouter_savings_estimate,
@ -309,12 +301,10 @@ def _get_spend_logs_metadata(
clean_metadata["batch_successful_requests"] = batch_successful_requests
clean_metadata["batch_failed_requests"] = batch_failed_requests
clean_metadata["mcp_tool_call_metadata"] = mcp_tool_call_metadata
clean_metadata["vector_store_request_metadata"] = (
_get_vector_store_request_for_spend_logs_payload(vector_store_request_metadata)
)
clean_metadata["guardrail_information"] = (
_sanitize_guardrail_information_for_spend_logs(guardrail_information)
clean_metadata["vector_store_request_metadata"] = _get_vector_store_request_for_spend_logs_payload(
vector_store_request_metadata
)
clean_metadata["guardrail_information"] = _sanitize_guardrail_information_for_spend_logs(guardrail_information)
clean_metadata["usage_object"] = usage_object
clean_metadata["model_map_information"] = model_map_information
clean_metadata["cold_storage_object_key"] = cold_storage_object_key
@ -336,8 +326,7 @@ def _cost_row_request_id_suffix(
return BATCH_COST_REQUEST_ID_SUFFIX
if settles_background_response or (
call_type in NON_INFERENCE_CALL_TYPES
and metadata.get(INTERNAL_CALL_ORIGIN_METADATA_KEY)
== BACKGROUND_RESPONSE_COST_POLL_CALL_ORIGIN
and metadata.get(INTERNAL_CALL_ORIGIN_METADATA_KEY) == BACKGROUND_RESPONSE_COST_POLL_CALL_ORIGIN
):
return BACKGROUND_RESPONSE_COST_REQUEST_ID_SUFFIX
return ""
@ -349,17 +338,11 @@ def get_spend_logs_id(
standard_logging_payload = kwargs.get("standard_logging_object")
candidate_ids: Final = (
response_obj.get("id"),
standard_logging_payload.get("id")
if isinstance(standard_logging_payload, dict)
else None,
standard_logging_payload.get("id") if isinstance(standard_logging_payload, dict) else None,
kwargs.get("litellm_call_id"),
)
resolved_id: Final = next(
(
candidate
for candidate in candidate_ids
if isinstance(candidate, str) and candidate
),
(candidate for candidate in candidate_ids if isinstance(candidate, str) and candidate),
None,
)
if resolved_id is None:
@ -453,9 +436,7 @@ def get_request_model_access_groups(
standard_logging_payload: Final = kwargs.get("standard_logging_object")
if isinstance(standard_logging_payload, Mapping):
from_payload: Final = coerce_model_access_groups(
standard_logging_payload.get("request_model_access_groups")
)
from_payload: Final = coerce_model_access_groups(standard_logging_payload.get("request_model_access_groups"))
if from_payload:
return from_payload
@ -476,13 +457,9 @@ def _sl_attribution_fallback(
def _deployment_provider(deployment: DeploymentTypedDict) -> str | None:
litellm_params: Final = LiteLLM_Params.model_validate(deployment["litellm_params"])
if litellm.LiteLLMProxyChatConfig.should_use_litellm_proxy_by_default(
litellm_params=litellm_params
):
if litellm.LiteLLMProxyChatConfig.should_use_litellm_proxy_by_default(litellm_params=litellm_params):
return LlmProviders.LITELLM_PROXY.value
declared: Final = declared_authenticating_provider(
litellm_params.model, litellm_params.custom_llm_provider
)
declared: Final = declared_authenticating_provider(litellm_params.model, litellm_params.custom_llm_provider)
if declared is not None:
return declared
try:
@ -509,17 +486,12 @@ def _model_group_provider(model_group: str, llm_router: "Router | None") -> str
def _is_configured_model_group(model_group: str, llm_router: "Router | None") -> bool:
if llm_router is None or not model_group:
return False
return (
llm_router.is_recognized_model(model_group)
or model_group in llm_router.team_public_model_names
)
return llm_router.is_recognized_model(model_group) or model_group in llm_router.team_public_model_names
def _looks_like_model_name(model: str) -> bool:
candidate: Final = model.removeprefix(MCP_SPEND_LOG_MODEL_PREFIX)
return len(candidate) <= MAX_SPEND_LOG_MODEL_NAME_LENGTH and not any(
char.isspace() for char in candidate
)
return len(candidate) <= MAX_SPEND_LOG_MODEL_NAME_LENGTH and not any(char.isspace() for char in candidate)
_TRUNCATION_MARKER: Final = re.compile(
@ -530,9 +502,7 @@ _SCRUBBED_ERROR_TEXT_FIELDS: Final = frozenset(("error_message", "traceback"))
def _raw_model_spellings(raw_model: str) -> tuple[str, ...]:
return tuple(
dict.fromkeys((raw_model, repr(raw_model)[1:-1], json.dumps(raw_model)[1:-1]))
)
return tuple(dict.fromkeys((raw_model, repr(raw_model)[1:-1], json.dumps(raw_model)[1:-1])))
def _overlap_at_end(text: str, spelling: str) -> int:
@ -542,9 +512,7 @@ def _overlap_at_end(text: str, spelling: str) -> int:
def _overlap_at_start(text: str, spelling: str) -> int:
lengths: Final = range(min(len(text), len(spelling) - 1), 0, -1)
return next(
(length for length in lengths if text.startswith(spelling[-length:])), 0
)
return next((length for length in lengths if text.startswith(spelling[-length:])), 0)
def _scrub_raw_model_split_by_truncation(text: str, spellings: tuple[str, ...]) -> str:
@ -568,9 +536,7 @@ def _scrub_raw_model_split_by_truncation(text: str, spellings: tuple[str, ...])
def _scrub_raw_model_from_error_text(text: str, spellings: tuple[str, ...]) -> str:
whole_occurrences_scrubbed: Final = reduce(
lambda scrubbed, spelling: scrubbed.replace(
spelling, UNKNOWN_MODEL_SPEND_LOG_MODEL
),
lambda scrubbed, spelling: scrubbed.replace(spelling, UNKNOWN_MODEL_SPEND_LOG_MODEL),
spellings,
text,
)
@ -613,9 +579,7 @@ def get_logging_payload(
# standardize this function to be used across, s3, dynamoDB, langfuse logging
litellm_params_value: Final[object] = kwargs.get("litellm_params", {})
litellm_params: Final[dict[str, object]] = (
cast(dict[str, object], litellm_params_value)
if isinstance(litellm_params_value, Mapping)
else {}
cast(dict[str, object], litellm_params_value) if isinstance(litellm_params_value, Mapping) else {}
)
metadata: Final = get_litellm_metadata_from_kwargs(kwargs)
routing_litellm_params: Final[Mapping[str, object] | None] = (
@ -659,12 +623,8 @@ def get_logging_payload(
if (not usage or "continued_partial_usage" in kwargs) and isinstance(_combined_usage, litellm.Usage):
usage = _combined_usage.model_dump()
id = get_spend_logs_id(
call_type or "acompletion", response_obj_dict, kwargs, metadata
)
standard_logging_payload: Final = cast(
StandardLoggingPayload | None, kwargs.get("standard_logging_object", None)
)
id = get_spend_logs_id(call_type or "acompletion", response_obj_dict, kwargs, metadata)
standard_logging_payload: Final = cast(StandardLoggingPayload | None, kwargs.get("standard_logging_object", None))
end_user_id = get_end_user_id_for_cost_tracking(
dict(litellm_params) if isinstance(litellm_params, Mapping) else litellm_params
@ -676,12 +636,8 @@ def get_logging_payload(
standard_logging_completion_tokens: int = 0
standard_logging_total_tokens: int = 0
if standard_logging_payload is not None:
standard_logging_prompt_tokens = standard_logging_payload.get(
"prompt_tokens", 0
)
standard_logging_completion_tokens = standard_logging_payload.get(
"completion_tokens", 0
)
standard_logging_prompt_tokens = standard_logging_payload.get("prompt_tokens", 0)
standard_logging_completion_tokens = standard_logging_payload.get("completion_tokens", 0)
standard_logging_total_tokens = standard_logging_payload.get("total_tokens", 0)
_trusted_hash = metadata.get("user_api_key_hash")
_key_alias = metadata.get("user_api_key_alias")
@ -690,12 +646,7 @@ def get_logging_payload(
and _is_non_secret_key_value(_trusted_hash, key_alias=_key_alias)
and _trusted_hash == api_key
)
api_key = (
_redact_logged_api_key(
api_key, already_redacted=_key_already_redacted, key_alias=_key_alias
)
or ""
)
api_key = _redact_logged_api_key(api_key, already_redacted=_key_already_redacted, key_alias=_key_alias) or ""
if (
standard_logging_payload is not None
@ -705,30 +656,21 @@ def get_logging_payload(
or _redact_logged_api_key(
standard_logging_payload["metadata"].get("user_api_key_hash"),
already_redacted=True,
key_alias=standard_logging_payload["metadata"].get(
"user_api_key_alias"
),
key_alias=standard_logging_payload["metadata"].get("user_api_key_alias"),
)
or ""
)
if not litellm.disable_end_user_cost_tracking:
end_user_id = end_user_id or standard_logging_payload["metadata"].get(
"user_api_key_end_user_id"
)
request_tags = (
safe_dumps(metadata.get("tags", []))
if isinstance(metadata.get("tags", []), list)
else "[]"
)
end_user_id = end_user_id or standard_logging_payload["metadata"].get("user_api_key_end_user_id")
request_tags = safe_dumps(metadata.get("tags", [])) if isinstance(metadata.get("tags", []), list) else "[]"
if (
standard_logging_payload is not None
and standard_logging_payload.get("request_tags") is not None
standard_logging_payload is not None and standard_logging_payload.get("request_tags") is not None
): # use 'tags' from standard logging payload instead
request_tags = safe_dumps(standard_logging_payload["request_tags"])
_model_id: Final = metadata.get("model_info", {}).get(
"id", ""
) or _sl_attribution_fallback(standard_logging_payload, "model_id")
_model_id: Final = metadata.get("model_info", {}).get("id", "") or _sl_attribution_fallback(
standard_logging_payload, "model_id"
)
_model_group: Final = metadata.get("model_group", "") or _sl_attribution_fallback(
standard_logging_payload, "model_group"
)
@ -747,22 +689,14 @@ def get_logging_payload(
or _sl_attribution_fallback(standard_logging_payload, "custom_llm_provider")
or None
)
custom_llm_provider: Final = logged_provider or _model_group_provider(
_model_group, llm_router
)
custom_llm_provider: Final = logged_provider or _model_group_provider(_model_group, llm_router)
requested_model: Final = cast(object, kwargs.get("model"))
raw_model: Final = requested_model if isinstance(requested_model, str) else ""
model_is_malformed: Final = requested_model is not None and not isinstance(
requested_model, str
model_is_malformed: Final = requested_model is not None and not isinstance(requested_model, str)
logged_model: Final = standard_logging_payload.get("model") if standard_logging_payload is not None else None
resolved_model: Final = (logged_model if isinstance(logged_model, str) else None) or reconstruct_model_name(
raw_model, logged_provider, metadata or {}
)
logged_model: Final = (
standard_logging_payload.get("model")
if standard_logging_payload is not None
else None
)
resolved_model: Final = (
logged_model if isinstance(logged_model, str) else None
) or reconstruct_model_name(raw_model, logged_provider, metadata or {})
failed_with_prompt_shaped_model: Final = (
_get_status_for_spend_log(metadata=metadata) == "failure"
and not _model_id
@ -771,25 +705,19 @@ def get_logging_payload(
)
model_name: Final = (
UNKNOWN_MODEL_SPEND_LOG_MODEL
if rejected_as_unknown_model
or failed_with_prompt_shaped_model
or model_is_malformed
if rejected_as_unknown_model or failed_with_prompt_shaped_model or model_is_malformed
else resolved_model
)
model_is_placeholdered: Final = model_name == UNKNOWN_MODEL_SPEND_LOG_MODEL
persisted_model_group: Final = (
""
if model_is_placeholdered
and _model_group == raw_model
and not _looks_like_model_name(raw_model)
if model_is_placeholdered and _model_group == raw_model and not _looks_like_model_name(raw_model)
else _model_group
)
persisted_metadata: Final = (
{
**metadata,
"error_information": _scrub_raw_model_from_error_information(
metadata.get("error_information"), raw_model
),
"error_information": _scrub_raw_model_from_error_information(metadata.get("error_information"), raw_model),
}
if model_is_placeholdered
else metadata
@ -813,16 +741,12 @@ def get_logging_payload(
else None
),
batch_successful_requests=(
standard_logging_payload.get("hidden_params", {}).get(
"batch_successful_requests", None
)
standard_logging_payload.get("hidden_params", {}).get("batch_successful_requests", None)
if standard_logging_payload is not None
else None
),
batch_failed_requests=(
standard_logging_payload.get("hidden_params", {}).get(
"batch_failed_requests", None
)
standard_logging_payload.get("hidden_params", {}).get("batch_failed_requests", None)
if standard_logging_payload is not None
else None
),
@ -832,9 +756,7 @@ def get_logging_payload(
else None
),
vector_store_request_metadata=(
standard_logging_payload["metadata"].get(
"vector_store_request_metadata", None
)
standard_logging_payload["metadata"].get("vector_store_request_metadata", None)
if standard_logging_payload is not None
else None
),
@ -844,18 +766,12 @@ def get_logging_payload(
else None
),
model_map_information=(
standard_logging_payload["model_map_information"]
if standard_logging_payload is not None
else None
standard_logging_payload["model_map_information"] if standard_logging_payload is not None else None
),
guardrail_information=(
standard_logging_payload.get("guardrail_information", None)
if standard_logging_payload is not None
else (
metadata.get("standard_logging_guardrail_information", None)
if metadata is not None
else None
)
else (metadata.get("standard_logging_guardrail_information", None) if metadata is not None else None)
),
cold_storage_object_key=(
standard_logging_payload["metadata"].get("cold_storage_object_key", None)
@ -864,14 +780,10 @@ def get_logging_payload(
),
litellm_overhead_time_ms=litellm_overhead_time_ms,
cost_breakdown=(
standard_logging_payload.get("cost_breakdown", None)
if standard_logging_payload is not None
else None
standard_logging_payload.get("cost_breakdown", None) if standard_logging_payload is not None else None
),
autorouter_savings=(
standard_logging_payload.get("autorouter_savings", None)
if standard_logging_payload is not None
else None
standard_logging_payload.get("autorouter_savings", None) if standard_logging_payload is not None else None
),
autorouter_savings_estimate=(
standard_logging_payload.get("autorouter_savings_estimate")
@ -888,15 +800,11 @@ def get_logging_payload(
metadata=metadata,
requested_model=persisted_model_group,
selected_model=model_name,
selected_provider=(
custom_llm_provider if isinstance(custom_llm_provider, str) else None
),
selected_provider=(custom_llm_provider if isinstance(custom_llm_provider, str) else None),
router_correlation_id=litellm_call_id,
),
used_client_oauth_token=resolve_used_client_oauth_token(
proxy_stamped_used_client_oauth_token(
litellm_params.get("metadata"), litellm_params
),
proxy_stamped_used_client_oauth_token(litellm_params.get("metadata"), litellm_params),
custom_llm_provider,
),
kubernetes_pod_routing=kubernetes_pod_routing,
@ -904,9 +812,7 @@ def get_logging_payload(
response_headers=kwargs.get("response_headers")
if isinstance(kwargs.get("response_headers"), Mapping)
else None,
additional_headers=standard_logging_payload["hidden_params"].get(
"additional_headers"
)
additional_headers=standard_logging_payload["hidden_params"].get("additional_headers")
if standard_logging_payload is not None
and isinstance(standard_logging_payload.get("hidden_params"), Mapping)
else None,
@ -931,26 +837,20 @@ def get_logging_payload(
if isinstance(cached_tokens, int) and cached_tokens > 0:
additional_usage_values["cache_read_input_tokens"] = cached_tokens
if "cache_creation_input_tokens" not in additional_usage_values:
cache_write_tokens: Final = prompt_tokens_details.get(
"cache_write_tokens"
) or prompt_tokens_details.get("cache_creation_tokens")
cache_write_tokens: Final = prompt_tokens_details.get("cache_write_tokens") or prompt_tokens_details.get(
"cache_creation_tokens"
)
if isinstance(cache_write_tokens, int) and cache_write_tokens > 0:
additional_usage_values["cache_creation_input_tokens"] = (
cache_write_tokens
)
additional_usage_values["cache_creation_input_tokens"] = cache_write_tokens
clean_metadata["additional_usage_values"] = additional_usage_values
drop_requester_ip_address: Final = requester_ip_address_logging_disabled()
error_information: Final = clean_metadata["error_information"]
if drop_requester_ip_address:
clean_metadata["requester_ip_address"] = None
if drop_requester_ip_address and isinstance(error_information, Mapping):
clean_metadata["error_information"] = (
cast( # cast-ok: same keys, only the str values are masked
StandardLoggingPayloadErrorInformation,
_error_information_without_ip_addresses(
_OBJECT_MAPPING.validate_python(error_information)
),
)
clean_metadata["error_information"] = cast( # cast-ok: same keys, only the str values are masked
StandardLoggingPayloadErrorInformation,
_error_information_without_ip_addresses(_OBJECT_MAPPING.validate_python(error_information)),
)
if litellm.cache is None:
@ -970,13 +870,9 @@ def get_logging_payload(
id = f"{id}_cache_hit{time.time()}" # SpendLogs does not allow duplicate request_id
mcp_namespaced_tool_name = None
mcp_tool_call_metadata: Final[StandardLoggingMCPToolCall | None] = (
clean_metadata.get("mcp_tool_call_metadata")
)
mcp_tool_call_metadata: Final[StandardLoggingMCPToolCall | None] = clean_metadata.get("mcp_tool_call_metadata")
if mcp_tool_call_metadata is not None:
mcp_namespaced_tool_name = mcp_tool_call_metadata.get(
"namespaced_tool_name", None
)
mcp_namespaced_tool_name = mcp_tool_call_metadata.get("namespaced_tool_name", None)
# Extract agent_id for A2A requests (set directly on model_call_details)
agent_id: Final[str | None] = kwargs.get("agent_id") or metadata.get("agent_id")
@ -999,9 +895,7 @@ def get_logging_payload(
spend=kwargs.get("response_cost", 0),
total_tokens=usage.get("total_tokens", standard_logging_total_tokens),
prompt_tokens=usage.get("prompt_tokens", standard_logging_prompt_tokens),
completion_tokens=usage.get(
"completion_tokens", standard_logging_completion_tokens
),
completion_tokens=usage.get("completion_tokens", standard_logging_completion_tokens),
request_tags=request_tags,
end_user=end_user_id or "",
api_base=_api_base,
@ -1015,15 +909,11 @@ def get_logging_payload(
messages=_get_messages_for_spend_logs_payload(
standard_logging_payload=standard_logging_payload, metadata=metadata
),
response=_get_response_for_spend_logs_payload(
payload=standard_logging_payload, kwargs=kwargs
),
response=_get_response_for_spend_logs_payload(payload=standard_logging_payload, kwargs=kwargs),
proxy_server_request=_get_proxy_server_request_for_spend_logs_payload(
metadata=metadata,
litellm_params=(
_placeholder_stored_request_body(
litellm_params, persisted_model_group, raw_model
)
_placeholder_stored_request_body(litellm_params, persisted_model_group, raw_model)
if model_is_placeholdered
else litellm_params
),
@ -1035,9 +925,7 @@ def get_logging_payload(
metadata=metadata,
standard_logging_payload=standard_logging_payload,
omit_when_missing=_omits_session_id_when_missing(metadata),
batch_trace_session_id=_get_batch_trace_session_id(
call_type=call_type, request_id=id
),
batch_trace_session_id=_get_batch_trace_session_id(call_type=call_type, request_id=id),
),
request_duration_ms=_get_request_duration_ms(start_time, end_time),
status=_get_status_for_spend_log(
@ -1087,9 +975,7 @@ _BATCH_TRACE_CALL_TYPES: Final = frozenset(
)
def _get_batch_trace_session_id(
call_type: str | None, request_id: str | None
) -> str | None:
def _get_batch_trace_session_id(call_type: str | None, request_id: str | None) -> str | None:
"""A batch's create row and its poller-written cost row both derive their request id
from the same batch id (the cost row appends BATCH_COST_REQUEST_ID_SUFFIX), so using
that id as the session groups the batch lifecycle into one trace on the logs UI. The
@ -1223,9 +1109,7 @@ async def get_spend_by_team(
group_by_day;
"""
db_response: Final = await _query_raw_rows(
prisma_client, sql_query, start_date, end_date, team_id
)
db_response: Final = await _query_raw_rows(prisma_client, sql_query, start_date, end_date, team_id)
if db_response is None:
return []
@ -1300,9 +1184,7 @@ async def get_spend_by_team_and_customer(
group_by_day;
"""
db_response: Final = await _query_raw_rows(
prisma_client, sql_query, start_date, end_date, team_id, customer_id
)
db_response: Final = await _query_raw_rows(prisma_client, sql_query, start_date, end_date, team_id, customer_id)
if db_response is None:
return []
@ -1327,21 +1209,13 @@ def _get_messages_for_spend_logs_payload(
_SENSITIVE_REQUEST_BODY_KEYS: Final = frozenset({"secret_fields"})
_REQUEST_BODY_CREDENTIAL_MASKER: Final = SensitiveDataMasker(
extra_sensitive_patterns=frozenset({"apikey"})
)
_TOOL_INPUT_BLOCK_TYPES: Final = frozenset(
{"tool_use", "server_tool_use", "mcp_tool_use"}
)
_TOOL_OUTPUT_BLOCK_TYPES: Final = frozenset(
{"tool_result", "mcp_tool_result", "function_call_output"}
)
_REQUEST_BODY_CREDENTIAL_MASKER: Final = SensitiveDataMasker(extra_sensitive_patterns=frozenset({"apikey"}))
_TOOL_INPUT_BLOCK_TYPES: Final = frozenset({"tool_use", "server_tool_use", "mcp_tool_use"})
_TOOL_OUTPUT_BLOCK_TYPES: Final = frozenset({"tool_result", "mcp_tool_result", "function_call_output"})
def _is_request_body_credential(key: str, value: object) -> bool:
return isinstance(value, str) and _REQUEST_BODY_CREDENTIAL_MASKER.is_sensitive_key(
key
)
return isinstance(value, str) and _REQUEST_BODY_CREDENTIAL_MASKER.is_sensitive_key(key)
def _is_spend_log_content(parent: Mapping[str, object], key: str) -> bool:
@ -1352,10 +1226,7 @@ def _is_spend_log_content(parent: Mapping[str, object], key: str) -> bool:
or (key == "input" and block_type_name in _TOOL_INPUT_BLOCK_TYPES)
or (
key in ("content", "output")
and (
block_type_name in _TOOL_OUTPUT_BLOCK_TYPES
or parent.get("role") == "tool"
)
and (block_type_name in _TOOL_OUTPUT_BLOCK_TYPES or parent.get("role") == "tool")
)
)
@ -1435,9 +1306,7 @@ def _sanitize_request_body_for_spend_logs_payload(
return {
k: REDACTED_BY_LITELM_STRING
if mask_credentials and _is_request_body_credential(k, v)
else _sanitize_value(
v, mask_credentials and not _is_spend_log_content(request_body, k)
)
else _sanitize_value(v, mask_credentials and not _is_spend_log_content(request_body, k))
for k, v in request_body.items()
if k not in _SENSITIVE_REQUEST_BODY_KEYS
}
@ -1607,21 +1476,10 @@ def _sanitize_guardrail_information_for_spend_logs(
here to match OTEL's defensive read pattern; otherwise iteration would
yield the dict's keys and crash the whole spend-log write.
"""
if (
guardrail_information is None
or should_store_prompts_and_responses_in_spend_logs()
):
if guardrail_information is None or should_store_prompts_and_responses_in_spend_logs():
return guardrail_information
entries: Final = (
[guardrail_information]
if isinstance(guardrail_information, dict)
else guardrail_information
)
return [
_redact_prompt_fields_in_guardrail_entry(entry)
for entry in entries
if isinstance(entry, dict)
]
entries: Final = [guardrail_information] if isinstance(guardrail_information, dict) else guardrail_information
return [_redact_prompt_fields_in_guardrail_entry(entry) for entry in entries if isinstance(entry, dict)]
_NUMERIC_COMPRESSION_STAT_KEYS: Final = (
@ -1640,9 +1498,7 @@ def _numeric_compression_stats_from_guardrail_response(
stats: Final = {
key: value
for key, value in guardrail_response.items()
if key in _NUMERIC_COMPRESSION_STAT_KEYS
and isinstance(value, (int, float))
and not isinstance(value, bool)
if key in _NUMERIC_COMPRESSION_STAT_KEYS and isinstance(value, (int, float)) and not isinstance(value, bool)
}
return stats or None
@ -1657,16 +1513,10 @@ def _redact_prompt_fields_in_guardrail_entry(
stats-only dict; spend aggregation reads them via
``extract_compression_saved_tokens``.
"""
preserved_stats: Final = _numeric_compression_stats_from_guardrail_response(
entry.get("guardrail_response")
)
preserved_stats: Final = _numeric_compression_stats_from_guardrail_response(entry.get("guardrail_response"))
redacted: Final[StandardLoggingGuardrailInformation] = {
**entry,
**{
key: REDACTED_BY_LITELM_STRING
for key in PROMPT_CARRYING_GUARDRAIL_FIELDS
if key in entry
},
**{key: REDACTED_BY_LITELM_STRING for key in PROMPT_CARRYING_GUARDRAIL_FIELDS if key in entry},
}
if preserved_stats is None:
return redacted
@ -1716,22 +1566,16 @@ def sanitize_error_information_for_spend_logs(
sanitized = _sanitize_request_body_for_spend_logs_payload(sanitized)
return cast(
StandardLoggingPayloadErrorInformation,
_error_information_without_ip_addresses(
_OBJECT_MAPPING.validate_python(sanitized)
)
_error_information_without_ip_addresses(_OBJECT_MAPPING.validate_python(sanitized))
if requester_ip_address_logging_disabled()
else sanitized,
)
_sanitize_error_information_for_spend_logs: Final = (
sanitize_error_information_for_spend_logs
)
_sanitize_error_information_for_spend_logs: Final = sanitize_error_information_for_spend_logs
def _convert_to_json_serializable_dict(
obj: object, visited: set[int] | None = None, max_depth: int = 20
) -> object:
def _convert_to_json_serializable_dict(obj: object, visited: set[int] | None = None, max_depth: int = 20) -> object:
"""
Convert object to JSON-serializable dict, handling Pydantic models safely.
@ -1770,20 +1614,12 @@ def _convert_to_json_serializable_dict(
# Recursively process the dumped dict
return _convert_to_json_serializable_dict(result, visited, max_depth - 1)
elif isinstance(obj, dict):
return {
k: _convert_to_json_serializable_dict(v, visited, max_depth - 1)
for k, v in obj.items()
}
return {k: _convert_to_json_serializable_dict(v, visited, max_depth - 1) for k, v in obj.items()}
elif isinstance(obj, list):
return [
_convert_to_json_serializable_dict(item, visited, max_depth - 1)
for item in obj
]
return [_convert_to_json_serializable_dict(item, visited, max_depth - 1) for item in obj]
elif hasattr(obj, "__dict__"):
# Handle objects with __dict__ attribute
return _convert_to_json_serializable_dict(
obj.__dict__, visited, max_depth - 1
)
return _convert_to_json_serializable_dict(obj.__dict__, visited, max_depth - 1)
else:
# Primitives (str, int, float, bool, None) pass through
return obj
@ -1826,10 +1662,7 @@ def _placeholder_stored_request_body_metadata(
{
**request_body,
"metadata": MappingProxyType(
{
key: placeholdered_fields.get(key, value)
for key, value in body_metadata.items()
}
{key: placeholdered_fields.get(key, value) for key, value in body_metadata.items()}
),
}
)
@ -1893,9 +1726,7 @@ _IP_ADDRESS_CHARACTERS: Final = "0123456789abcdefABCDEF.:"
_MAX_IP_ADDRESS_LENGTH: Final = len("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")
_LONG_HEX_GROUP: Final = re.compile(r"[0-9A-Fa-f]{5,}")
_TRUNCATION_MARKER_GROUP: Final = re.compile(f"({_TRUNCATION_MARKER.pattern})")
_IPV4_ADDRESS: Final = re.compile(
r"(?<![0-9A-Za-z])(?:\d{1,3}\.){3}\d{1,3}(?![0-9A-Za-z])"
)
_IPV4_ADDRESS: Final = re.compile(r"(?<![0-9A-Za-z])(?:\d{1,3}\.){3}\d{1,3}(?![0-9A-Za-z])")
_IPV6_ADDRESS_CANDIDATE: Final = re.compile(
r"(?:(?<![0-9A-Za-z:])|(?<=\w:))(?:[0-9A-Fa-f]{0,4}:){2,9}[0-9A-Fa-f]{0,4}(?![0-9A-Za-z:])"
)
@ -1920,9 +1751,7 @@ def _masked_ipv6_address(candidate: re.Match[str]) -> str:
def _without_ip_addresses(text: str) -> str:
return _IPV6_ADDRESS_CANDIDATE.sub(
_masked_ipv6_address, _IPV4_ADDRESS.sub(REDACTED_BY_LITELM_STRING, text)
)
return _IPV6_ADDRESS_CANDIDATE.sub(_masked_ipv6_address, _IPV4_ADDRESS.sub(REDACTED_BY_LITELM_STRING, text))
def _is_ip_address_piece(piece: str) -> bool:
@ -1932,32 +1761,18 @@ def _is_ip_address_piece(piece: str) -> bool:
def _without_ip_piece_before_cut(text: str) -> str:
run: Final = text[len(text.rstrip(_IP_ADDRESS_CHARACTERS)) :]
long_groups: Final = list(_LONG_HEX_GROUP.finditer(run))
piece: Final = run[long_groups[-1].end() if long_groups else 0 :][
-_MAX_IP_ADDRESS_LENGTH:
].lstrip(".:")
return (
text[: len(text) - len(piece)] + REDACTED_BY_LITELM_STRING
if _is_ip_address_piece(piece)
else text
)
piece: Final = run[long_groups[-1].end() if long_groups else 0 :][-_MAX_IP_ADDRESS_LENGTH:].lstrip(".:")
return text[: len(text) - len(piece)] + REDACTED_BY_LITELM_STRING if _is_ip_address_piece(piece) else text
def _without_ip_piece_after_cut(text: str) -> str:
run: Final = text[: len(text) - len(text.lstrip(_IP_ADDRESS_CHARACTERS))]
long_group: Final = _LONG_HEX_GROUP.search(run)
piece: Final = run[: long_group.start() if long_group else len(run)][
:_MAX_IP_ADDRESS_LENGTH
].rstrip(".:")
return (
REDACTED_BY_LITELM_STRING + text[len(piece) :]
if _is_ip_address_piece(piece)
else text
)
piece: Final = run[: long_group.start() if long_group else len(run)][:_MAX_IP_ADDRESS_LENGTH].rstrip(".:")
return REDACTED_BY_LITELM_STRING + text[len(piece) :] if _is_ip_address_piece(piece) else text
def _without_ip_pieces_beside_cuts(
text: str, *, after_cut: bool, before_cut: bool
) -> str:
def _without_ip_pieces_beside_cuts(text: str, *, after_cut: bool, before_cut: bool) -> str:
after: Final = _without_ip_piece_after_cut(text) if after_cut else text
return _without_ip_piece_before_cut(after) if before_cut else after
@ -1968,11 +1783,7 @@ def _masked_ip_text(text: str) -> str:
parts: Final = _TRUNCATION_MARKER_GROUP.split(_without_ip_addresses(text))
last: Final = len(parts) - 1
return "".join(
part
if index % 2
else _without_ip_pieces_beside_cuts(
part, after_cut=index > 0, before_cut=index < last
)
part if index % 2 else _without_ip_pieces_beside_cuts(part, after_cut=index > 0, before_cut=index < last)
for index, part in enumerate(parts)
)
@ -1982,9 +1793,7 @@ def _error_information_without_ip_addresses(
) -> Mapping[object, object]:
"""The error information with every IP address in its error message and traceback masked."""
return {
key: _masked_ip_text(value)
if key in _SCRUBBED_ERROR_TEXT_FIELDS and isinstance(value, str)
else value
key: _masked_ip_text(value) if key in _SCRUBBED_ERROR_TEXT_FIELDS and isinstance(value, str) else value
for key, value in error_information.items()
}
@ -1993,9 +1802,7 @@ def _stored_value_without_requester_ip_address(key: object, value: object) -> ob
if key == "requester_ip_address":
return None
if key == "error_information" and isinstance(value, Mapping):
return _error_information_without_ip_addresses(
_OBJECT_MAPPING.validate_python(value)
)
return _error_information_without_ip_addresses(_OBJECT_MAPPING.validate_python(value))
return _without_requester_ip_address(value, headers=key == "headers")
@ -2006,15 +1813,10 @@ def _without_requester_ip_address(value: object, *, headers: bool = False) -> ob
if headers and isinstance(item, str)
else _stored_value_without_requester_ip_address(key, item)
for key, item in _OBJECT_MAPPING.validate_python(value).items()
if not (
headers and isinstance(key, str) and key.lower() in _CLIENT_IP_HEADERS
)
if not (headers and isinstance(key, str) and key.lower() in _CLIENT_IP_HEADERS)
}
if isinstance(value, list):
return [
_without_requester_ip_address(item)
for item in _OBJECT_LIST.validate_python(value)
]
return [_without_requester_ip_address(item) for item in _OBJECT_LIST.validate_python(value)]
return value
@ -2022,9 +1824,7 @@ def _request_metadata_without_requester_ip_address(
request_body: Mapping[object, object],
) -> Mapping[object, object]:
return {
key: _without_requester_ip_address(value)
if key in _REQUEST_METADATA_KEYS
else value
key: _without_requester_ip_address(value) if key in _REQUEST_METADATA_KEYS else value
for key, value in request_body.items()
}
@ -2036,14 +1836,10 @@ def _stored_request_without_requester_ip_address(
`requester_ip_address` set to null, client-IP forwarding headers dropped and every IP address in the other header
values and in the error text masked inside their metadata."""
return {
key: _request_metadata_without_requester_ip_address(
_OBJECT_MAPPING.validate_python(value)
)
key: _request_metadata_without_requester_ip_address(_OBJECT_MAPPING.validate_python(value))
if key in CLASSIFIER_AUDIT_FIELDS and isinstance(value, Mapping)
else value
for key, value in _request_metadata_without_requester_ip_address(
request_body
).items()
for key, value in _request_metadata_without_requester_ip_address(request_body).items()
}
@ -2059,21 +1855,13 @@ def _get_proxy_server_request_for_spend_logs_payload(
If turn_off_message_logging is enabled, redact messages in the request body.
"""
if should_store_prompts_and_responses_in_spend_logs():
_proxy_server_request: Final = cast(
dict | None, litellm_params.get("proxy_server_request", EMPTY_MAPPING)
)
_proxy_server_request: Final = cast(dict | None, litellm_params.get("proxy_server_request", EMPTY_MAPPING))
if _proxy_server_request is not None:
_request_body = (
_proxy_server_request.get("body", EMPTY_MAPPING) or EMPTY_MAPPING
)
_request_body = _proxy_server_request.get("body", EMPTY_MAPPING) or EMPTY_MAPPING
standard_payload: Final = (kwargs or EMPTY_MAPPING).get(
"standard_logging_object"
)
standard_payload: Final = (kwargs or EMPTY_MAPPING).get("standard_logging_object")
if isinstance(standard_payload, Mapping):
_request_body = MappingProxyType(
{**_request_body, **classifier_audit_fields(standard_payload)}
)
_request_body = MappingProxyType({**_request_body, **classifier_audit_fields(standard_payload)})
if kwargs is not None:
realtime_tools: Final = kwargs.get("realtime_tools")
@ -2091,16 +1879,12 @@ def _get_proxy_server_request_for_spend_logs_payload(
# Build model_call_details dict to check redaction settings
model_call_details: Final = {
"litellm_params": litellm_params,
"standard_callback_dynamic_params": kwargs.get(
"standard_callback_dynamic_params"
),
"standard_callback_dynamic_params": kwargs.get("standard_callback_dynamic_params"),
}
# If redaction is enabled, convert to serializable dict before redacting
if should_redact_message_logging(model_call_details=model_call_details):
_request_body = _convert_mapping_to_json_serializable(
without_classifier_audit(_request_body)
)
_request_body = _convert_mapping_to_json_serializable(without_classifier_audit(_request_body))
perform_redaction(model_call_details=_request_body, result=None)
_request_body = _sanitize_request_body_for_spend_logs_payload(_request_body)
@ -2133,8 +1917,7 @@ def _get_vector_store_request_for_spend_logs_payload(
return None
for vector_store_request in vector_store_request_metadata:
vector_store_search_response: VectorStoreSearchResponse = (
vector_store_request.get("vector_store_search_response")
or VectorStoreSearchResponse()
vector_store_request.get("vector_store_search_response") or VectorStoreSearchResponse()
)
response_data = vector_store_search_response.get("data", []) or []
for response_item in response_data:
@ -2171,21 +1954,15 @@ def _get_response_for_spend_logs_payload(
litellm_params: Final = kwargs.get("litellm_params", {})
model_call_details: Final = {
"litellm_params": litellm_params,
"standard_callback_dynamic_params": kwargs.get(
"standard_callback_dynamic_params"
),
"standard_callback_dynamic_params": kwargs.get("standard_callback_dynamic_params"),
}
# If redaction is enabled, convert to serializable dict before redacting
if should_redact_message_logging(model_call_details=model_call_details):
response_obj = _convert_to_json_serializable_dict(response_obj)
response_obj = perform_redaction(
model_call_details={}, result=response_obj
)
response_obj = perform_redaction(model_call_details={}, result=response_obj)
sanitized_wrapper: Final = _sanitize_request_body_for_spend_logs_payload(
{"response": response_obj}
)
sanitized_wrapper: Final = _sanitize_request_body_for_spend_logs_payload({"response": response_obj})
sanitized_response: Final = sanitized_wrapper.get("response", response_obj)
@ -2223,9 +2000,9 @@ def should_store_prompts_and_responses_in_spend_logs() -> bool:
return get_secret_bool("STORE_PROMPTS_IN_SPEND_LOGS") is True
_SPEND_LOGS_METADATA_FIELDS_ADAPTER: Final[
TypeAdapter[SpendLogsMetadataFields | None]
] = TypeAdapter(SpendLogsMetadataFields | None)
_SPEND_LOGS_METADATA_FIELDS_ADAPTER: Final[TypeAdapter[SpendLogsMetadataFields | None]] = TypeAdapter(
SpendLogsMetadataFields | None
)
_SPEND_LOGS_METADATA_ADAPTER: Final = TypeAdapter(dict[str, JsonValue])
@ -2237,9 +2014,7 @@ def configured_spend_logs_metadata_fields() -> SpendLogsMetadataFields | None:
general_settings_view().get("spend_logs_metadata_fields")
)
except ValidationError as e:
verbose_proxy_logger.error(
"Ignoring invalid general_settings.spend_logs_metadata_fields: %s", e
)
verbose_proxy_logger.error("Ignoring invalid general_settings.spend_logs_metadata_fields: %s", e)
return None
@ -2252,9 +2027,7 @@ def requester_ip_address_logging_disabled() -> bool:
try:
return (
_OPTIONAL_BOOL_ADAPTER.validate_python(
general_settings_view().get("disable_requester_ip_address_logging")
)
_OPTIONAL_BOOL_ADAPTER.validate_python(general_settings_view().get("disable_requester_ip_address_logging"))
is True
)
except ValidationError:
@ -2268,9 +2041,7 @@ def spend_log_row_with_retained_metadata(
if fields is None or not isinstance(metadata_json, str):
return row
metadata: Final = _SPEND_LOGS_METADATA_ADAPTER.validate_json(metadata_json)
retained: Final = {
name: value for name, value in metadata.items() if fields.keeps(name)
}
retained: Final = {name: value for name, value in metadata.items() if fields.keeps(name)}
return {**row, "metadata": safe_dumps(retained)}