mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-07 02:59:05 +00:00
removed jwt tokens from detailed_debug logging
This commit is contained in:
parent
af3acdda18
commit
82204d3e97
3 changed files with 85 additions and 7 deletions
|
|
@ -252,6 +252,34 @@ def clean_headers(
|
|||
return clean_headers
|
||||
|
||||
|
||||
def _mask_secret_fields_for_logging(secret_fields: dict) -> dict:
|
||||
"""
|
||||
Masks sensitive values (like JWT tokens) in secret_fields before logging.
|
||||
Keeps the field structure intact but redacts authorization header values.
|
||||
"""
|
||||
_sensitive_header_keys = frozenset(
|
||||
{"authorization", "x-api-key", "api-key", "x-litellm-api-key"}
|
||||
)
|
||||
if not isinstance(secret_fields, dict):
|
||||
return secret_fields
|
||||
masked = {}
|
||||
for field_key, field_value in secret_fields.items():
|
||||
if isinstance(field_value, dict):
|
||||
masked_inner = {}
|
||||
for k, v in field_value.items():
|
||||
if k.lower() in _sensitive_header_keys and isinstance(v, str):
|
||||
if len(v) > 20:
|
||||
masked_inner[k] = v[:10] + "****" + v[-4:]
|
||||
else:
|
||||
masked_inner[k] = "****"
|
||||
else:
|
||||
masked_inner[k] = v
|
||||
masked[field_key] = masked_inner
|
||||
else:
|
||||
masked[field_key] = field_value
|
||||
return masked
|
||||
|
||||
|
||||
class LiteLLMProxyRequestSetup:
|
||||
@staticmethod
|
||||
def _get_timeout_from_request(headers: dict) -> Optional[float]:
|
||||
|
|
@ -899,13 +927,19 @@ async def add_litellm_data_to_request( # noqa: PLR0915
|
|||
|
||||
## Cache Controls
|
||||
headers = request.headers
|
||||
verbose_proxy_logger.debug("Request Headers: %s", headers)
|
||||
verbose_proxy_logger.debug("Request Headers: %s", clean_headers(headers))
|
||||
cache_control_header = headers.get("Cache-Control", None)
|
||||
if cache_control_header:
|
||||
cache_dict = parse_cache_control(cache_control_header)
|
||||
data["ttl"] = cache_dict.get("s-maxage")
|
||||
|
||||
verbose_proxy_logger.debug("receiving data: %s", data)
|
||||
verbose_proxy_logger.debug(
|
||||
"receiving data: %s",
|
||||
{
|
||||
k: (_mask_secret_fields_for_logging(v) if k == "secret_fields" else v)
|
||||
for k, v in data.items()
|
||||
},
|
||||
)
|
||||
|
||||
# Parse metadata if it's a string (e.g., from multipart/form-data)
|
||||
if "metadata" in data and data["metadata"] is not None:
|
||||
|
|
@ -1133,7 +1167,11 @@ async def add_litellm_data_to_request( # noqa: PLR0915
|
|||
)
|
||||
|
||||
verbose_proxy_logger.debug(
|
||||
"[PROXY] returned data from litellm_pre_call_utils: %s", data
|
||||
"[PROXY] returned data from litellm_pre_call_utils: %s",
|
||||
{
|
||||
k: (_mask_secret_fields_for_logging(v) if k == "secret_fields" else v)
|
||||
for k, v in data.items()
|
||||
},
|
||||
)
|
||||
|
||||
## ENFORCED PARAMS CHECK
|
||||
|
|
|
|||
|
|
@ -328,7 +328,11 @@ from litellm.proxy.hooks.prompt_injection_detection import (
|
|||
)
|
||||
from litellm.proxy.hooks.proxy_track_cost_callback import _ProxyDBLogger
|
||||
from litellm.proxy.image_endpoints.endpoints import router as image_router
|
||||
from litellm.proxy.litellm_pre_call_utils import add_litellm_data_to_request
|
||||
from litellm.proxy.litellm_pre_call_utils import (
|
||||
_mask_secret_fields_for_logging,
|
||||
add_litellm_data_to_request,
|
||||
clean_headers,
|
||||
)
|
||||
from litellm.proxy.management_endpoints.budget_management_endpoints import (
|
||||
router as budget_management_router,
|
||||
)
|
||||
|
|
@ -9838,11 +9842,17 @@ async def async_queue_request(
|
|||
data["proxy_server_request"] = {
|
||||
"url": str(request.url),
|
||||
"method": request.method,
|
||||
"headers": dict(request.headers),
|
||||
"headers": clean_headers(request.headers),
|
||||
"body": copy.copy(data), # use copy instead of deepcopy
|
||||
}
|
||||
|
||||
verbose_proxy_logger.debug("receiving data: %s", data)
|
||||
verbose_proxy_logger.debug(
|
||||
"receiving data: %s",
|
||||
{
|
||||
k: (_mask_secret_fields_for_logging(v) if k == "secret_fields" else v)
|
||||
for k, v in data.items()
|
||||
},
|
||||
)
|
||||
data["model"] = (
|
||||
general_settings.get("completion_model", None) # server default
|
||||
or user_model # model name passed via cli args
|
||||
|
|
|
|||
|
|
@ -7267,6 +7267,32 @@ def get_valid_models(
|
|||
return [] # NON-Blocking
|
||||
|
||||
|
||||
def _mask_secret_fields_for_logging(secret_fields: dict) -> dict:
|
||||
"""
|
||||
Masks sensitive values (like JWT tokens) in secret_fields before logging.
|
||||
Keeps the field structure intact but redacts authorization header values.
|
||||
"""
|
||||
if not isinstance(secret_fields, dict):
|
||||
return secret_fields
|
||||
masked = {}
|
||||
for field_key, field_value in secret_fields.items():
|
||||
if isinstance(field_value, dict):
|
||||
masked_inner = {}
|
||||
for k, v in field_value.items():
|
||||
if k.lower() in ("authorization", "x-api-key", "api-key", "x-litellm-api-key") and isinstance(v, str):
|
||||
# Show first 10 and last 4 chars, mask the rest
|
||||
if len(v) > 20:
|
||||
masked_inner[k] = v[:10] + "****" + v[-4:]
|
||||
else:
|
||||
masked_inner[k] = "****"
|
||||
else:
|
||||
masked_inner[k] = v
|
||||
masked[field_key] = masked_inner
|
||||
else:
|
||||
masked[field_key] = field_value
|
||||
return masked
|
||||
|
||||
|
||||
def print_args_passed_to_litellm(original_function, args, kwargs):
|
||||
if not _is_debugging_on():
|
||||
return
|
||||
|
|
@ -7292,7 +7318,11 @@ def print_args_passed_to_litellm(original_function, args, kwargs):
|
|||
return
|
||||
|
||||
args_str = ", ".join(map(repr, args))
|
||||
kwargs_str = ", ".join(f"{key}={repr(value)}" for key, value in kwargs.items())
|
||||
# Mask JWT tokens / auth headers in secret_fields before logging
|
||||
kwargs_str = ", ".join(
|
||||
f"{key}={repr(_mask_secret_fields_for_logging(value)) if key == 'secret_fields' else repr(value)}"
|
||||
for key, value in kwargs.items()
|
||||
)
|
||||
print_verbose(
|
||||
"\n",
|
||||
) # new line before
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue