Spaces:
Sleeping
Sleeping
""" | |
Helper functions to query prometheus API | |
""" | |
import time | |
from datetime import datetime, timedelta | |
from typing import Optional | |
from litellm import get_secret | |
from litellm._logging import verbose_logger | |
from litellm.llms.custom_httpx.http_handler import ( | |
get_async_httpx_client, | |
httpxSpecialProvider, | |
) | |
PROMETHEUS_URL: Optional[str] = get_secret("PROMETHEUS_URL") # type: ignore | |
PROMETHEUS_SELECTED_INSTANCE: Optional[str] = get_secret("PROMETHEUS_SELECTED_INSTANCE") # type: ignore | |
async_http_handler = get_async_httpx_client( | |
llm_provider=httpxSpecialProvider.LoggingCallback | |
) | |
async def get_metric_from_prometheus( | |
metric_name: str, | |
): | |
# Get the start of the current day in Unix timestamp | |
if PROMETHEUS_URL is None: | |
raise ValueError( | |
"PROMETHEUS_URL not set please set 'PROMETHEUS_URL=<>' in .env" | |
) | |
query = f"{metric_name}[24h]" | |
now = int(time.time()) | |
response = await async_http_handler.get( | |
f"{PROMETHEUS_URL}/api/v1/query", params={"query": query, "time": now} | |
) # End of the day | |
_json_response = response.json() | |
verbose_logger.debug("json response from prometheus /query api %s", _json_response) | |
results = response.json()["data"]["result"] | |
return results | |
async def get_fallback_metric_from_prometheus(): | |
""" | |
Gets fallback metrics from prometheus for the last 24 hours | |
""" | |
response_message = "" | |
relevant_metrics = [ | |
"litellm_deployment_successful_fallbacks_total", | |
"litellm_deployment_failed_fallbacks_total", | |
] | |
for metric in relevant_metrics: | |
response_json = await get_metric_from_prometheus( | |
metric_name=metric, | |
) | |
if response_json: | |
verbose_logger.debug("response json %s", response_json) | |
for result in response_json: | |
verbose_logger.debug("result= %s", result) | |
metric = result["metric"] | |
metric_values = result["values"] | |
most_recent_value = metric_values[0] | |
if PROMETHEUS_SELECTED_INSTANCE is not None: | |
if metric.get("instance") != PROMETHEUS_SELECTED_INSTANCE: | |
continue | |
value = int(float(most_recent_value[1])) # Convert value to integer | |
primary_model = metric.get("primary_model", "Unknown") | |
fallback_model = metric.get("fallback_model", "Unknown") | |
response_message += f"`{value} successful fallback requests` with primary model=`{primary_model}` -> fallback model=`{fallback_model}`" | |
response_message += "\n" | |
verbose_logger.debug("response message %s", response_message) | |
return response_message | |
def is_prometheus_connected() -> bool: | |
if PROMETHEUS_URL is not None: | |
return True | |
return False | |
async def get_daily_spend_from_prometheus(api_key: Optional[str]): | |
""" | |
Expected Response Format: | |
[ | |
{ | |
"date": "2024-08-18T00:00:00+00:00", | |
"spend": 1.001818099998933 | |
}, | |
...] | |
""" | |
if PROMETHEUS_URL is None: | |
raise ValueError( | |
"PROMETHEUS_URL not set please set 'PROMETHEUS_URL=<>' in .env" | |
) | |
# Calculate the start and end dates for the last 30 days | |
end_date = datetime.utcnow() | |
start_date = end_date - timedelta(days=30) | |
# Format dates as ISO 8601 strings with UTC offset | |
start_str = start_date.isoformat() + "+00:00" | |
end_str = end_date.isoformat() + "+00:00" | |
url = f"{PROMETHEUS_URL}/api/v1/query_range" | |
if api_key is None: | |
query = "sum(delta(litellm_spend_metric_total[1d]))" | |
else: | |
query = ( | |
f'sum(delta(litellm_spend_metric_total{{hashed_api_key="{api_key}"}}[1d]))' | |
) | |
params = { | |
"query": query, | |
"start": start_str, | |
"end": end_str, | |
"step": "86400", # Step size of 1 day in seconds | |
} | |
response = await async_http_handler.get(url, params=params) | |
_json_response = response.json() | |
verbose_logger.debug("json response from prometheus /query api %s", _json_response) | |
results = response.json()["data"]["result"] | |
formatted_results = [] | |
for result in results: | |
metric_data = result["values"] | |
for timestamp, value in metric_data: | |
# Convert timestamp to ISO 8601 string with UTC offset | |
date = datetime.fromtimestamp(float(timestamp)).isoformat() + "+00:00" | |
spend = float(value) | |
formatted_results.append({"date": date, "spend": spend}) | |
return formatted_results | |