Fix json_logs issue: Replace print() statements with logger calls

This fix addresses the issue where some startup logs were printed as
plain text with ANSI color codes instead of being formatted as JSON
when json_logs: true is enabled.

Root cause:
- print() statements in proxy_cli.py and proxy_server.py bypassed
  the configured JsonFormatter
- ANSI color codes were hardcoded in the messages

Changes:
1. litellm/proxy/proxy_cli.py:
   - Replaced 2 print() calls with verbose_proxy_logger.info()

2. litellm/proxy/proxy_server.py:
   - Replaced print() calls for success/failure callbacks
   - Replaced print() calls for model list initialization
   - Removed ANSI color codes from all messages
   - Consolidated model list logging into single line

Impact:
- All startup logs now respect json_logs configuration
- No more ANSI color codes in logs
- Logs are now parseable by JSON aggregators
- ERROR logs with exceptions already worked (unchanged)

Testing:
Run ./reproduce_json_logs.sh to verify all logs are JSON formatted.
This commit is contained in:
Claude 2026-01-21 05:38:39 +00:00
parent ad91819c5a
commit 68f96276d8
No known key found for this signature in database
3 changed files with 69 additions and 12 deletions

61
FIX_DOCUMENTATION.md Normal file
View file

@ -0,0 +1,61 @@
# Fix for json_logs Issue
## Problem
When `json_logs: true` is enabled in litellm proxy configuration, some logs were printed as plain text with ANSI color codes instead of being formatted as JSON.
## Root Cause
Several `print()` statements in `proxy_cli.py` and `proxy_server.py` were outputting logs directly to stdout instead of using the configured logger. These bypassed the JsonFormatter entirely.
## Solution
Replaced `print()` statements with `verbose_proxy_logger.info()` calls in the following locations:
### Files Changed:
1. **litellm/proxy/proxy_cli.py**
- Line 137: `print(f"Using log_config: {log_config}")` → `verbose_proxy_logger.info(f"Using log_config: {log_config}")`
- Line 140: `print("Using json logs. Setting log_config to None.")` → `verbose_proxy_logger.info("Using json logs. Setting log_config to None.")`
2. **litellm/proxy/proxy_server.py**
- Lines 2425-2427: Replaced print statement for success callbacks
- Lines 2443-2445: Replaced print statement for failure callbacks
- Lines 2675-2679: Replaced print statements for model list initialization
- Removed ANSI color codes (`\033[94m`, `\033[32m`, etc.) from all messages
## Changes in Detail
### Before:
```python
print(f"{blue_color_code} Initialized Success Callbacks - {litellm.success_callback} {reset_color_code}")
```
### After:
```python
verbose_proxy_logger.info(f"Initialized Success Callbacks - {litellm.success_callback}")
```
### Model List Logging:
**Before:** Printed header + one line per model
```python
print("\033[32mLiteLLM: Proxy initialized with Config, Set models:\033[0m")
for model in model_list:
print(f"\033[32m {model.get('model_name', '')}\033[0m")
```
**After:** Single log line with all models
```python
model_names = [model.get('model_name', '') for model in model_list]
verbose_proxy_logger.info(f"LiteLLM: Proxy initialized with Config, Set models: {', '.join(model_names)}")
```
## Impact
- ✅ All startup INFO logs now use the configured JsonFormatter when `json_logs: true`
- ✅ No more ANSI color codes in logs
- ✅ Logs are now parseable by JSON log aggregators (Elasticsearch, Splunk, etc.)
- ✅ ERROR logs with exceptions already worked correctly (unchanged)
## Testing
Run the reproducer script to verify:
```bash
./reproduce_json_logs.sh
```
Expected: All logs after "Using json logs" should be in JSON format with no ANSI color codes.

View file

@ -128,16 +128,18 @@ class ProxyInitializationHelpers:
"""
import litellm
from litellm._logging import verbose_proxy_logger
uvicorn_args = {
"app": "litellm.proxy.proxy_server:app",
"host": host,
"port": port,
}
if log_config is not None:
print(f"Using log_config: {log_config}") # noqa
verbose_proxy_logger.info(f"Using log_config: {log_config}")
uvicorn_args["log_config"] = log_config
elif litellm.json_logs:
print("Using json logs. Setting log_config to None.") # noqa
verbose_proxy_logger.info("Using json logs. Setting log_config to None.")
uvicorn_args["log_config"] = None
if keepalive_timeout is not None:
uvicorn_args["timeout_keep_alive"] = keepalive_timeout

View file

@ -2422,9 +2422,7 @@ class ProxyConfig:
"mounting metrics endpoint"
)
PrometheusLogger._mount_metrics_endpoint()
print( # noqa
f"{blue_color_code} Initialized Success Callbacks - {litellm.success_callback} {reset_color_code}"
) # noqa
verbose_proxy_logger.info(f"Initialized Success Callbacks - {litellm.success_callback}")
elif key == "failure_callback":
litellm.failure_callback = []
@ -2440,9 +2438,7 @@ class ProxyConfig:
litellm.logging_callback_manager.add_litellm_failure_callback(
callback
)
print( # noqa
f"{blue_color_code} Initialized Failure Callbacks - {litellm.failure_callback} {reset_color_code}"
) # noqa
verbose_proxy_logger.info(f"Initialized Failure Callbacks - {litellm.failure_callback}")
elif key == "cache_params":
# this is set in the cache branch
# see usage here: https://docs.litellm.ai/docs/proxy/caching
@ -2672,15 +2668,13 @@ class ProxyConfig:
model_list = config.get("model_list", None)
if model_list:
router_params["model_list"] = model_list
print( # noqa
"\033[32mLiteLLM: Proxy initialized with Config, Set models:\033[0m"
) # noqa
model_names = [model.get('model_name', '') for model in model_list]
verbose_proxy_logger.info(f"LiteLLM: Proxy initialized with Config, Set models: {', '.join(model_names)}")
for model in model_list:
### LOAD FROM os.environ/ ###
for k, v in model["litellm_params"].items():
if isinstance(v, str) and v.startswith("os.environ/"):
model["litellm_params"][k] = get_secret(v)
print(f"\033[32m {model.get('model_name', '')}\033[0m") # noqa
litellm_model_name = model["litellm_params"]["model"]
litellm_model_api_base = model["litellm_params"].get("api_base", None)
if "ollama" in litellm_model_name and litellm_model_api_base is None: