From f8b655ac8ff8c0bf1e176cc9ec84b3126f6a2d74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josh=20Goldberg=20=E2=9C=A8?= Date: Mon, 5 Oct 2026 10:55:16 -0400 Subject: [PATCH 1/8] feat(search-events): Teach the logs query agent regex message search Add logs text-matching guidance to the embedded query-translation agent prompt so it uses `key://pattern//` regex filters when wildcards cannot express the request, and add regex few-shot examples for the logs dataset. Refs LOGS-1014 Co-Authored-By: Claude Code --- .../search-events-api-patterns.md | 1 + .../src/tools/support/search-events/config.ts | 38 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/docs/contributing/search-events-api-patterns.md b/docs/contributing/search-events-api-patterns.md index b6299c234..b4e159e43 100644 --- a/docs/contributing/search-events-api-patterns.md +++ b/docs/contributing/search-events-api-patterns.md @@ -114,6 +114,7 @@ https://us.sentry.io/api/0/organizations/sentry/events/?dataset=spans&field=ai.m - Does NOT support timestamp filters in query (use `statsPeriod` instead) - Severity levels: fatal, error, warning, info, debug, trace - Common aggregate functions: `count()`, `epm()` +- Regex filters on string attributes: `message://timeout after \d+ms//` (RE2, unquoted, max 64 characters); prefer wildcards for plain substrings #### Metrics Dataset - Represents newer span metrics, including counters, gauges, and distributions diff --git a/packages/mcp-core/src/tools/support/search-events/config.ts b/packages/mcp-core/src/tools/support/search-events/config.ts index 27d4a42a4..38228b4e8 100644 --- a/packages/mcp-core/src/tools/support/search-events/config.ts +++ b/packages/mcp-core/src/tools/support/search-events/config.ts @@ -122,6 +122,17 @@ REPLAY SEARCH RULES: - If the user asks about replays they have viewed, prefer viewed_by_me:true - If the user asks about replay users and says "me", use whoami and translate to user.email: +LOGS TEXT MATCHING (LOGS DATASET ONLY): +- Plain word or phrase: use wildcards, e.g. message:"*database*". Do NOT use a regex when a substring match is enough +- Use a regex filter key://pattern// when wildcards cannot express the request: number shapes (\\d+), alternation (a|b), anchoring (^ starts with, $ ends with), character classes ([0-9a-f]), or structured values like IPs, UUIDs, and status codes + - Example: message://timeout after \\d+ms// + - Negate with a leading !: !message://job \\d+ completed// + - There is no list form; use alternation: message://(ConnectionReset|ReadTimeout)Error// +- NEVER quote a regex: message:"//...//" is a literal string match, not a regex. Spaces and parentheses inside the pattern are fine unquoted +- Regex uses RE2 syntax (no lookarounds or backreferences), matches anywhere unless anchored, and is case sensitive; prefix the pattern with (?i) to ignore case +- Patterns are limited to 64 characters (an escape like \\d counts as one). Write \\/\\/ to match a literal // +- Regex only works on string attributes, and only in the logs dataset; other datasets treat //...// as a literal value + MATHEMATICAL QUERY PATTERNS: When user asks mathematical questions like "how many X", "total Y used", "sum of Z": - Identify the appropriate dataset based on context @@ -720,6 +731,33 @@ export const DATASET_EXAMPLES: Record< sort: "-timestamp", }, }, + { + description: + "logs whose message reports a retry count like 'retry 3 of 5'", + output: { + query: "message://retry \\d+ of \\d+//", + fields: ["timestamp", "message", "severity", "trace"], + sort: "-timestamp", + }, + }, + { + description: + "error logs whose message starts with ConnectionReset or ReadTimeout", + output: { + query: "severity:error AND message://^(ConnectionReset|ReadTimeout)//", + fields: ["timestamp", "message", "severity", "trace"], + sort: "-timestamp", + }, + }, + { + description: + "logs excluding cache hit messages like 'cache hit for key user:42'", + output: { + query: "!message://^cache hit for key \\S+//", + fields: ["timestamp", "message", "severity", "trace"], + sort: "-timestamp", + }, + }, ], tracemetrics: [ { From 5b2c76604d5ab72ffb41ef6efdabf1c94edc202e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josh=20Goldberg=20=E2=9C=A8?= Date: Mon, 5 Oct 2026 12:41:22 -0400 Subject: [PATCH 2/8] fix(search-events): Keep the regex prompt from favoring regex over wildcards Teach prefix, suffix, and wildcard-list matching so plain alternatives and anchors don't reach for a regex, keep exact value sets as key:[a,b], and swap examples that overlapped the regex evals or needed no regex. Refs LOGS-1014 Co-Authored-By: Claude Opus 5.5 --- .../search-events-api-patterns.md | 2 +- .../src/tools/support/search-events/config.ts | 25 +++++++++++-------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/docs/contributing/search-events-api-patterns.md b/docs/contributing/search-events-api-patterns.md index b4e159e43..5fe627927 100644 --- a/docs/contributing/search-events-api-patterns.md +++ b/docs/contributing/search-events-api-patterns.md @@ -114,7 +114,7 @@ https://us.sentry.io/api/0/organizations/sentry/events/?dataset=spans&field=ai.m - Does NOT support timestamp filters in query (use `statsPeriod` instead) - Severity levels: fatal, error, warning, info, debug, trace - Common aggregate functions: `count()`, `epm()` -- Regex filters on string attributes: `message://timeout after \d+ms//` (RE2, unquoted, max 64 characters); prefer wildcards for plain substrings +- Regex filters on string attributes: `message://timeout after \d+ms//` (RE2, unquoted, max 64 characters); prefer wildcards for plain substrings, prefixes, and suffixes #### Metrics Dataset - Represents newer span metrics, including counters, gauges, and distributions diff --git a/packages/mcp-core/src/tools/support/search-events/config.ts b/packages/mcp-core/src/tools/support/search-events/config.ts index 38228b4e8..659fc24f3 100644 --- a/packages/mcp-core/src/tools/support/search-events/config.ts +++ b/packages/mcp-core/src/tools/support/search-events/config.ts @@ -123,14 +123,17 @@ REPLAY SEARCH RULES: - If the user asks about replay users and says "me", use whoami and translate to user.email: LOGS TEXT MATCHING (LOGS DATASET ONLY): -- Plain word or phrase: use wildcards, e.g. message:"*database*". Do NOT use a regex when a substring match is enough -- Use a regex filter key://pattern// when wildcards cannot express the request: number shapes (\\d+), alternation (a|b), anchoring (^ starts with, $ ends with), character classes ([0-9a-f]), or structured values like IPs, UUIDs, and status codes - - Example: message://timeout after \\d+ms// - - Negate with a leading !: !message://job \\d+ completed// - - There is no list form; use alternation: message://(ConnectionReset|ReadTimeout)Error// -- NEVER quote a regex: message:"//...//" is a literal string match, not a regex. Spaces and parentheses inside the pattern are fine unquoted +- Plain word, phrase, prefix, or suffix: use wildcards. message:"*database*" contains, message:"database*" starts with, message:"*database" ends with. Do NOT use a regex when a wildcard is enough +- Any of several plain words or phrases: use a wildcard list, e.g. message:["*ConnectionReset*","*ReadTimeout*"] +- Use a regex filter key://pattern// when wildcards cannot express the request: number shapes (\\d+), character classes ([0-9a-f]), or structured values like IPs, UUIDs, and status codes. Use alternation (a|b) and anchors (^ or $) only alongside one of these + - Example: message://request took \\d+ms// + - Negate with a leading !: !message://worker \\d+ ready// + - There is no regex list form (key:[//a//,//b//] is a literal list); put alternatives inside one pattern: message://(upload|download) of \\d+ bytes failed// + - For an exact set of values, keep the list: severity:[error,fatal], not severity://error|fatal// +- NEVER quote a regex: message:"//...//" is a literal string match, not a regex +- The pattern ends at the first // followed by a space, ) or the end of the query. Spaces, parentheses, and a // followed by anything else (https?://host) are fine unquoted; write \\/\\/ for a literal // followed by a space or ) - Regex uses RE2 syntax (no lookarounds or backreferences), matches anywhere unless anchored, and is case sensitive; prefix the pattern with (?i) to ignore case -- Patterns are limited to 64 characters (an escape like \\d counts as one). Write \\/\\/ to match a literal // +- Patterns are limited to 64 characters (an escape like \\d counts as one) - Regex only works on string attributes, and only in the logs dataset; other datasets treat //...// as a literal value MATHEMATICAL QUERY PATTERNS: @@ -742,18 +745,18 @@ export const DATASET_EXAMPLES: Record< }, { description: - "error logs whose message starts with ConnectionReset or ReadTimeout", + "error logs whose message contains a hex trace id like 'trace=4bf92f3577b34da6a3ce929d0e0e4736'", output: { - query: "severity:error AND message://^(ConnectionReset|ReadTimeout)//", + query: "severity:error AND message://trace=[0-9a-f]{32}//", fields: ["timestamp", "message", "severity", "trace"], sort: "-timestamp", }, }, { description: - "logs excluding cache hit messages like 'cache hit for key user:42'", + "logs excluding heartbeat messages like 'heartbeat seq=1042'", output: { - query: "!message://^cache hit for key \\S+//", + query: "!message://^heartbeat seq=\\d+$//", fields: ["timestamp", "message", "severity", "trace"], sort: "-timestamp", }, From 49bb61636dee22485920f52ad87b537eb12f7116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josh=20Goldberg=20=E2=9C=A8?= Date: Mon, 5 Oct 2026 15:01:33 -0400 Subject: [PATCH 3/8] fix(search-events): Point the logs agent at attributes before message regex A value with its own attribute, like a response status, should filter that attribute rather than a regex over message text. Refs LOGS-1014 Co-Authored-By: Claude Opus 5.5 --- packages/mcp-core/src/tools/support/search-events/config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/mcp-core/src/tools/support/search-events/config.ts b/packages/mcp-core/src/tools/support/search-events/config.ts index 659fc24f3..c06f04d93 100644 --- a/packages/mcp-core/src/tools/support/search-events/config.ts +++ b/packages/mcp-core/src/tools/support/search-events/config.ts @@ -130,6 +130,7 @@ LOGS TEXT MATCHING (LOGS DATASET ONLY): - Negate with a leading !: !message://worker \\d+ ready// - There is no regex list form (key:[//a//,//b//] is a literal list); put alternatives inside one pattern: message://(upload|download) of \\d+ bytes failed// - For an exact set of values, keep the list: severity:[error,fatal], not severity://error|fatal// +- Regex on message is for text inside the message. When the user asks about a value that has its own attribute (e.g. response status), filter that attribute instead - NEVER quote a regex: message:"//...//" is a literal string match, not a regex - The pattern ends at the first // followed by a space, ) or the end of the query. Spaces, parentheses, and a // followed by anything else (https?://host) are fine unquoted; write \\/\\/ for a literal // followed by a space or ) - Regex uses RE2 syntax (no lookarounds or backreferences), matches anywhere unless anchored, and is case sensitive; prefix the pattern with (?i) to ignore case From 229b8c5a27d6342dc704081b1625914215ad16ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josh=20Goldberg=20=E2=9C=A8?= Date: Mon, 5 Oct 2026 15:22:36 -0400 Subject: [PATCH 4/8] fix(search-events): Teach regex for ignoring case and drop the trace-id example Wildcards are case sensitive, so ignoring case is a regex trigger; the trace id few-shot is replaced since trace has its own attribute, and array attributes are noted as regex-capable. Refs LOGS-1014 Co-Authored-By: Claude Opus 5.5 --- docs/contributing/search-events-api-patterns.md | 2 +- .../mcp-core/src/tools/support/search-events/config.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/contributing/search-events-api-patterns.md b/docs/contributing/search-events-api-patterns.md index 5fe627927..ab98803c5 100644 --- a/docs/contributing/search-events-api-patterns.md +++ b/docs/contributing/search-events-api-patterns.md @@ -114,7 +114,7 @@ https://us.sentry.io/api/0/organizations/sentry/events/?dataset=spans&field=ai.m - Does NOT support timestamp filters in query (use `statsPeriod` instead) - Severity levels: fatal, error, warning, info, debug, trace - Common aggregate functions: `count()`, `epm()` -- Regex filters on string attributes: `message://timeout after \d+ms//` (RE2, unquoted, max 64 characters); prefer wildcards for plain substrings, prefixes, and suffixes +- Regex filters on string and array attributes: `message://timeout after \d+ms//` (RE2, unquoted, max 64 characters); prefer wildcards for plain substrings, prefixes, and suffixes #### Metrics Dataset - Represents newer span metrics, including counters, gauges, and distributions diff --git a/packages/mcp-core/src/tools/support/search-events/config.ts b/packages/mcp-core/src/tools/support/search-events/config.ts index c06f04d93..6615c242d 100644 --- a/packages/mcp-core/src/tools/support/search-events/config.ts +++ b/packages/mcp-core/src/tools/support/search-events/config.ts @@ -125,7 +125,7 @@ REPLAY SEARCH RULES: LOGS TEXT MATCHING (LOGS DATASET ONLY): - Plain word, phrase, prefix, or suffix: use wildcards. message:"*database*" contains, message:"database*" starts with, message:"*database" ends with. Do NOT use a regex when a wildcard is enough - Any of several plain words or phrases: use a wildcard list, e.g. message:["*ConnectionReset*","*ReadTimeout*"] -- Use a regex filter key://pattern// when wildcards cannot express the request: number shapes (\\d+), character classes ([0-9a-f]), or structured values like IPs, UUIDs, and status codes. Use alternation (a|b) and anchors (^ or $) only alongside one of these +- Use a regex filter key://pattern// when wildcards cannot express the request: number shapes (\\d+), character classes ([0-9a-f]), structured values like IPs, UUIDs, and status codes, or ignoring case (wildcards are case sensitive). Use alternation (a|b) and anchors (^ or $) only alongside one of these - Example: message://request took \\d+ms// - Negate with a leading !: !message://worker \\d+ ready// - There is no regex list form (key:[//a//,//b//] is a literal list); put alternatives inside one pattern: message://(upload|download) of \\d+ bytes failed// @@ -135,7 +135,7 @@ LOGS TEXT MATCHING (LOGS DATASET ONLY): - The pattern ends at the first // followed by a space, ) or the end of the query. Spaces, parentheses, and a // followed by anything else (https?://host) are fine unquoted; write \\/\\/ for a literal // followed by a space or ) - Regex uses RE2 syntax (no lookarounds or backreferences), matches anywhere unless anchored, and is case sensitive; prefix the pattern with (?i) to ignore case - Patterns are limited to 64 characters (an escape like \\d counts as one) -- Regex only works on string attributes, and only in the logs dataset; other datasets treat //...// as a literal value +- Regex only works on string and array attributes, and only in the logs dataset; other datasets treat //...// as a literal value MATHEMATICAL QUERY PATTERNS: When user asks mathematical questions like "how many X", "total Y used", "sum of Z": @@ -746,9 +746,9 @@ export const DATASET_EXAMPLES: Record< }, { description: - "error logs whose message contains a hex trace id like 'trace=4bf92f3577b34da6a3ce929d0e0e4736'", + "error logs whose message contains a hex error code like 'err=0x8007000e'", output: { - query: "severity:error AND message://trace=[0-9a-f]{32}//", + query: "severity:error AND message://err=0x[0-9a-f]+//", fields: ["timestamp", "message", "severity", "trace"], sort: "-timestamp", }, From b07e21f37616dc6755582700962ea070449e3cfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josh=20Goldberg=20=E2=9C=A8?= Date: Mon, 5 Oct 2026 15:35:13 -0400 Subject: [PATCH 5/8] fix(search-events): Say regex works on string attributes only Array regex needs the tags[name,array][*] key form, so naming arrays without it invites a plain key regex that silently matches nothing. Refs LOGS-1014 Co-Authored-By: Claude Opus 5.5 --- docs/contributing/search-events-api-patterns.md | 2 +- packages/mcp-core/src/tools/support/search-events/config.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/contributing/search-events-api-patterns.md b/docs/contributing/search-events-api-patterns.md index ab98803c5..5fe627927 100644 --- a/docs/contributing/search-events-api-patterns.md +++ b/docs/contributing/search-events-api-patterns.md @@ -114,7 +114,7 @@ https://us.sentry.io/api/0/organizations/sentry/events/?dataset=spans&field=ai.m - Does NOT support timestamp filters in query (use `statsPeriod` instead) - Severity levels: fatal, error, warning, info, debug, trace - Common aggregate functions: `count()`, `epm()` -- Regex filters on string and array attributes: `message://timeout after \d+ms//` (RE2, unquoted, max 64 characters); prefer wildcards for plain substrings, prefixes, and suffixes +- Regex filters on string attributes: `message://timeout after \d+ms//` (RE2, unquoted, max 64 characters); prefer wildcards for plain substrings, prefixes, and suffixes #### Metrics Dataset - Represents newer span metrics, including counters, gauges, and distributions diff --git a/packages/mcp-core/src/tools/support/search-events/config.ts b/packages/mcp-core/src/tools/support/search-events/config.ts index 6615c242d..e67923bf7 100644 --- a/packages/mcp-core/src/tools/support/search-events/config.ts +++ b/packages/mcp-core/src/tools/support/search-events/config.ts @@ -135,7 +135,7 @@ LOGS TEXT MATCHING (LOGS DATASET ONLY): - The pattern ends at the first // followed by a space, ) or the end of the query. Spaces, parentheses, and a // followed by anything else (https?://host) are fine unquoted; write \\/\\/ for a literal // followed by a space or ) - Regex uses RE2 syntax (no lookarounds or backreferences), matches anywhere unless anchored, and is case sensitive; prefix the pattern with (?i) to ignore case - Patterns are limited to 64 characters (an escape like \\d counts as one) -- Regex only works on string and array attributes, and only in the logs dataset; other datasets treat //...// as a literal value +- Regex only works on string attributes, and only in the logs dataset; other datasets treat //...// as a literal value MATHEMATICAL QUERY PATTERNS: When user asks mathematical questions like "how many X", "total Y used", "sum of Z": From 01ddebc473cc13e732ff3b7d3a169ff7f76f9364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josh=20Goldberg=20=E2=9C=A8?= Date: Mon, 5 Oct 2026 15:38:22 -0400 Subject: [PATCH 6/8] fix(search-events): Ask for short regex patterns near the 64-character limit An unneeded \b or (?i) pushed a UUID pattern past Sentry's limit in an eval run, so the length rule now says to leave them out unless needed. Refs LOGS-1014 Co-Authored-By: Claude Opus 5.5 --- packages/mcp-core/src/tools/support/search-events/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mcp-core/src/tools/support/search-events/config.ts b/packages/mcp-core/src/tools/support/search-events/config.ts index e67923bf7..be809795f 100644 --- a/packages/mcp-core/src/tools/support/search-events/config.ts +++ b/packages/mcp-core/src/tools/support/search-events/config.ts @@ -134,7 +134,7 @@ LOGS TEXT MATCHING (LOGS DATASET ONLY): - NEVER quote a regex: message:"//...//" is a literal string match, not a regex - The pattern ends at the first // followed by a space, ) or the end of the query. Spaces, parentheses, and a // followed by anything else (https?://host) are fine unquoted; write \\/\\/ for a literal // followed by a space or ) - Regex uses RE2 syntax (no lookarounds or backreferences), matches anywhere unless anchored, and is case sensitive; prefix the pattern with (?i) to ignore case -- Patterns are limited to 64 characters (an escape like \\d counts as one) +- Patterns are limited to 64 characters (an escape like \\d counts as one), so leave out \\b and (?i) unless the request needs them - Regex only works on string attributes, and only in the logs dataset; other datasets treat //...// as a literal value MATHEMATICAL QUERY PATTERNS: From a737557cdaca628a61c0f5981d4346e9fd6ef332 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josh=20Goldberg=20=E2=9C=A8?= Date: Mon, 5 Oct 2026 16:36:32 -0400 Subject: [PATCH 7/8] fix(search-events): Forbid regex filters outside the logs dataset The agent still wrote key://pattern// for errors in some eval runs, so the rule now names the other datasets and says to use wildcards there. Refs LOGS-1014 Co-Authored-By: Claude Opus 5.5 --- packages/mcp-core/src/tools/support/search-events/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mcp-core/src/tools/support/search-events/config.ts b/packages/mcp-core/src/tools/support/search-events/config.ts index be809795f..b411aa0bb 100644 --- a/packages/mcp-core/src/tools/support/search-events/config.ts +++ b/packages/mcp-core/src/tools/support/search-events/config.ts @@ -135,7 +135,7 @@ LOGS TEXT MATCHING (LOGS DATASET ONLY): - The pattern ends at the first // followed by a space, ) or the end of the query. Spaces, parentheses, and a // followed by anything else (https?://host) are fine unquoted; write \\/\\/ for a literal // followed by a space or ) - Regex uses RE2 syntax (no lookarounds or backreferences), matches anywhere unless anchored, and is case sensitive; prefix the pattern with (?i) to ignore case - Patterns are limited to 64 characters (an escape like \\d counts as one), so leave out \\b and (?i) unless the request needs them -- Regex only works on string attributes, and only in the logs dataset; other datasets treat //...// as a literal value +- Regex only works on string attributes in the logs dataset. NEVER write key://pattern// for errors, spans, metrics, or any other dataset: they match //...// literally and return nothing. Approximate the shape with wildcards there, e.g. message:"*retry*failed*" MATHEMATICAL QUERY PATTERNS: When user asks mathematical questions like "how many X", "total Y used", "sum of Z": From 0d0b8c93beabf02fbaed4e586aa82249be72bbb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josh=20Goldberg=20=E2=9C=A8?= Date: Mon, 5 Oct 2026 17:03:56 -0400 Subject: [PATCH 8/8] fix(search-events): Prefer (?i) over mixed-case classes to fit the regex limit An eval run spelled a UUID with [0-9a-fA-F], landing at 75 characters, so the length rule now says to match either case with (?i) and a lowercase class, which fits a UUID in 64. Refs LOGS-1014 Co-Authored-By: Claude Opus 5.5 --- packages/mcp-core/src/tools/support/search-events/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mcp-core/src/tools/support/search-events/config.ts b/packages/mcp-core/src/tools/support/search-events/config.ts index b411aa0bb..3c344263c 100644 --- a/packages/mcp-core/src/tools/support/search-events/config.ts +++ b/packages/mcp-core/src/tools/support/search-events/config.ts @@ -134,7 +134,7 @@ LOGS TEXT MATCHING (LOGS DATASET ONLY): - NEVER quote a regex: message:"//...//" is a literal string match, not a regex - The pattern ends at the first // followed by a space, ) or the end of the query. Spaces, parentheses, and a // followed by anything else (https?://host) are fine unquoted; write \\/\\/ for a literal // followed by a space or ) - Regex uses RE2 syntax (no lookarounds or backreferences), matches anywhere unless anchored, and is case sensitive; prefix the pattern with (?i) to ignore case -- Patterns are limited to 64 characters (an escape like \\d counts as one), so leave out \\b and (?i) unless the request needs them +- Patterns are limited to 64 characters (an escape like \\d counts as one), so keep them short: leave out \\b unless the request needs it, and match either case with (?i)[0-9a-f] rather than [0-9a-fA-F] - Regex only works on string attributes in the logs dataset. NEVER write key://pattern// for errors, spans, metrics, or any other dataset: they match //...// literally and return nothing. Approximate the shape with wildcards there, e.g. message:"*retry*failed*" MATHEMATICAL QUERY PATTERNS: