Repository navigation
feat(cli): Complete dataset fields and aggregates in shell completion - #1782
Merged
Merged
Conversation
`explore --field`/`--sort`, `dashboard widget add|edit --group-by`/ `--query`/`--sort`, and `alert metrics create|edit --aggregate` now complete the fields of the dataset `--dataset` names, and its aggregate functions. Attribute keys are cached per org and dataset (`span-attribute`, `log-attribute`, `metric-attribute`) from the trace-items attributes endpoint, matched on its `dataset` query parameter. Errors use the cached issue tag keys; replays use the fixed fields the CLI renders. Aggregate functions come from `aggregateFunctionsOf`, now shared with `validateAggregateNames`. The completer reads `--dataset` (by name, alias, or `--dataset=`) from the words typed before it; commands without a default, like `dashboard widget edit`, complete every dataset. Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
…d-completion Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
BYK
approved these changes
Nov 1, 2026
Contributor
Author
|
This merged before the follow-ups to your answers landed, so they're in #1785:
|
BYK
added a commit
that referenced
this pull request
Nov 1, 2026
Follow-up to #1782, which was merged before these changes landed. It implements the answers to that PR's design questions. ## Alert `--aggregate` completes only what metric alerts accept `alert metrics create|edit --aggregate` no longer reuses the widget function lists. Each `--dataset` gets the aggregates the Sentry backend accepts for it: | `--dataset` | Completes | | --- | --- | | `spans` (and `transaction(s)`) | `EAP_FUNCTIONS`: `count`, `count_unique`, `avg`, `p50`–`p99`, `p100`, `max`, `min`, `sum`, `epm`, `eps`, `failure_count`, `failure_rate`, `apdex`, `user_misery`, called on cached span attribute keys | | `logs` | the `EAP_FUNCTIONS` that logs define: no formulas and no `p100`, called on cached log attribute keys | | `errors` / `events` | `count()`, `count_unique(user)`, `count_unique(release)`, `count_unique(dist)` | | `metrics` / `sessions` (crash rate) | `percentage(sessions_crashed,sessions)`, `percentage(users_crashed,users)` | A new `DatasetFields.aggregates` holds whole aggregates that aren't a function of one field. Sources (getsentry/sentry master @ `063a6cb2`): - `src/sentry/snuba/snuba_query_validator.py` `_validate_aggregate` (L253) calls `check_aggregate_column_support` and `translate_aggregate_field`. For EAP it skips the SnQL query check (L361). - `src/sentry/incidents/logic.py`: - `EAP_FUNCTIONS` (L140). For these functions, `get_column_from_aggregate` (L179) skips column validation on EAP datasets. - `SUPPORTED_COLUMNS` and `TRANSLATABLE_COLUMNS` (L118, L124). `check_aggregate_column_support` (L214) checks columns against these lists, so errors can't take arbitrary tag keys. - `src/sentry/snuba/entity_subscription.py`: - `PerformanceSpansEAPRpcEntitySubscription.build_rpc_request` resolves the aggregate with `Spans` or `OurLogs` definitions, depending on the event type. - `CRASH_RATE_ALERT_AGGREGATE_RE` (L59) and `determine_crash_rate_alert_entity` restrict crash rate to the percentages above. - `src/sentry/search/eap/spans/aggregates.py` and `formulas.py` define every `EAP_FUNCTIONS` entry. `src/sentry/search/eap/ourlogs/aggregates.py` defines no `p100`, and `ourlogs/definitions.py` sets `formulas={}`. - The UI agrees: `static/app/views/detectors/datasetConfig/errors.tsx` offers `count` and `count_unique(user)`, and `releases.tsx` maps `crash_free_rate(session|user)` to the two percentages. **`@sentry/api` has no list to use.** 0.428.0 types detector `data_sources` as `Array<unknown>`. The only aggregates it mentions are in prose examples from `workflow_engine/endpoints/validators/api_docs_help_text.py`, and those are out of date: they list `percentile(measurements.lcp,x)`, but EAP spans don't define `percentile`. Exposing the aggregates upstream would be worthwhile. The natural form is an `aggregate` schema on the `SnubaQueryValidator` data source, with an enum or pattern per `dataset`/`eventTypes`. Clients could then stop copying `EAP_FUNCTIONS` and the crash-rate regex. Caveat: the errors list is the practical set, not an exhaustive allowlist. Errors accept any Discover function whose column is empty or in the column allowlist, provided the test query runs. Completion offers what the UI offers, plus the other allowed columns. ## Fields match one `.` segment at a time `fuzzyMatchSegments` matches the Nth typed segment against the candidate's Nth segment, using `fuzzyMatch` search mode. A candidate must have a segment for each typed one, and may have more after them. So: - `avg(span.d` → `avg(span.duration)`, never `avg(span.op)` - `avg(span.duraton` → `avg(span.duration)` (typo within the segment) - `span` → every `span.*` This applies to every field completion (`explore --field/--sort`, widget `--group-by/--query/--sort`, alert `--aggregate`), both bare and inside `fn(` or `fn:`. Field completion now matches values only. It no longer matches attribute type labels such as `number`. ## Background attribute-key fetch for explore: not added `explore` doesn't get attribute keys from any call it already makes. `/events/` meta covers only the requested fields, and the error path (`toExploreFieldError`) fetches nothing. A separate fetch costs too much for what the cache would keep. I measured `GET /organizations/sentry/trace-items/attributes/` on sentry.io (3 runs each, curl, gzip): | dataset | keys | gzip | raw JSON | latency | | --- | --- | --- | --- | --- | | spans | 6,007 | ~72 KB | ~1.0 MB | 0.40–0.48 s | | logs | 6,114 | ~51 KB | ~0.97 MB | 0.45–0.55 s | | tracemetrics | 963 | ~10 KB | ~115 KB | 0.29–0.70 s | | spans, `per_page=100` | ≤100 per type | ~5 KB | — | 0.30–2.2 s | The cache keeps 500 keys per kind per org. The server returns keys in name order, so the first rows are keys like `0`, `1`, `AGP_VERSION`, and the kept 500 would miss `span.*`. A small page has the same problem. The fetch also adds a request that the process must either wait for before exiting or abandon. `sentry attribute list` still seeds the cache. The 500 cap is unchanged. ## Checks - `pnpm exec tsc --noEmit` (packages/cli): pass - `pnpm run lint`: pass - `vitest run` on `test/lib/complete.test.ts`, `test/lib/fuzzy.test.ts`, `test/lib/db/completion-cache.test.ts`, `test/lib/completion-coverage.test.ts`, `test/lib/api/completion-seed.test.ts`, `test/lib/introspect.test.ts`, `test/commands/alert`, `test/commands/explore.test.ts`, `test/commands/dashboard`: 28 files, 659 tests, all pass - The full `test/lib` suite didn't finish within the sandbox's 15-minute limit, so it wasn't run to completion. <!-- junior-request-attribution:start --> via @BYK. <!-- junior-request-attribution:end --> <!-- junior-session-footer:start --> <!-- junior-conversation-id:agent%3Ad44a6d899e425504b37476161fdb6ebe --> -- [View Session in Sentry](https://sentry.sentry.io/explore/conversations/agent%3Ad44a6d899e425504b37476161fdb6ebe/?project=4510944073809921) <!-- junior-session-footer:end --> Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com> Co-authored-by: BYK <126780+BYK@users.noreply.github.com>
sentry-junior Bot
added a commit
that referenced
this pull request
Nov 2, 2026
Resolve the widget/add.ts import conflict by keeping both DashboardWidgetChangeOutputSchema (output schema) and DEFAULT_WIDGET_TYPE (dataset-field completers from #1782). Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
This branch was successfully deployed
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.
This follows up #1759. The field and aggregate flags that were still
textnow complete the fields of the dataset that--datasetnames, plus its aggregate functions.Now completing
explore --field/--sort: fields, thenfn(). Once a function name is typed in full, it also completesfn(field)for every field, sop95<TAB>insertsp95(and listsp95(span.duration)and the rest.p95(span.d<TAB>finishes the call.alert metrics create|edit --aggregate: the same calls, without bare fields.dashboard widget add|edit --query/--sort: the shorthand form,fnand thenfn:field. These used to complete every dataset's function names. Now they complete only the names of the widget's dataset, with the aliases (spm,tpm, …) that resolve to them.dashboard widget add|edit --group-by: fields.Where the values come from
span-attribute,log-attribute, andmetric-attribute. They are seeded fromGET /organizations/{org}/trace-items/attributes/. The seed table can now also match on query parameters, so thedatasetparameter decides which kind a response fills. The stored value is the attribute'skey, because the API queries bykey(tags[foo,number]for custom non-string attributes). I checked this againstas_attribute_keyinsrc/sentry/api/endpoints/organization_trace_item_attributes.pyin getsentry/sentry. The description is the attribute type, with the display name in front of it when the name differs from the key.tag-key).--fielduseslistSupportedReplayFields()and--sortusesREPLAY_SORT_FIELDS.aggregateFunctionsOfintypes/dashboard.ts.validateAggregateNamesnow uses the same function, and it replacesAGGREGATE_FUNCTION_NAMES.How it works
DatasetCompletiontag on the parser describes what completes for each dataset, the command's--datasetaliases, and its default dataset.--name; aliases are mapped back to it at completion time.flagValuesfrom the words typed before the cursor, so it sees--dataset spans,-d spans, and--dataset=spans.--dataset, a command falls back to its default: errors forexplore, spans forwidget add.widget editkeeps the existing widget's dataset, andalerthas no default, so those two complete every dataset.Still completing nothing
-field: a word that starts with-completes flag names.sum(value,metric,type,unit)): they name a metric rather than a field. Only trace metric fields complete.--dataset metrics|sessions) andissue/preprod-app-sizewidgets.sentry attribute listhas run for the org, since that command is the only caller of the attributes endpoint. Errors complete nothing until some issue details have been fetched.Open questions
--aggregate, so it reuses the widget function lists: errors functions forerrors/events, spans functions forspans/logs. Should alerts get their own, narrower list?explore(or a light background call) also seed attribute keys, so completion does not depend on runningattribute listfirst?via @BYK.
--
View Session in Sentry