adds user-agent tracking for llm and mcp logs - #4083
Merged
akshaydeo merged 1 commit intoJun 17, 2026
Conversation
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds end-to-end User-Agent and client app tracking across logs, MCP tool logs, and the dashboard. The raw HTTP
User-Agentheader is now captured verbatim on every log entry, and a backend-detectedapplabel (e.g. "Claude Code", "Codex", "Cursor") is derived from it at write time. Both fields are exposed as filterable dimensions, histogram axes, and ranking dimensions, with a new "App Rankings" dashboard tab.Changes
ExtractAndSetUserAgentFromHeadersnow stores the raw UA unconditionally (previously only stored it when it matched a known integration). A newuserAgentFromContexthelper in the logging plugin reads from the request-headers map first, falling back to the context key.DetectAppFromUserAgentwalks a priority-orderedUserAgentAppMatchersslice and returns a human-readable app name ("Claude Code", "Gemini CLI", "Other", etc.). Matching uses prefix-or-contains on the lowercased UA to handle versioned strings likeclaude-cli/2.1.168 (external, cli).user_agentandappcolumns tologsandmcp_tool_logs, and register a marker migration that defersmv_logs_hourlyrebuild to startup (viaensureMatViews/repairMatViewShapes) to avoid lock contention on large tables.mv_logs_hourlynow groups byuser_agentandapp; two new filter matviews (mv_filter_apps,mv_filter_user_agents) back the filter dropdowns.applyMatViewFiltersOnlyandapplyFiltersboth respect the new fields.GetDistinctUserAgents,GetDistinctApps,GetAvailableMCPUserAgents, andGetAvailableMCPAppsto the interface, with matview-backed fast paths and recency-scoped raw-table fallbacks.getLogs,getLogsStats,parseHistogramFilters,parseMCPFiltersAndPagination, andparseMCPFiltersall parseuser_agentsandappsquery params.getAvailableFilterDataandgetMCPLogsFilterDataserve the newappsanduser_agentsdimensions.mapAppToClientApp(for backend-populatedappfield) ormapUserAgentToApp(fallback for older rows without the column).AppFiltercomponents added toLogsFilterSidebarandMCPFilterSidebar, fetching distinct app names from the new filter-data endpoints.user_agentdimension with a client-sideaggregateRankingsByApptransform that rolls per-version UA rows up into one row per app, with request/token/cost-weighted trend averaging.LogFilters,MCPToolLogFilters,LogEntry,MCPToolLogEntry,RankingDimension, andDashboardDataupdated;buildFilterParamsandbuildMCPFilterParamsserialize the new fields.Type of change
Affected areas
How to test
User-Agent: claude-cli/2.1.168 (external, cli)header.app-rankingssheet is present.Breaking changes
The
mv_logs_hourlymaterialized view gains two new grouping columns (user_agent,app). On first startup after deploy the view will be dropped and recreated, which may take time on large tables. TheLogStoreinterface has four new required methods — any custom implementations must be updated.Related issues
Security considerations
The raw
User-Agentstring is stored verbatim in the database and surfaced in the UI. It is treated as untrusted display data only; no execution or privileged interpretation occurs. The field is capped atvarchar(512)to bound storage.Checklist
docs/contributing/README.mdand followed the guidelines