Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
188 changes: 188 additions & 0 deletions skills-next/references/search-query-language.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
# Search Query Language

Sentry's `key:value` search grammar. It's the **shared vocabulary** for every query surface —
the Issues stream, Explore, Dashboards, alert/monitor conditions, and the MCP
tools. Authoring a good query (and reading one back) is the same skill everywhere, so the
grammar lives here once.

> The web UI auto-completes these as you type. You only need to *write* the raw syntax when
> driving the API / MCP.

## Grammar

A query is a space-separated list of **tokens**. Each token is either a `key:value` pair or a
single piece of **raw text** (matched against the event title/message with a CONTAINS match).

```
is:unresolved user.username:"Jane Doe" server:web-8 example error
```

That's four tokens: `is:unresolved`, `user.username:"Jane Doe"`, `server:web-8` (a custom
tag), and the raw search `example error`.

### Rules

- **Quote values with spaces:** `user.username:"Jane Doe"`.
- **Implicit `AND`:** space-separated tokens are intersected (all must match).
- **Negation:** prefix with `!` to exclude — `!user.email:test@example.com`,
`!message:"*Timeout"`.
- **Comparison operators** on numbers/durations/dates: `>`, `<`, `>=`, `<=`, placed after the
`:` for numeric/duration fields (an exact `:` match rarely exists):
- `transaction.duration:>5s`
- `count_dead_clicks:<=10`
- `event.timestamp:>2023-09-28T00:00:00-07:00`
- **Value lists** (OR on one key): `release:[12.0, 13.0]` ≡ `release:12.0 OR release:13.0`.
Not allowed with `is:` and not combinable with wildcards.
- **Wildcards:** `*` matches any characters — `browser:"Safari 11*"`, `!message:"*Timeout"`.
- **`has:`** — field/tag exists regardless of value: `has:user`. Negate as `!has:`.
- **`is:`** — issue/feedback **state** (see catalogs below); not usable with value lists.
- **Explicit tag syntax** when a tag name collides with a reserved key:
`tags[project_id]:value`.

### `AND` / `OR` / parentheses

`OR`, `AND`, and grouping `()` are available in **Discover, Dashboards, and Monitors** (not the
basic Issues search):

```
browser:Chrome OR browser:Opera
release:13.0 AND (transaction.duration:>2s OR http.status_code:500)
```

- `AND` binds tighter than `OR`: `x AND y OR z` ≡ `(x AND y) OR z`. Use parens to override.
- `AND` may join a non-aggregate with an aggregate; **`OR` may not** mix the two.
`user.username:jane OR count():>100` is invalid.

### Aggregate conditions (functions)

On aggregating surfaces (Discover/Dashboards), function keys filter on computed values. The
function still needs a value/filter even when it takes no parameter:

```
count():>100
count_unique(user):>=20
p95(transaction.duration):>500ms
failure_rate():>0.05
epm():>12
count_if(transaction.duration,greater,1000):>5
```

### Relative time / age

`age:` (and `firstSeen`/`lastSeen`) use Unix-find-style offsets — suffixes `m`/`h`/`d`/`w`:

- `age:-24h` — created in the last 24 hours.
- `age:+12h` — older than 12 hours.
- `age:+12h age:-24h` — created between 12 and 24 hours ago.

---

## Searchable properties by dataset

Search terms only validate against the **dataset** you're querying — a span key won't work in
Issues, etc. The catalogs below are the common keys per dataset. (Any **custom tag** your SDK
sets is also searchable as a key; use `tags[name]:value` if the name collides with a reserved
one.)

### Issues (the Issues stream)

State & triage: `is:` (`unresolved`, `resolved`, `archived`, `assigned`, `unassigned`,
`for_review`, `linked`, `unlinked`), `assigned`, `assigned_or_suggested`, `bookmarks`
(values: an email, `me`, `none`, `my_teams`, `#team-name`).

Identity & grouping: `issue` (short code, e.g. `SENTRY-ABC`), `issue.category` (`error`,
`performance`, `frontend`, `outage`), `issue.type` (e.g.
Comment on lines +93 to +94

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: The documentation for issue.category lists frontend and outage as valid values, but these are not supported by Sentry.
Severity: MEDIUM

Suggested Fix

Update the documentation to replace the incorrect values frontend and outage with the correct list of Sentry issue categories: error, performance, feedback, replay, and cron.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: skills-next/references/search-query-language.md#L93-L94

Potential issue: The documentation file `search-query-language.md` incorrectly lists
`frontend` and `outage` as valid values for the `issue.category` search filter. The
actual valid values are `error`, `performance`, `feedback`, `replay`, and `cron`. This
discrepancy will cause systems or users, particularly AI agents relying on this
documentation, to construct invalid search queries, leading to failed searches.

Did we get this right? 👍 / 👎 to inform future reviews.

`performance_n_plus_one_db_queries`), `title`, `message`, `culprit`, `location`.

Counts & age: `timesSeen` (= `count()`), `age`, `firstSeen`, `lastSeen`, `event.timestamp`.

Release/version: `release`, `firstRelease` (supports `latest`), `release.version`,
`release.build`, `release.package`, `release.stage` (`adopted`/`low`/`replaced`), `dist`.

Error shape: `error.handled`, `error.unhandled`, `error.type`, `error.value`,
`error.mechanism`, `error.main_thread`, `level`, `event.type`.

Stack: `stack.filename`, `stack.function`, `stack.module`, `stack.package`, `stack.abs_path`.

Request/user/device/geo: `http.method`, `http.status_code`, `http.url`, `http.referer`,
`user.id`, `user.email`, `user.username`, `user.ip`, `device.*`, `os.*`, `geo.city`,
`geo.country_code`, `geo.region`, `platform.name`, `sdk.name`, `sdk.version`.

Other: `project`, `project.id`, `transaction`, `trace`, `flags["my_flag"]:true` (feature-flag
evaluation), `has`.

### Events (Discover, error + transaction events)

Everything in Issues that's event-level, plus **aggregate functions**: `count()`,
`count_unique(field)`, `count_if(column,operator,value)`, `count_miserable(field,threshold)`,
`count_web_vitals(vital,threshold)`, `avg(field)`, `min`/`max`/`sum(field)`,
`percentile(field,level)`, `pXY(duration field)` (e.g. `p95`), `apdex(threshold)`,
`failure_count()`, `failure_rate()`, `user_misery(number)`, `last_seen()`, `epm()`, `eps()`.

Transaction/perf: `transaction`, `transaction.duration`, `transaction.op`,
`transaction.status`, `measurements.lcp` / `.fcp` / `.fid` / `.cls` / `.ttfb` (web vitals),
`measurements.app_start_cold` / `.app_start_warm`, `measurements.frames_*`,
`measurements.stall_*`, `spans.db` / `.http` / `.browser` / `.resource` / `.ui`.

Trace linking: `trace`, `trace.span`, `trace.parent_span`. Time bucketing:
`timestamp.to_hour`, `timestamp.to_day`. Plus `environment`, `device.class`, full `stack.*`
(incl. `stack.lineno`, `stack.colno`, `stack.in_app`), `user.display`.

### Spans (Trace / Span Explorer)

`span.op` / `op`, `span.description` / `description`, `span.duration` / `duration`,
`self_time`, `module`, `group`, `action`, `domain`, `system`, `status`, `status_code`,
`trace.status`, `transaction`, `transaction.op`, `transaction.method`, `cache.hit`,
`file_extension`, `resource.render_blocking_status`,
`http.response_content_length` / `.decoded_response_content_length` / `.response_transfer_size`,
`messaging.destination.name`, `messaging.message.id`, `release`, `environment`,
`browser.name`, `os.name`, `device.class`, `platform`, `sdk.name`, `sdk.version`,
`user.id` / `.email` / `.username`.

### Logs

Logs search on the log `message`, `level` / `severity`, `timestamp`, the trace it belongs to
(`trace`), and any **structured attributes** you attached (searched as keys). Plus the common
context keys (`release`, `environment`, `project`).

### Session Replay

Counts/quality: `count_errors`, `count_dead_clicks`, `count_rage_clicks`, `count_urls`,
`count_segments`, `count_traces`, `activity`, `duration`.

Clicks: `click.tag`, `click.id`, `click.class`, `click.role`, `click.label`,
`click.textContent`, `click.title`, `click.testid`, `click.component_name`, `click.selector`,
`click.alt`, `dead.selector`, `rage.selector`.

Session/identity: `id`, `replay_type`, `url`, `screen`, `trace`, `error_ids`, `is_archived`,
`seen_by_me`, `level`, `dist`, `release`, `platform`, `browser.name`, `browser.version`,
`os.name`, `os.version`, `device.*`, `user.id` / `.email` / `.username` / `.ip`,
`user.geo.city` / `.country_code` / `.region` / `.subdivision`, `sdk.name`, `sdk.version`,
`project_id`.

### User Feedback

`is`, `assigned`, `id`, `level`, `message`, `url`, `transaction`, `timestamp`, `environment`,
`browser.name`, `os.name`, `device.brand` / `.family` / `.model_id` / `.name`, `dist`,
`user.id` / `.email` / `.ip` / `.username`, `sdk.name`, `sdk.version`.

### Releases

`release`, `release.version`, `release.build`, `release.package`, `release.stage`
(`adopted` / `low` / `replaced`). Pick the newest with `release:latest`.

---

## Where this language is used

- **Reading data** — issue search and event/Discover queries locate and slice data with this
grammar; natural-language questions are translated into it.
- **Authoring monitors & dashboards** — alerts, metric monitors, and dashboards are authored as
saved queries in this grammar.

## Pitfalls

- Using a key from the wrong dataset (it won't validate — the API errors, the UI fails to
auto-complete).
- Using `:` instead of a comparison operator on a numeric/duration/date field.
- Expecting `OR`/`AND` in the basic Issues search (only Discover/Dashboards/Monitors).
Loading