(UI) - View Logs Page - Refinement (#8087)

* working refetch interval

* ui show provider logo in SpendLogs Table

* fix padding

* improve time range filter

* ui fix diff minutes

* fix refresh button placement
This commit is contained in:
Ishaan Jaff 2025-01-29 08:46:20 -08:00 • committed by GitHub
parent 46b44f3a7f
commit 892581ffc3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 134 additions and 59 deletions

View file

@ -5,15 +5,9 @@ model_list:
api_key: fake-key
api_base: https://exampleopenaiendpoint-production.up.railway.app/
litellm_settings:
callbacks: ["prometheus"]
prometheus_initialize_budget_metrics: true
guardrails:
- guardrail_name: "bedrock-pre-guard"
litellm_params:
guardrail: bedrock # supported values: "aporia", "bedrock", "lakera"
mode: "during_call"
guardrailIdentifier: gf3sc1mzinjw
guardrailVersion: "DRAFT"
callbacks: ["datadog"]
general_settings:
store_prompts_in_spend_logs: true

View file

@ -1740,6 +1740,8 @@ async def ui_view_spend_logs( # noqa: PLR0915
# Calculate total pages
total_pages = (total_records + page_size - 1) // page_size
verbose_proxy_logger.debug("data= %s", json.dumps(data, indent=4, default=str))
return {
"data": data,
"total": total_records,

View file

@ -3,6 +3,7 @@ import { getCountryFromIP } from "./ip_lookup";
import moment from "moment";
import React from "react";
import { CountryCell } from "./country_cell";
import { getProviderLogoAndName } from "../provider_info_helpers";
export type LogEntry = {
request_id: string;
@ -18,6 +19,7 @@ export type LogEntry = {
startTime: string;
endTime: string;
user?: string;
custom_llm_provider?: string;
metadata?: Record<string, any>;
cache_hit: string;
cache_key?: string;
@ -106,7 +108,26 @@ export const columns: ColumnDef<LogEntry>[] = [
{
header: "Model",
accessorKey: "model",
cell: (info: any) => <span>{String(info.getValue() || "")}</span>,
cell: (info: any) => {
const row = info.row.original;
const provider = row.custom_llm_provider;
return (
<div className="flex items-center space-x-2">
{provider && (
<img
src={getProviderLogoAndName(provider).logo}
alt=""
className="w-4 h-4"
onError={(e) => {
const target = e.target as HTMLImageElement;
target.style.display = 'none';
}}
/>
)}
<span>{String(info.getValue() || "")}</span>
</div>
);
},
},
{
header: "Tokens",

View file

@ -106,13 +106,15 @@ export default function SpendLogsTable({
}
const formattedStartTime = moment(startTime).format("YYYY-MM-DD HH:mm:ss");
const formattedEndTime = moment(endTime).format("YYYY-MM-DD HH:mm:ss");
const formattedEndTime = isCustomDate
? moment(endTime).format("YYYY-MM-DD HH:mm:ss")
: moment().format("YYYY-MM-DD HH:mm:ss");
return await uiSpendLogsCall(
accessToken,
selectedKeyHash || undefined,
selectedTeamId || undefined,
undefined, // This parameter might be setting a default min_spend
undefined,
formattedStartTime,
formattedEndTime,
currentPage,
@ -120,6 +122,8 @@ export default function SpendLogsTable({
);
},
enabled: !!accessToken && !!token && !!userRole && !!userID,
refetchInterval: 5000,
refetchIntervalInBackground: true,
});
if (!accessToken || !token || !userRole || !userID) {
@ -141,10 +145,37 @@ export default function SpendLogsTable({
return matchesSearch;
}) || [];
// Add this function to handle manual refresh
const handleRefresh = () => {
logs.refetch();
};
// Add this function to format the time range display
const getTimeRangeDisplay = () => {
if (isCustomDate) {
return `${moment(startTime).format('MMM D, h:mm A')} - ${moment(endTime).format('MMM D, h:mm A')}`;
}
const now = moment();
const start = moment(startTime);
const diffMinutes = now.diff(start, 'minutes');
if (diffMinutes <= 15) return 'Last 15 Minutes';
if (diffMinutes <= 60) return 'Last Hour';
const diffHours = now.diff(start, 'hours');
if (diffHours <= 4) return 'Last 4 Hours';
if (diffHours <= 24) return 'Last 24 Hours';
if (diffHours <= 168) return 'Last 7 Days';
return `${start.format('MMM D')} - ${now.format('MMM D')}`;
};
return (
<div className="w-full">
<h1 className="text-xl font-semibold mb-4">Traces</h1>
<div className="w-full p-6">
<div className="flex items-center justify-between mb-4">
<h1 className="text-xl font-semibold">Request Logs</h1>
</div>
<div className="bg-white rounded-lg shadow overflow-hidden">
<div className="border-b px-6 py-4">
<div className="flex flex-col md:flex-row items-start md:items-center justify-between space-y-4 md:space-y-0">
@ -310,13 +341,78 @@ export default function SpendLogsTable({
)}
</div>
<div className="relative" ref={quickSelectRef}>
<div className="flex items-center gap-2">
<div className="relative" ref={quickSelectRef}>
<button
onClick={() => setQuickSelectOpen(!quickSelectOpen)}
className="px-3 py-2 text-sm border rounded-md hover:bg-gray-50 flex items-center gap-2"
>
<svg
className="w-4 h-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
/>
</svg>
{getTimeRangeDisplay()}
</button>
{quickSelectOpen && (
<div className="absolute right-0 mt-2 w-64 bg-white rounded-lg shadow-lg border p-2 z-50">
<div className="space-y-1">
{[
{ label: "Last 15 Minutes", value: 15, unit: "minutes" },
{ label: "Last Hour", value: 1, unit: "hours" },
{ label: "Last 4 Hours", value: 4, unit: "hours" },
{ label: "Last 24 Hours", value: 24, unit: "hours" },
{ label: "Last 7 Days", value: 7, unit: "days" },
].map((option) => (
<button
key={option.label}
className={`w-full px-3 py-2 text-left text-sm hover:bg-gray-50 rounded-md ${
getTimeRangeDisplay() === option.label ? 'bg-blue-50 text-blue-600' : ''
}`}
onClick={() => {
setEndTime(moment().format("YYYY-MM-DDTHH:mm"));
setStartTime(
moment()
.subtract(option.value, option.unit as any)
.format("YYYY-MM-DDTHH:mm")
);
setQuickSelectOpen(false);
setIsCustomDate(false);
}}
>
{option.label}
</button>
))}
<div className="border-t my-2" />
<button
className={`w-full px-3 py-2 text-left text-sm hover:bg-gray-50 rounded-md ${
isCustomDate ? 'bg-blue-50 text-blue-600' : ''
}`}
onClick={() => setIsCustomDate(!isCustomDate)}
>
Custom Range
</button>
</div>
</div>
)}
</div>
<button
onClick={() => setQuickSelectOpen(!quickSelectOpen)}
onClick={handleRefresh}
className="px-3 py-2 text-sm border rounded-md hover:bg-gray-50 flex items-center gap-2"
title="Refresh data"
>
<svg
className="w-4 h-4"
className={`w-4 h-4 ${logs.isFetching ? 'animate-spin' : ''}`}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
@ -325,49 +421,11 @@ export default function SpendLogsTable({
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
/>
</svg>
Time Range
<span>Refresh</span>
</button>
{quickSelectOpen && (
<div className="absolute left-0 mt-2 w-64 bg-white rounded-lg shadow-lg border p-2 z-50">
<div className="space-y-1">
{[
{ label: "Last 15 Minutes", value: 15, unit: "minutes" },
{ label: "Last Hour", value: 1, unit: "hours" },
{ label: "Last 4 Hours", value: 4, unit: "hours" },
{ label: "Last 24 Hours", value: 24, unit: "hours" },
{ label: "Last 7 Days", value: 7, unit: "days" },
].map((option) => (
<button
key={option.label}
className="w-full px-3 py-2 text-left text-sm hover:bg-gray-50 rounded-md"
onClick={() => {
setEndTime(moment().format("YYYY-MM-DDTHH:mm"));
setStartTime(
moment()
.subtract(option.value, option.unit as any)
.format("YYYY-MM-DDTHH:mm")
);
setQuickSelectOpen(false);
setIsCustomDate(false);
}}
>
{option.label}
</button>
))}
<div className="border-t my-2" />
<button
className="w-full px-3 py-2 text-left text-sm hover:bg-gray-50 rounded-md"
onClick={() => setIsCustomDate(!isCustomDate)}
>
Custom Range
</button>
</div>
</div>
)}
</div>
{isCustomDate && (