mirror of
https://github.com/BerriAI/litellm.git
synced 2025-04-25 18:54:30 +00:00
(feat) - track org_id in SpendLogs (#8253)
* track org id in spend logs * read org id from team table * show user_api_key_org_id in spend logs * test_spend_logs_payload * test_spend_logs_with_org_id * test_spend_logs_with_org_id
This commit is contained in:
parent
b59b26f797
commit
1d5370b9e6
5 changed files with 90 additions and 6 deletions
|
@ -1856,6 +1856,7 @@ class SpendLogsMetadata(TypedDict):
|
||||||
user_api_key: Optional[str]
|
user_api_key: Optional[str]
|
||||||
user_api_key_alias: Optional[str]
|
user_api_key_alias: Optional[str]
|
||||||
user_api_key_team_id: Optional[str]
|
user_api_key_team_id: Optional[str]
|
||||||
|
user_api_key_org_id: Optional[str]
|
||||||
user_api_key_user_id: Optional[str]
|
user_api_key_user_id: Optional[str]
|
||||||
user_api_key_team_alias: Optional[str]
|
user_api_key_team_alias: Optional[str]
|
||||||
spend_logs_metadata: Optional[
|
spend_logs_metadata: Optional[
|
||||||
|
|
|
@ -38,6 +38,7 @@ def _get_spend_logs_metadata(metadata: Optional[dict]) -> SpendLogsMetadata:
|
||||||
user_api_key=None,
|
user_api_key=None,
|
||||||
user_api_key_alias=None,
|
user_api_key_alias=None,
|
||||||
user_api_key_team_id=None,
|
user_api_key_team_id=None,
|
||||||
|
user_api_key_org_id=None,
|
||||||
user_api_key_user_id=None,
|
user_api_key_user_id=None,
|
||||||
user_api_key_team_alias=None,
|
user_api_key_team_alias=None,
|
||||||
spend_logs_metadata=None,
|
spend_logs_metadata=None,
|
||||||
|
|
|
@ -1544,6 +1544,7 @@ class PrismaClient:
|
||||||
t.team_alias AS team_alias,
|
t.team_alias AS team_alias,
|
||||||
t.metadata AS team_metadata,
|
t.metadata AS team_metadata,
|
||||||
t.members_with_roles AS team_members_with_roles,
|
t.members_with_roles AS team_members_with_roles,
|
||||||
|
t.organization_id as org_id,
|
||||||
tm.spend AS team_member_spend,
|
tm.spend AS team_member_spend,
|
||||||
m.aliases AS team_model_aliases,
|
m.aliases AS team_model_aliases,
|
||||||
-- Added comma to separate b.* columns
|
-- Added comma to separate b.* columns
|
||||||
|
|
|
@ -66,14 +66,14 @@ def test_spend_logs_payload(model_id: Optional[str]):
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"tags": ["model-anthropic-claude-v2.1", "app-ishaan-prod"],
|
"tags": ["model-anthropic-claude-v2.1", "app-ishaan-prod"],
|
||||||
"user_api_key": "88dc28d0f030c55ed4ab77ed8faf098196cb1c05df778539800c9f1243fe6b4b",
|
"user_api_key": "88dc28d0f030c55ed4ab77ed8faf098196cb1c05df778539800c9f1243fe6b4b",
|
||||||
"user_api_key_alias": None,
|
"user_api_key_alias": "custom-key-alias",
|
||||||
"user_api_end_user_max_budget": None,
|
"user_api_end_user_max_budget": None,
|
||||||
"litellm_api_version": "0.0.0",
|
"litellm_api_version": "0.0.0",
|
||||||
"global_max_parallel_requests": None,
|
"global_max_parallel_requests": None,
|
||||||
"user_api_key_user_id": "116544810872468347480",
|
"user_api_key_user_id": "116544810872468347480",
|
||||||
"user_api_key_org_id": None,
|
"user_api_key_org_id": "custom-org-id",
|
||||||
"user_api_key_team_id": None,
|
"user_api_key_team_id": "custom-team-id",
|
||||||
"user_api_key_team_alias": None,
|
"user_api_key_team_alias": "custom-team-alias",
|
||||||
"user_api_key_metadata": {},
|
"user_api_key_metadata": {},
|
||||||
"requester_ip_address": "127.0.0.1",
|
"requester_ip_address": "127.0.0.1",
|
||||||
"spend_logs_metadata": {"hello": "world"},
|
"spend_logs_metadata": {"hello": "world"},
|
||||||
|
@ -216,6 +216,10 @@ def test_spend_logs_payload(model_id: Optional[str]):
|
||||||
assert (
|
assert (
|
||||||
payload["request_tags"] == '["model-anthropic-claude-v2.1", "app-ishaan-prod"]'
|
payload["request_tags"] == '["model-anthropic-claude-v2.1", "app-ishaan-prod"]'
|
||||||
)
|
)
|
||||||
|
assert payload["metadata"]["user_api_key_org_id"] == "custom-org-id"
|
||||||
|
assert payload["metadata"]["user_api_key_team_id"] == "custom-team-id"
|
||||||
|
assert payload["metadata"]["user_api_key_team_alias"] == "custom-team-alias"
|
||||||
|
assert payload["metadata"]["user_api_key_alias"] == "custom-key-alias"
|
||||||
|
|
||||||
assert payload["custom_llm_provider"] == "azure"
|
assert payload["custom_llm_provider"] == "azure"
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
# What this tests?
|
# What this tests?
|
||||||
## Tests /spend endpoints.
|
## Tests /spend endpoints.
|
||||||
|
|
||||||
import pytest, time, uuid
|
import pytest, time, uuid, json
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
|
||||||
|
|
||||||
async def generate_key(session, models=[]):
|
async def generate_key(session, models=[], team_id=None):
|
||||||
url = "http://0.0.0.0:4000/key/generate"
|
url = "http://0.0.0.0:4000/key/generate"
|
||||||
headers = {"Authorization": "Bearer sk-1234", "Content-Type": "application/json"}
|
headers = {"Authorization": "Bearer sk-1234", "Content-Type": "application/json"}
|
||||||
data = {
|
data = {
|
||||||
"models": models,
|
"models": models,
|
||||||
"duration": None,
|
"duration": None,
|
||||||
}
|
}
|
||||||
|
if team_id is not None:
|
||||||
|
data["team_id"] = team_id
|
||||||
|
|
||||||
async with session.post(url, headers=headers, json=data) as response:
|
async with session.post(url, headers=headers, json=data) as response:
|
||||||
status = response.status
|
status = response.status
|
||||||
|
@ -113,6 +115,81 @@ async def test_spend_logs():
|
||||||
await get_spend_logs(session=session, request_id=response["id"])
|
await get_spend_logs(session=session, request_id=response["id"])
|
||||||
|
|
||||||
|
|
||||||
|
async def generate_org(session: aiohttp.ClientSession) -> dict:
|
||||||
|
"""
|
||||||
|
Generate a new organization using the API.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
session: aiohttp client session
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Response containing org_id
|
||||||
|
"""
|
||||||
|
url = "http://0.0.0.0:4000/organization/new"
|
||||||
|
headers = {"Authorization": "Bearer sk-1234", "Content-Type": "application/json"}
|
||||||
|
|
||||||
|
request_body = {
|
||||||
|
"organization_alias": f"test-org-{uuid.uuid4()}",
|
||||||
|
}
|
||||||
|
|
||||||
|
async with session.post(url, headers=headers, json=request_body) as response:
|
||||||
|
return await response.json()
|
||||||
|
|
||||||
|
|
||||||
|
async def generate_team(session: aiohttp.ClientSession, org_id: str) -> dict:
|
||||||
|
"""
|
||||||
|
Generate a new team within an organization using the API.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
session: aiohttp client session
|
||||||
|
org_id: Organization ID to create the team in
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Response containing team_id
|
||||||
|
"""
|
||||||
|
url = "http://0.0.0.0:4000/team/new"
|
||||||
|
headers = {"Authorization": "Bearer sk-1234", "Content-Type": "application/json"}
|
||||||
|
data = {"organization_id": org_id}
|
||||||
|
|
||||||
|
async with session.post(url, headers=headers, json=data) as response:
|
||||||
|
return await response.json()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_spend_logs_with_org_id():
|
||||||
|
"""
|
||||||
|
- Create Organization
|
||||||
|
- Create Team in organization
|
||||||
|
- Create Key in organization
|
||||||
|
- Make call (makes sure it's in spend logs)
|
||||||
|
- Get request id from logs
|
||||||
|
- Assert spend logs have correct org_id and team_id
|
||||||
|
"""
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
org_gen = await generate_org(session=session)
|
||||||
|
print("org_gen: ", json.dumps(org_gen, indent=4, default=str))
|
||||||
|
org_id = org_gen["organization_id"]
|
||||||
|
team_gen = await generate_team(session=session, org_id=org_id)
|
||||||
|
print("team_gen: ", json.dumps(team_gen, indent=4, default=str))
|
||||||
|
team_id = team_gen["team_id"]
|
||||||
|
key_gen = await generate_key(session=session, team_id=team_id)
|
||||||
|
print("key_gen: ", json.dumps(key_gen, indent=4, default=str))
|
||||||
|
key = key_gen["key"]
|
||||||
|
response = await chat_completion(session=session, key=key)
|
||||||
|
await asyncio.sleep(20)
|
||||||
|
spend_logs_response = await get_spend_logs(
|
||||||
|
session=session, request_id=response["id"]
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
"spend_logs_response: ",
|
||||||
|
json.dumps(spend_logs_response, indent=4, default=str),
|
||||||
|
)
|
||||||
|
spend_logs_response = spend_logs_response[0]
|
||||||
|
assert spend_logs_response["metadata"]["user_api_key_org_id"] == org_id
|
||||||
|
assert spend_logs_response["metadata"]["user_api_key_team_id"] == team_id
|
||||||
|
assert spend_logs_response["team_id"] == team_id
|
||||||
|
|
||||||
|
|
||||||
async def get_predict_spend_logs(session):
|
async def get_predict_spend_logs(session):
|
||||||
url = "http://0.0.0.0:4000/global/predict/spend/logs"
|
url = "http://0.0.0.0:4000/global/predict/spend/logs"
|
||||||
headers = {"Authorization": "Bearer sk-1234", "Content-Type": "application/json"}
|
headers = {"Authorization": "Bearer sk-1234", "Content-Type": "application/json"}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue