fix(logging): redact raw callback request payloads

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
yucheng 2026-09-14 19:41:15 +00:00
parent 008318c5a7
commit 566a323e47
3 changed files with 51 additions and 12 deletions

View file

@ -3194,25 +3194,27 @@ class Logging(LiteLLMLoggingBaseClass):
)
if isinstance(callback, CustomLogger): # custom logger class
model_call_details: dict = self.model_call_details
callback_model_call_details: Final[dict] = self.model_call_details
##################################
# call redaction hook for custom logger
model_call_details = callback.redact_standard_logging_payload_from_model_call_details(
model_call_details=model_call_details
standard_redacted_model_call_details: Final[dict] = (
callback.redact_standard_logging_payload_from_model_call_details(
model_call_details=callback_model_call_details
)
)
model_call_details = redact_streaming_responses_for_custom_logger(
model_call_details=model_call_details, custom_logger=callback
streaming_redacted_model_call_details: Final[dict] = redact_streaming_responses_for_custom_logger(
model_call_details=standard_redacted_model_call_details, custom_logger=callback
)
model_call_details = redact_model_call_details_for_custom_logger(
model_call_details=model_call_details, custom_logger=callback
redacted_model_call_details: Final[dict] = redact_model_call_details_for_custom_logger(
model_call_details=streaming_redacted_model_call_details, custom_logger=callback
)
##################################
if self.stream is True:
if "async_complete_streaming_response" in model_call_details:
if "async_complete_streaming_response" in redacted_model_call_details:
await callback.async_log_success_event(
kwargs=model_call_details,
kwargs=redacted_model_call_details,
response_obj=redact_response_for_custom_logger(
result=model_call_details["async_complete_streaming_response"],
result=redacted_model_call_details["async_complete_streaming_response"],
custom_logger=callback,
),
start_time=start_time,
@ -3220,14 +3222,14 @@ class Logging(LiteLLMLoggingBaseClass):
)
else:
await callback.async_log_stream_event( # [TODO]: move this to being an async log stream event function
kwargs=model_call_details,
kwargs=redacted_model_call_details,
response_obj=redact_response_for_custom_logger(result=result, custom_logger=callback),
start_time=start_time,
end_time=end_time,
)
else:
await callback.async_log_success_event(
kwargs=model_call_details,
kwargs=redacted_model_call_details,
response_obj=redact_response_for_custom_logger(result=result, custom_logger=callback),
start_time=start_time,
end_time=end_time,

View file

@ -88,6 +88,23 @@ def redact_model_call_details_for_custom_logger(
if not opted_out or custom_logger.redacts_messages_itself():
return model_call_details
response_keys: Final = ("response", "original_response", "complete_response")
raw_request_typed_dict: Final = model_call_details.get("raw_request_typed_dict")
raw_request_body: Final = (
raw_request_typed_dict.get("raw_request_body") if isinstance(raw_request_typed_dict, dict) else None
)
redacted_raw_request_typed_dict: Final = (
{
**raw_request_typed_dict,
"raw_request_body": {
**raw_request_body,
"messages": [{"role": "user", "content": REDACTED_BY_LITELLM}],
"input": "",
"prompt": "",
},
}
if isinstance(raw_request_typed_dict, dict) and isinstance(raw_request_body, dict)
else raw_request_typed_dict
)
return {
**model_call_details,
**{
@ -95,6 +112,11 @@ def redact_model_call_details_for_custom_logger(
for key in response_keys
if model_call_details.get(key) is not None
},
**(
{"raw_request_typed_dict": redacted_raw_request_typed_dict}
if redacted_raw_request_typed_dict is not raw_request_typed_dict
else {}
),
}

View file

@ -1054,6 +1054,9 @@ def test_success_handler_redacts_custom_logger_payload_per_callback(logging_obj)
logging_obj.model_call_details["original_response"] = {
"choices": [{"message": {"content": "original response"}}]
}
logging_obj.model_call_details["raw_request_typed_dict"] = {
"raw_request_body": {"messages": [{"role": "user", "content": "original request"}]},
}
standard_logging_object = {
"messages": [{"role": "user", "content": "original message"}],
"response": {"choices": []},
@ -1076,14 +1079,26 @@ def test_success_handler_redacts_custom_logger_payload_per_callback(logging_obj)
assert (
logging_obj.model_call_details["standard_logging_object"]["messages"][0]["content"] == "original message"
)
assert (
logging_obj.model_call_details["raw_request_typed_dict"]["raw_request_body"]["messages"][0]["content"]
== "original request"
)
assert redacting_logger.received_kwargs[0]["messages"] == [{"role": "user", "content": "redacted-by-litellm"}]
assert (
redacting_logger.received_kwargs[0]["original_response"]["choices"][0]["message"]["content"]
== "redacted-by-litellm"
)
assert (
redacting_logger.received_kwargs[0]["raw_request_typed_dict"]["raw_request_body"]["messages"][0]["content"]
== "redacted-by-litellm"
)
assert (
plain_logger.received_kwargs[0]["original_response"]["choices"][0]["message"]["content"] == "original response"
)
assert (
plain_logger.received_kwargs[0]["raw_request_typed_dict"]["raw_request_body"]["messages"][0]["content"]
== "original request"
)
assert redacting_logger.received_response_objs[0] == {"text": "redacted-by-litellm"}
assert plain_logger.received_response_objs[0] == {"id": "response"}