mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-11 08:38:24 +00:00
fix(logging): take the scrubbed exception message off the traceback when the payload has none
When the failure payload could not be built, scrubbed_exception_text found the marker only in the logged traceback and handed Langfuse, Traceloop, OTel v1 and MLflow an empty message. Use the exception lines that end the scrubbed traceback.
This commit is contained in:
parent
0d6d09a00a
commit
12f2b3c03d
2 changed files with 24 additions and 4 deletions
|
|
@ -583,6 +583,7 @@ def scrubbed_exception_text(model_call_details: Mapping[str, object]) -> tuple[s
|
|||
"""
|
||||
The error message and traceback a failure logged when redaction scrubbed the request's text out of
|
||||
either, for callbacks that would otherwise record the raw exception. ``None`` when nothing was scrubbed.
|
||||
Without a logged error message, the message is the exception text that ends the traceback.
|
||||
"""
|
||||
payload: Final = _as_mapping(model_call_details.get("standard_logging_object")) or {}
|
||||
error_information: Final = _as_mapping(payload.get("error_information")) or {}
|
||||
|
|
@ -593,10 +594,14 @@ def scrubbed_exception_text(model_call_details: Mapping[str, object]) -> tuple[s
|
|||
)
|
||||
if not any(isinstance(text, str) and REDACTED_BY_LITELLM in text for text in (message, traceback_text)):
|
||||
return None
|
||||
return (
|
||||
message if isinstance(message, str) else "",
|
||||
traceback_text if isinstance(traceback_text, str) else "",
|
||||
)
|
||||
logged_traceback_text: Final = traceback_text if isinstance(traceback_text, str) else ""
|
||||
return (message if isinstance(message, str) else _exception_text(logged_traceback_text), logged_traceback_text)
|
||||
|
||||
|
||||
def _exception_text(traceback_text: str) -> str:
|
||||
"""The lines after the last indented frame line of ``traceback_text``."""
|
||||
lines: Final = reversed(traceback_text.rstrip().splitlines())
|
||||
return "\n".join(reversed(tuple(itertools.takewhile(lambda line: not line.startswith(" "), lines))))
|
||||
|
||||
|
||||
def redacted_standard_logging_payload(payload: Mapping[str, object]) -> Mapping[str, object]:
|
||||
|
|
|
|||
|
|
@ -2202,6 +2202,21 @@ def test_scrubbed_exception_text_reports_a_scrub_of_the_logged_traceback() -> No
|
|||
assert scrubbed_exception_text(model_call_details) == ("outer", "ValueError: bad: redacted-by-litellm")
|
||||
|
||||
|
||||
def test_scrubbed_exception_text_reads_the_message_off_the_traceback_without_a_logged_message() -> None:
|
||||
traceback_text: Final = (
|
||||
"Traceback (most recent call last):\n"
|
||||
' File "main.py", line 1, in completion\n'
|
||||
" raise BadRequestError(message)\n"
|
||||
"BadRequestError: Invalid content: 'redacted-by-litellm'\n"
|
||||
"Received Messages=['redacted-by-litellm']\n"
|
||||
)
|
||||
|
||||
assert scrubbed_exception_text({"traceback_exception": traceback_text}) == (
|
||||
"BadRequestError: Invalid content: 'redacted-by-litellm'\nReceived Messages=['redacted-by-litellm']",
|
||||
traceback_text,
|
||||
)
|
||||
|
||||
|
||||
def test_scrubbed_error_information_for_request_scrubs_only_when_the_request_redacts() -> None:
|
||||
error_information: Final = StandardLoggingPayloadErrorInformation(
|
||||
error_code="400", error_class="BadRequestError", error_message=f"bad: {PROMPT}", traceback=f"tb {PROMPT}"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue