mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-29 06:33:28 +00:00
fix(logging): emit startup warnings as WARNING records in JSON mode
This commit is contained in:
parent
ecfb597376
commit
593f07a1ee
4 changed files with 18 additions and 15 deletions
|
|
@ -943,17 +943,18 @@ def print_startup_message(message: str) -> None:
|
|||
if litellm.suppress_startup_output is True:
|
||||
return
|
||||
frame: Final = inspect.currentframe()
|
||||
_write_startup_message(message, frame.f_back if frame is not None else None)
|
||||
_write_startup_message(message, frame.f_back if frame is not None else None, logging.INFO)
|
||||
|
||||
|
||||
def print_startup_warning(message: str) -> None:
|
||||
"""Write a boot-time warning exactly as print_startup_message writes a message, even with
|
||||
suppress_startup_output on, since it names something the operator has to fix."""
|
||||
"""Write a boot-time warning as print_startup_message writes a message, even with suppress_startup_output
|
||||
on, since it names something the operator has to fix. With JSON logs on it is a WARNING record, on
|
||||
stdout where the print put it, so a collector that filters on the level field keeps it."""
|
||||
frame: Final = inspect.currentframe()
|
||||
_write_startup_message(message, frame.f_back if frame is not None else None)
|
||||
_write_startup_message(message, frame.f_back if frame is not None else None, logging.WARNING)
|
||||
|
||||
|
||||
def _write_startup_message(message: str, caller: FrameType | None) -> None:
|
||||
def _write_startup_message(message: str, caller: FrameType | None, level: int) -> None:
|
||||
if not litellm.json_logs:
|
||||
print(terminal_text(message), flush=True) # noqa: T201 # plain mode: this is the operator-terminal print it replaces
|
||||
return
|
||||
|
|
@ -962,7 +963,7 @@ def _write_startup_message(message: str, caller: FrameType | None) -> None:
|
|||
return
|
||||
record: Final = verbose_proxy_logger.makeRecord(
|
||||
verbose_proxy_logger.name,
|
||||
logging.INFO,
|
||||
level,
|
||||
caller.f_code.co_filename if caller is not None else __file__,
|
||||
caller.f_lineno if caller is not None else 0,
|
||||
text,
|
||||
|
|
@ -992,8 +993,8 @@ def _write_startup_message(message: str, caller: FrameType | None) -> None:
|
|||
|
||||
|
||||
def _startup_json_handler() -> logging.Handler:
|
||||
"""The proxy's JSON handler on stdout, filters included, for one startup message."""
|
||||
handler: Final = LevelRoutingStreamHandler()
|
||||
"""The proxy's JSON handler on stdout, filters included, for one startup message or warning."""
|
||||
handler: Final = logging.StreamHandler(sys.stdout)
|
||||
handler.setFormatter(JsonFormatter())
|
||||
handler.addFilter(_secret_filter)
|
||||
handler.addFilter(_correlation_filter)
|
||||
|
|
|
|||
|
|
@ -111,8 +111,8 @@ def test_policy_table_is_one_json_record_in_json_mode(monkeypatch, capfd):
|
|||
|
||||
|
||||
def test_missing_attachments_warning_is_a_second_json_record(monkeypatch, capfd):
|
||||
"""Without attachments the table and the yellow warning are two INFO records on stdout, where the two
|
||||
prints put them."""
|
||||
"""Without attachments the table and the yellow warning are an INFO and a WARNING record on stdout,
|
||||
where the two prints put them."""
|
||||
monkeypatch.setattr(litellm, "json_logs", True)
|
||||
monkeypatch.setattr(sys, "excepthook", sys.excepthook)
|
||||
turn_on_json()
|
||||
|
|
@ -126,4 +126,4 @@ def test_missing_attachments_warning_is_a_second_json_record(monkeypatch, capfd)
|
|||
"\n".join(("LiteLLM Policy Engine: Loaded 1 policies", "", *POLICY_ROWS)),
|
||||
NO_ATTACHMENTS_WARNING,
|
||||
]
|
||||
assert {record["level"] for record in records} == {"INFO"}
|
||||
assert [record["level"] for record in records] == ["INFO", "WARNING"]
|
||||
|
|
|
|||
|
|
@ -4252,8 +4252,8 @@ class TestEnforcePrismaMigrationCheckNoticeAroundTheConfigRead:
|
|||
|
||||
def test_granian_flag_notices_are_json_records_in_json_mode(monkeypatch, capfd):
|
||||
"""The yellow notices for the flags Granian ignores (`--max_requests_before_restart`, `--ciphers`) are
|
||||
printed while the launcher starts; with json_logs on they are INFO records on stdout like every other
|
||||
line, not plaintext between the records."""
|
||||
printed while the launcher starts; with json_logs on they are WARNING records on stdout after the INFO
|
||||
start line, not plaintext between the records."""
|
||||
pytest.importorskip("granian")
|
||||
monkeypatch.setattr(litellm, "json_logs", True)
|
||||
monkeypatch.setattr(sys, "excepthook", sys.excepthook) # turn_on_json swaps it; put it back at teardown
|
||||
|
|
@ -4284,4 +4284,4 @@ def test_granian_flag_notices_are_json_records_in_json_mode(monkeypatch, capfd):
|
|||
"(Granian uses workers_lifetime in seconds, not a per-request limit).",
|
||||
"LiteLLM: --ciphers is not applied when using --run_granian.",
|
||||
]
|
||||
assert {record["level"] for record in records} == {"INFO"}
|
||||
assert [record["level"] for record in records] == ["INFO", "WARNING", "WARNING"]
|
||||
|
|
|
|||
|
|
@ -1914,7 +1914,8 @@ def test_print_startup_warning_still_prints_when_suppressed(
|
|||
monkeypatch: pytest.MonkeyPatch, capfd: pytest.CaptureFixture[str], json_logs: bool
|
||||
):
|
||||
"""A warning names something the operator has to fix, like an ignored flag or a failed migration diff,
|
||||
so suppress_startup_output leaves it in place, at the caller's location in JSON mode."""
|
||||
so suppress_startup_output leaves it in place. In JSON mode it is a WARNING record at the caller's
|
||||
location, on stdout where the print put it, so a collector's WARNING filter keeps it."""
|
||||
monkeypatch.setattr(litellm, "json_logs", json_logs)
|
||||
monkeypatch.setattr(litellm, "suppress_startup_output", True)
|
||||
monkeypatch.setattr(sys, "excepthook", sys.excepthook)
|
||||
|
|
@ -1930,6 +1931,7 @@ def test_print_startup_warning_still_prints_when_suppressed(
|
|||
if json_logs:
|
||||
record: Final = json.loads(lines[0])
|
||||
assert record["message"] == "LiteLLM: --ciphers is not applied when using --run_granian."
|
||||
assert record["level"] == "WARNING"
|
||||
assert str(record["logger"]).startswith("test_logging.py:"), record["logger"]
|
||||
else:
|
||||
assert lines[0] == "LiteLLM: --ciphers is not applied when using --run_granian."
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue