Skip to content

Commit 4fffd33

Browse files
Merge pull request #17167 from BerriAI/litellm_spend_logs_api
[Refactor] Deprecate `spend/logs` & add `spend/logs/v2`
2 parents 7f42b9b + df190d2 commit 4fffd33

File tree

1 file changed

+41
-17
lines changed

1 file changed

+41
-17
lines changed

litellm/proxy/spend_tracking/spend_management_endpoints.py

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
#### SPEND MANAGEMENT #####
22
import collections
3+
import json
34
import os
45
from datetime import datetime, timedelta, timezone
56
from functools import lru_cache
67
from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional
78

89
import fastapi
9-
from fastapi import APIRouter, Depends, HTTPException, status
10+
from fastapi import APIRouter, Depends, HTTPException, Request, status
1011

1112
import litellm
1213
from litellm._logging import verbose_proxy_logger
@@ -1609,6 +1610,14 @@ async def calculate_spend(request: SpendCalculateRequest):
16091610
)
16101611

16111612

1613+
@router.get(
1614+
"/spend/logs/v2",
1615+
tags=["Budget & Spend Tracking"],
1616+
dependencies=[Depends(user_api_key_auth)],
1617+
responses={
1618+
200: {"model": Dict[str, Any]},
1619+
},
1620+
)
16121621
@router.get(
16131622
"/spend/logs/ui",
16141623
tags=["Budget & Spend Tracking"],
@@ -1619,6 +1628,7 @@ async def calculate_spend(request: SpendCalculateRequest):
16191628
},
16201629
)
16211630
async def ui_view_spend_logs( # noqa: PLR0915
1631+
request: Request,
16221632
api_key: Optional[str] = fastapi.Query(
16231633
default=None,
16241634
description="Get spend logs based on api key",
@@ -1672,16 +1682,16 @@ async def ui_view_spend_logs( # noqa: PLR0915
16721682
),
16731683
):
16741684
"""
1675-
View spend logs for UI with pagination support
1685+
View spend logs with pagination support.
1686+
Available at both `/spend/logs/v2` (public API) and `/spend/logs/ui` (internal UI).
16761687
1677-
Returns:
1678-
{
1679-
"data": List[LiteLLM_SpendLogs], # Paginated spend logs
1680-
"total": int, # Total number of records
1681-
"page": int, # Current page number
1682-
"page_size": int, # Number of items per page
1683-
"total_pages": int # Total number of pages
1684-
}
1688+
Returns paginated response with data, total, page, page_size, and total_pages.
1689+
1690+
Example:
1691+
```
1692+
curl -X GET "http://0.0.0.0:8000/spend/logs/v2?start_date=2025-11-25%2000:00:00&end_date=2025-11-26%2023:59:59&page=1&page_size=50" \
1693+
-H "Authorization: Bearer sk-1234"
1694+
```
16851695
"""
16861696
from litellm.proxy.proxy_server import prisma_client
16871697

@@ -1702,13 +1712,24 @@ async def ui_view_spend_logs( # noqa: PLR0915
17021712
)
17031713

17041714
try:
1705-
# Convert the date strings to datetime objects
1706-
start_date_obj = datetime.strptime(start_date, "%Y-%m-%d %H:%M:%S").replace(
1707-
tzinfo=timezone.utc
1708-
)
1709-
end_date_obj = datetime.strptime(end_date, "%Y-%m-%d %H:%M:%S").replace(
1710-
tzinfo=timezone.utc
1711-
)
1715+
is_v2 = "/spend/logs/v2" in request.url.path
1716+
formats = ["%Y-%m-%d %H:%M:%S", "%Y-%m-%d"] if is_v2 else ["%Y-%m-%d %H:%M:%S"]
1717+
1718+
def parse_date(date_str: str) -> datetime:
1719+
date_str = date_str.strip()
1720+
for fmt in formats:
1721+
try:
1722+
return datetime.strptime(date_str, fmt).replace(tzinfo=timezone.utc)
1723+
except ValueError:
1724+
continue
1725+
expected = "'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'" if is_v2 else "'YYYY-MM-DD HH:MM:SS'"
1726+
raise HTTPException(
1727+
status_code=status.HTTP_400_BAD_REQUEST,
1728+
detail=f"Invalid date format: {date_str}. Expected: {expected}",
1729+
)
1730+
1731+
start_date_obj = parse_date(start_date)
1732+
end_date_obj = parse_date(end_date)
17121733

17131734
# Convert to ISO format strings for Prisma
17141735
start_date_iso = start_date_obj.isoformat() # Already in UTC, no need to add Z
@@ -1896,6 +1917,9 @@ async def view_spend_logs( # noqa: PLR0915
18961917
user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth),
18971918
):
18981919
"""
1920+
[DEPRECATED] This endpoint is not paginated and can cause performance issues.
1921+
Please use `/spend/logs/v2` instead for paginated access to spend logs.
1922+
18991923
View all spend logs, if request_id is provided, only logs for that request_id will be returned
19001924
19011925
When start_date and end_date are provided:

0 commit comments

Comments
 (0)