Skip to content

adds user-agent tracking for llm and mcp logs - #4083

Merged
akshaydeo merged 1 commit into
v2.0.0from
06-05-adds_user-agent_tracking_for_llm_and_mcp_logs
Jun 17, 2026
Merged

adds user-agent tracking for llm and mcp logs#4083
akshaydeo merged 1 commit into
v2.0.0from
06-05-adds_user-agent_tracking_for_llm_and_mcp_logs

Conversation

@akshaydeo

@akshaydeo akshaydeo commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

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-Agent header is now captured verbatim on every log entry, and a backend-detected app label (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

  • User-Agent capture: ExtractAndSetUserAgentFromHeaders now stores the raw UA unconditionally (previously only stored it when it matched a known integration). A new userAgentFromContext helper in the logging plugin reads from the request-headers map first, falling back to the context key.
  • App detection: DetectAppFromUserAgent walks a priority-ordered UserAgentAppMatchers slice 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 like claude-cli/2.1.168 (external, cli).
  • Expanded app registry: Added Claude Desktop, Windsurf, Kilo Code, Roo Code, Cline, and additional identifier aliases for Codex, Gemini CLI, and Qwen Code.
  • Schema migrations: Three new migration steps add user_agent and app columns to logs and mcp_tool_logs, and register a marker migration that defers mv_logs_hourly rebuild to startup (via ensureMatViews/repairMatViewShapes) to avoid lock contention on large tables.
  • Materialized views: mv_logs_hourly now groups by user_agent and app; two new filter matviews (mv_filter_apps, mv_filter_user_agents) back the filter dropdowns. applyMatViewFiltersOnly and applyFilters both respect the new fields.
  • LogStore interface: Added GetDistinctUserAgents, GetDistinctApps, GetAvailableMCPUserAgents, and GetAvailableMCPApps to the interface, with matview-backed fast paths and recency-scoped raw-table fallbacks.
  • HTTP handlers: getLogs, getLogsStats, parseHistogramFilters, parseMCPFiltersAndPagination, and parseMCPFilters all parse user_agents and apps query params. getAvailableFilterData and getMCPLogsFilterData serve the new apps and user_agents dimensions.
  • UI – App column: Both the logs table and MCP logs table show an "App" column with icon + name resolved via mapAppToClientApp (for backend-populated app field) or mapUserAgentToApp (fallback for older rows without the column).
  • UI – App filter: AppFilter components added to LogsFilterSidebar and MCPFilterSidebar, fetching distinct app names from the new filter-data endpoints.
  • UI – App Rankings tab: A new "App Rankings" dashboard tab uses the user_agent dimension with a client-side aggregateRankingsByApp transform that rolls per-version UA rows up into one row per app, with request/token/cost-weighted trend averaging.
  • UI – types and API params: LogFilters, MCPToolLogFilters, LogEntry, MCPToolLogEntry, RankingDimension, and DashboardData updated; buildFilterParams and buildMCPFilterParams serialize the new fields.

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (React)
  • Docs

How to test

# Core/Transports
go test ./core/schemas/... ./plugins/logging/... ./framework/logstore/...

# UI
cd ui
pnpm i
pnpm test
pnpm build
  1. Send a request through the proxy with a User-Agent: claude-cli/2.1.168 (external, cli) header.
  2. Open the logs table — the "App" column should show "Claude Code" with its icon.
  3. Open the filter sidebar — the "App" filter should list "Claude Code" as an available option.
  4. Navigate to the Dashboard → "App Rankings" tab and confirm usage is broken down by app.
  5. Export to CSV and verify an app-rankings sheet is present.

Breaking changes

  • Yes
  • No

The mv_logs_hourly materialized 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. The LogStore interface has four new required methods — any custom implementations must be updated.

Related issues

Security considerations

The raw User-Agent string 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 at varchar(512) to bound storage.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

Loading
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.

2 participants