Skip to content

feat(cli): Narrow alert aggregates and match fields by segment - #1785

Merged
BYK merged 1 commit into
mainfrom
feat/cli-alert-aggregate-completion
Nov 1, 2026
Merged

BYK merged 1 commit into
mainfrom
feat/cli-alert-aggregate-completion

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

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. Tracked in getsentry/sentry#129450.

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.

via @BYK.

--

View Session in Sentry

`alert metrics create|edit --aggregate` now completes only what metric
alerts accept on the `--dataset` given, from getsentry/sentry:
`EAP_FUNCTIONS` for spans, the subset logs define (no formulas, no
`p100`) for logs, `count()` and `count_unique(user|release|dist)` for
errors, and the two crash-free percentages for `metrics`/`sessions`.
`DatasetFields.aggregates` carries whole aggregates that are not a
function of one field.

Fields now match one `.` segment at a time (`fuzzyMatchSegments`): the
Nth typed segment is fuzzy-matched against the candidate's Nth, so
`span.d` finds `span.duration` but never `span.op`, while a typo within
a segment (`span.duraton`) still matches.

Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
@vercel

vercel Bot commented Nov 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
sentry-local Skipped Skipped Nov 1, 2026 5:05pm UTC

Request Review

@BYK BYK left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sentry/api has no list to use. 0.428.0 types detector data_sources as Array. 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.

Let's file an issue to make this available in @sentry/api. You'll need to figure out whether this should be from getsentry/sentry repo or getsentry/sentry-api-schema repo.

Background attribute-key fetch for explore: not added

How about we do this in auth, and/or upgrade as part of an "initialization" to get a cache in place? Too expensive and invasive or feasible? The logic would be:

  1. Refresh on auth
  2. Refresh on upgrade if authenticated

Alternatively we can consider refreshing on auto complete setup if authenticated instead of upgrade which gets called anyway.

@BYK
BYK merged commit 3dfea48 into main Nov 1, 2026
26 checks passed
@BYK
BYK deleted the feat/cli-alert-aggregate-completion branch November 1, 2026 18:21

This branch was previously deployed

1 inactive deployment
Preview — 76fc0934 Deployed Nov 1, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk: medium PR risk score: medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant