Attribute backend analytics events to the requesting client

What does this MR do and why?

GitLab Rails has not populated the client_type and client_name fields of the gitlab_standard Snowplow context. Chat events like execute_llm_method derived client identity from User-Agent regexes (IDE and glab only) or defaulted to web. Agent Platform events and background jobs had no client at all.

This MR makes Rails resolve and populate client identity consistently:

  • New class Gitlab::Tracking::ClientIdentity parses X-Gitlab-Client-Type and X-Gitlab-Client-Name headers, User-Agent, and defaults to api with no name.
  • Request middleware (Gitlab::Middleware::RequestContext) resolves identity per request and wraps it in Gitlab::ApplicationContext.
  • Labkit propagates context to Sidekiq jobs, so background workers inherit the triggering user's client.
  • Frontend (axios and Apollo) send the client type header on same-origin requests; for browser clients Rails derives client_name from the User-Agent browser family (chrome, firefox, safari, edge, opera, electron).
  • Tracking classes emit client_type and client_name into the standard context and AI usage event extras.
  • Documentation: new page doc/development/internal_analytics/internal_event_instrumentation/client_identity.md.
  • MCP and Slack integrations explicitly set client_type: integration.

Client type values are browser, ide, cli, mobile, integration, system, and api. Unknown header values are dropped (client-controlled headers are not stored as free text).

Verification: 130 RSpec examples in tracking/context/chat, 82 in resolver/middleware/Slack/MCP specs, all green. ee/spec/lib/gitlab/tracking/ai_tracking_spec.rb could not run locally because it needs a ClickHouse configuration. 27 Jest examples green. RuboCop and linters clean.

References

Follows !256654 (merged), which added the request User-Agent to backend events.

Stacked follow-up: !257626 (merged) makes Workhorse forward the resolved identity on the agent actions it runs for websocket clients.

Client side: https://gitlab.com/mvanremmerden/gitlab-mobile/-/merge_requests/13 sends the headers from the mobile app.

How to set up and validate locally

  1. Send a request with curl -H 'X-Gitlab-Client-Type: mobile' -H 'X-Gitlab-Client-Name: gitlab-mobile-ios' http://gdk.test:3000/api/v4/user with a token and check log/api_json.log for meta.client_type.
  2. Run Gitlab::Tracking::StandardContext.new.to_h.slice(:client_type, :client_name) in a Rails console (expect system/gitlab-rails).
  3. With Snowplow Micro running, start a Duo Chat from the browser and inspect the gitlab_standard context of the execute_llm_method event for client_type: browser.

Reviewer notes

  • Needs an ~"analytics instrumentation" review; the label is applied.
  • Data team should be told that the client property gains new values api and mobile, and that unknown User-Agents move from web to api.
  • Labelled pipeline:run-as-if-foss because CE and EE both change.
  • No database migration.
  • No feature flag, because the middleware only does string matching and the resolver is covered by a table-driven spec.

Follow-up

  • #630922 tracks the client names and types the IDE plugins, the Duo CLI, and the language server send, the Web IDE naming collision, and who owns the allowlist.

MR acceptance checklist

Evaluated against the MR acceptance checklist.

🤖 Generated with Claude Code

Edited by Marcel van Remmerden

Merge request reports

Loading
Loading