Skip to content

[Feature] UI - Logs: Use backend request_duration_ms and make Duration sortable - #22122

Merged
yuneng-jiang merged 2 commits into
mainfrom
litellm_ui_spend_logs_duration
Feb 26, 2026
Merged

[Feature] UI - Logs: Use backend request_duration_ms and make Duration sortable#22122
yuneng-jiang merged 2 commits into
mainfrom
litellm_ui_spend_logs_duration

Conversation

@yuneng-jiang

Copy link
Copy Markdown
Contributor

Summary

Problem

The spend logs Duration column was calculated client-side from endTime - startTime. This was imprecise and did not support server-side sorting.

Fix

  • Use the backend-provided request_duration_ms field directly instead of computing duration client-side
  • Add request_duration_ms to the sort field map, making the Duration column sortable via the existing sort dropdown pattern
  • When sorting by duration, the UI sends sortBy=request_duration_ms to the /spend/logs/ui endpoint

Testing

  • All 150 existing view_logs tests pass
  • Updated test fixtures to use request_duration_ms: 1000 instead of duration: 1

Type

🆕 New Feature
✅ Test

…n sortable

Use the backend-provided request_duration_ms field instead of computing
duration client-side from startTime/endTime. Add sort support for the
Duration column, which sends sortBy=request_duration_ms to the API.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Feb 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
litellm Ready Ready Preview, Comment Feb 25, 2026 8:29pm

Request Review

@yuneng-jiang

Copy link
Copy Markdown
Contributor Author

@greptile

@greptile-apps

greptile-apps Bot commented Feb 25, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR replaces the client-side computed duration field (derived from endTime - startTime) with the backend-provided request_duration_ms field across the spend logs UI. It also makes the Duration column sortable via server-side sorting, following the same SortableHeader pattern used by Time, Cost, and Tokens columns.

  • Type change: LogEntry.duration (seconds, number) → LogEntry.request_duration_ms (milliseconds, number | undefined) with ms-to-seconds conversion at display time
  • Sortable Duration column: Adds request_duration_ms to LOGS_SORT_FIELD_MAP and wraps the column header with SortableHeader, sending sortBy=request_duration_ms to the backend
  • Null-safe display: All display locations use != null checks with a "-" fallback, and LogDetailsDrawer retains a client-side fallback via ?? for the session endpoint which does not yet return request_duration_ms
  • Test fixtures updated: All three test files updated from duration: 1 to request_duration_ms: 1000

Confidence Score: 4/5

  • This PR is safe to merge — it's a straightforward UI field rename with proper null handling and backend support.
  • All changes are UI-only, replacing a client-computed field with a backend-provided one. The backend /spend/logs/ui endpoint already supports request_duration_ms as both a response field and a valid sort field. Null handling is correct throughout. The only minor gap is that the session endpoint doesn't return the field, but the fallback in LogDetailsDrawer handles it. Tests updated consistently. Score is 4 instead of 5 due to the session endpoint gap noted in the review.
  • No files require special attention. The LogDetailsDrawer.tsx fallback for session logs is noted as a style comment but is not a blocking issue.

Important Files Changed

Filename Overview
ui/litellm-dashboard/src/components/view_logs/columns.tsx Adds request_duration_ms to sort field map, updates LogEntry type from duration to request_duration_ms, and converts the Duration column to a sortable column with ms-to-seconds conversion. Clean implementation following existing sortable column patterns.
ui/litellm-dashboard/src/components/view_logs/index.tsx Replaces client-side duration computation with direct pass-through of request_duration_ms from backend. Updates RequestViewer display to convert ms to seconds with null-safe handling.
ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.tsx Updates TraceEventRow and session log mapping to use request_duration_ms with a client-side fallback via nullish coalescing for session endpoints that don't yet include the field.
ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailContent.tsx Updates MetricsSection to display duration from request_duration_ms with null-safe ms-to-seconds conversion and a dash fallback.
ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailContent.test.tsx Test fixture updated from duration: 1 to request_duration_ms: 1000 to match the new field name and millisecond units.
ui/litellm-dashboard/src/components/view_logs/RequestResponsePanel.test.tsx Test fixture updated from duration: 1 to request_duration_ms: 1000 to match the new field name and millisecond units.
ui/litellm-dashboard/src/components/view_logs/index.test.tsx Test fixture updated from duration: 1 to request_duration_ms: 1000 to match the new field name and millisecond units.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["/spend/logs/ui endpoint"] -->|"returns request_duration_ms<br/>(COALESCE from DB or computed)"| B["SpendLogsTable (index.tsx)"]
    B -->|"passes request_duration_ms<br/>directly to LogEntry"| C["columns.tsx<br/>Duration column cell"]
    C -->|"ms / 1000 → seconds display"| D["Table Row"]
    
    E["User clicks Sort by Duration"] -->|"sortBy=request_duration_ms"| A
    
    F["/spend/logs/session/ui endpoint"] -->|"does NOT return<br/>request_duration_ms"| G["LogDetailsDrawer.tsx"]
    G -->|"fallback: endTime - startTime"| H["TraceEventRow"]
    G -->|"enriched log"| I["LogDetailContent.tsx<br/>Metrics Section"]
    I -->|"ms / 1000 → seconds display"| J["Detail Drawer"]
Loading

Last reviewed commit: 743b8fd

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

7 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

.map((row) => ({
...row,
duration: (Date.parse(row.endTime) - Date.parse(row.startTime)) / 1000,
request_duration_ms: row.request_duration_ms ?? (Date.parse(row.endTime) - Date.parse(row.startTime)),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good fallback for session endpoint

The nullish coalescing fallback here is necessary and correct — the /spend/logs/session/ui backend endpoint does not currently include request_duration_ms in its SQL SELECT list (see spend_management_endpoints.py:3207-3215), so row.request_duration_ms will be undefined for session logs and this fallback will always kick in.

For full consistency, consider filing a follow-up to add COALESCE(request_duration_ms, ...) to the session endpoint's query as well, similar to what the main /spend/logs/ui endpoint does at line 1943.

@yuneng-jiang
yuneng-jiang merged commit 6ac3ed6 into main Feb 26, 2026
66 of 93 checks passed
@ishaan-berri
ishaan-berri deleted the litellm_ui_spend_logs_duration branch March 26, 2026 22:30
fzowl pushed a commit to fzowl/litellm that referenced this pull request Jun 24, 2026
…uration

[Feature] UI - Logs: Use backend request_duration_ms and make Duration sortable
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant