Skip to content

feat(ourlogs): add regex search support to the EAP query syntax - #123788

Draft
JoshuaKGoldberg wants to merge 12 commits into
masterfrom
joshgoldberg/logs-958-implement-getsentrysentry-backend-for-regex-log-esarching
Draft

feat(ourlogs): add regex search support to the EAP query syntax#123788
JoshuaKGoldberg wants to merge 12 commits into
masterfrom
joshgoldberg/logs-958-implement-getsentrysentry-backend-for-regex-log-esarching

Conversation

@JoshuaKGoldberg

@JoshuaKGoldberg JoshuaKGoldberg commented Sep 8, 2026

Copy link
Copy Markdown
Member

Adds regex search to the EAP query syntax, so logs can be filtered by pattern rather than by literal or wildcard. This is done with a new Matches operator, using the same reserved-unicode marker encoding as the existing Contains / StartsWith / EndsWith wildcard operators:

message:Matches^ERROR \[\d+\]

( is the literal reserved-unicode marker, written out here because it renders invisibly.)

Resolution produces a ComparisonFilter with OP_REGEXP, which Snuba compiles to a ClickHouse match(). There is no OP_NOT_REGEXP, so != and NOT IN wrap the match in a NotFilter, and IN / NOT IN lists become an OrFilter over the patterns.

Case insensitivity is expressed by prefixing the pattern with RE2's (?i) rather than by setting ignoreCase on the filter: Snuba implements that flag by lowercasing the pattern along with the value, which rewrites [A-Z] and inverts escapes like \D.

Patterns are validated before the query is sent. ClickHouse only reports an uncompilable pattern once the query runs, and Snuba surfaces that as a 500, so the syntax RE2 lacks — backreferences, lookaround, atomic groups, conditionals, inline comments, \Z — is rejected up front as an invalid search.

Both upstreams this needed have landed:

  1. feat(snuba): add OP_REGEXP to EAP comparison filters sentry-protos#420 added OP_REGEXP
  2. feat(eap): translate OP_REGEXP to ClickHouse match() snuba#8437 translates OP_REGEXP to ClickHouse match()

Closes LOGS-958.

Adds a `Matches` operator to the search grammar, using the same reserved-unicode
marker encoding as the existing Contains/StartsWith/EndsWith wildcard operators,
and resolves it to a `ComparisonFilter` with `OP_REGEXP` for EAP datasets.

Unlike the wildcard operators, the pattern is carried verbatim rather than being
rewritten: `SearchValue.is_regex` suppresses wildcard translation and escape
sequence handling, so `\*` stays a literal asterisk and `a*b` stays a quantifier.

Patterns are validated at parse time, rejecting empty patterns and the
backreference and lookaround syntax that RE2 does not support. Regex is rejected
on virtual column contexts and on keys backed by a filter alias, since those
converters resolve values against Sentry models and would match the pattern as a
literal. There is no `OP_NOT_REGEXP`, so `!=` and `NOT IN` wrap the match in a
`NotFilter`.

`OP_REGEXP` is referenced by its wire value until sentry-protos publishes a
release containing it (getsentry/sentry-protos#420). Snuba's translation to
ClickHouse `match()` is likewise not yet released (getsentry/snuba#8437), so
this path is not end-to-end testable yet.

Fixes LOGS-958
@linear-code

linear-code Bot commented Sep 8, 2026

Copy link
Copy Markdown

LOGS-958

LOGS-966

@github-actions github-actions Bot added the Scope: Backend Automatically applied to PRs that change backend components label Sep 8, 2026
@JoshuaKGoldberg JoshuaKGoldberg changed the title feat(logs): add regex search support to the EAP query syntax feat(ourlogs): add regex search support to the EAP query syntax Sep 10, 2026
…uests

The guard sat inside `if context_definition:`, but the timeseries branch above
clears context_definition after remapping, so it never fired. The pattern was
then looked up in the context's value map as a literal, surfacing as
"Unknown value ^sen" instead of the intended error.
Three visitor sites repeated the same validate-then-mark block; SearchValue
branched on is_regex in three places where one condition covers it.
The mypy config points django_settings_module at sentry.conf.server_mypy, so
mypy cannot construct the django plugin and exits before checking anything.
make test-tools runs under uv sync --only-dev in the dev env workflow, where
the four tests asserting diagnostics have been failing since they were added
in #123923 - that PR touched no path that triggers the workflow, so it never
ran there.
Comment thread tests/tools/mypy_helpers/test_typed_validated_data.py Outdated
… installed"

This reverts commit 4ff7e94.

#124057 fixed the same devenv/test-tools failure at the root: the checks now
run under an isolated mypy config with the vendored stubs on MYPYPATH, so the
django plugin is never constructed and sentry does not need to be installed.
The skip is no longer needed, and would drop the coverage that fix restores.
…58-implement-getsentrysentry-backend-for-regex-log-esarching
Snuba lowercases the pattern along with the value when a comparison filter sets ignore_case, which rewrites classes like [A-Z] and inverts escapes like \D. Prefixing the pattern with (?i) instead keeps it intact.
ClickHouse only reports an uncompilable pattern once the query runs, and Snuba surfaces that as a 500, so \Z, atomic groups, conditionals, inline comments and named backreferences are now caught alongside backreferences and lookaround.
Exercises matching, negation, IN lists, attribute keys and case insensitivity against Snuba now that OP_REGEXP has landed there.
@JoshuaKGoldberg

Copy link
Copy Markdown
Member Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a7d246e. Configure here.

Comment thread src/sentry/search/events/constants.py Outdated
The unsupported-syntax scan treated any backslash-digit pair as a backreference, so a pattern matching a literal backslash followed by a digit was rejected before it reached Snuba.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Backend Automatically applied to PRs that change backend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants