ref(api): Log client_kind on the API access log - #123915
Draft
DominikB2014 wants to merge 2 commits into
Draft
Conversation
The client_kind attributes ride on spans today, and spans do not reach the analytics warehouse: it promotes a fixed, hand-curated allow-list of columns off `spans_gcs` and drops every other attribute, so nothing set through `sentry_sdk.set_attribute` is queryable downstream. The `api.access` log line is warehouse-visible -- it lands in `internal-sentry.getsentry_api_access_logs.stdout` as `jsonPayload` and is rolled up into `api_logs_us.api_log_stdout`, the table behind the API Trends dashboard, which today separates callers by regex-matching `sentry-mcp` in the user agent. Stash the kind and host `set_client_kind_attributes` already derives onto the underlying Django request -- the DRF wrapper is gone by the time the middleware runs -- and log them. The span is untouched: developers keep reading attribution off a trace, this only adds the path that also reaches analysis.
Set the attributes the way `convert_args` sets `organization`, with one comment instead of a docstring. Registers both on the mypy plugin's `HttpRequest`, which is what lets the `organization` assignment type-check today.
skaasten
reviewed
Sep 9, 2026
| path=request.path, | ||
| caller_ip=request.META.get("REMOTE_ADDR"), | ||
| user_agent=request.META.get("HTTP_USER_AGENT"), | ||
| client_kind=client_kind.value if client_kind is not None else None, |
Contributor
There was a problem hiding this comment.
~ can this be simplified to client_kind=getattr(request, "client_kind", None), like we do in the tests?
skaasten
approved these changes
Sep 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
client_kindattribution currently rides on spans only, and span attributes never reach the analytics warehouse. The warehouse promotes a fixed, hand-curated allow-list of columns offspans_gcsand drops every other attribute — there is no tags map, JSON blob, or key-value side table. Soclient_kind_test,client_host_testanduser_agent.originalare queryable in a trace and nowhere else.The
api.accesslog line is warehouse-visible: it lands ininternal-sentry.getsentry_api_access_logs.stdoutasjsonPayload, and is rolled up daily intoapi_logs_us.api_log_stdout— the table behind the API Trends dashboard, which today tells callers apart by regex-matchingsentry-mcpin the user agent.This adds the log path. The span is untouched — developers keep reading attribution off a trace; this is additive.
Changes
set_client_kind_attributesstashes the kind and host it already derives onto the underlying Django request. The DRF wrapper is gone by the timeaccess_logmiddleware runs, which is the same reasonconvert_argsassignsrequest._request.organization. Re-deriving in the middleware is not an option: the organization whose opt-in gates this is resolved during dispatch and out of scope by then.access_loglogsclient_kindandclient_host, absent for orgs that have not opted in.Known gaps, deliberate
internal_servicecannot appear here._create_api_access_logreturns early ontoken_type == "system", so this field describes the mix of external callers by construction._testsuffix to stay clear of a future realclient_kindspan attribute. The log is a fresh namespace with no such collision, so these are unsuffixed — the downstream column will not need renaming when the POC suffix goes. Happy to align them if reviewers prefer uniformity.organization_idis still oftenNonein the access log (pre-existing TODO in this file). Attribution is usable without it, but org-level breakdowns will be partial until that is fixed.Follow-up, not in this PR
The warehouse rollup drops columns it is not told about. A one-line change in
getsentry/etl(api_analysis_stdout.sqlandapi_analysis_stdout_mcp.sql) is needed to carryclient_kindthrough theSELECT/GROUP BY. The grain is already(api_endpoint, user_agent, organization_id, dt), so adding a nine-value column barely moves row counts. Once that lands, API Trends can drop the user-agent regex for a derived field.Note also that
api_logs_usis US-region only (there is acust_regioncolumn); an EU equivalent needs checking before quoting totals.