Skip to content

feat: add pattern column selector for event pattern matching on any column#2460

Open
knudtty wants to merge 4 commits into
mainfrom
aaron/switch-event-patterns
Open

feat: add pattern column selector for event pattern matching on any column#2460
knudtty wants to merge 4 commits into
mainfrom
aaron/switch-event-patterns

Conversation

@knudtty

@knudtty knudtty commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a selector to do event pattern matching on any column or expression, not just Body.
Also changes the drain tokenizer.

Drain collapses any token to a space character and then runs the drain algorithm. To make things look fine in the event patterns, I had to add some reconstruction logic.

Screenshots or video

image

How to test on Vercel preview

Preview routes:

Steps:

  1. Go to "Event Patterns" on the search page
  2. Change to an expression like concatWithSeparator(' ', Body, LogAttributes)
  3. Enjoy

References

  • Linear Issue: Closes HDX-4523

@vercel

vercel Bot commented Jun 12, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
hyperdx-oss Ready Ready Preview, Comment Jun 12, 2026 8:03pm
hyperdx-storybook Ready Ready Preview, Comment Jun 12, 2026 8:03pm

Request Review

@changeset-bot

changeset-bot Bot commented Jun 12, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b20d0b4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@hyperdx/app Patch
@hyperdx/api Patch
@hyperdx/otel-collector Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@knudtty knudtty requested review from a team and fleon and removed request for a team June 12, 2026 19:53
@knudtty knudtty marked this pull request as ready for review June 12, 2026 19:53
@github-actions github-actions Bot added the review/tier-2 Low risk — AI review + quick human skim label Jun 12, 2026
@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

🔵 Tier 2 — Low Risk

Small, isolated change with no API route or data model modifications.

Why this tier:

  • Standard feature/fix — introduces new logic or modifies core functionality

Review process: AI review + quick human skim (target: 5–15 min). Reviewer validates AI assessment and checks for domain-specific concerns.
SLA: Resolve within 4 business hours.

Stats
  • Production files changed: 5
  • Production lines changed: 145 (+ 101 in test files, excluded from tier calculation)
  • Branch: aaron/switch-event-patterns
  • Author: knudtty

To override this classification, remove the review/tier-2 label and apply a different review/tier-* label. Manual overrides are preserved on subsequent pushes.

@greptile-apps

greptile-apps Bot commented Jun 12, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds a column/expression selector to the Event Patterns view so users can run drain-based pattern matching against any SQL expression (not just Body), with the chosen expression persisted in the URL. It also changes the drain3 tokenizer to treat all punctuation as delimiters and introduces a reconstructTemplate utility that restores the original separators into the mined pattern string.

  • PatternColumnSelector wraps any user-supplied expression in toString() and passes it to the existing useGroupedPatterns / usePatterns hooks; the committed expression is stored in a patternColumn query-string param with a draftPatternColumn local state for buffering edits.
  • usePatterns now includes bodyValueExpression in its queryKey, so changing the expression correctly invalidates the cached pattern results.
  • reconstructTemplate (new file) re-aligns the whitespace-collapsed drain template against the original log string to restore punctuation-based separators — but the regex constant it depends on (TOKEN_OR_SEPARATOR) is never defined, causing a build failure and a runtime TypeError on every call.

Confidence Score: 2/5

Not safe to merge: reconstructTemplate.ts references an undefined constant, preventing the TypeScript build from compiling and crashing every pattern reconstruction call at runtime.

reconstructTemplate.ts calls TOKEN_OR_SEPARATOR.lastIndex and TOKEN_OR_SEPARATOR.exec(...) but the regex constant is never declared anywhere in the file or the codebase. The TypeScript compiler will reject the file outright, and if somehow bundled without type-checking it would throw a TypeError on every invocation, making the entire new pattern matching feature non-functional.

packages/app/src/components/Patterns/reconstructTemplate.ts — the regex constant TOKEN_OR_SEPARATOR must be defined before the function (or locally inside it) for the build and tests to pass.

Important Files Changed

Filename Overview
packages/app/src/components/Patterns/reconstructTemplate.ts Uses TOKEN_OR_SEPARATOR which is never defined — causes a TypeScript compile error and a runtime TypeError on every call.
packages/app/src/components/Patterns/PatternColumnSelector.tsx New component: renders SQLInlineEditor for picking the pattern expression, with a helper buildPatternColumnExpression that wraps non-empty input in toString().
packages/app/src/components/PatternTable.tsx Adds patternColumn / draftPatternColumn props and renders PatternColumnSelector in both the error and success branches; passes the effective expression to downstream hooks.
packages/app/src/DBSearchPage.tsx Adds patternColumn URL query state with a draft/committed pattern; onSubmit now writes the draft to the URL and passes both to PatternTable.
packages/app/src/hooks/usePatterns.tsx Adds bodyValueExpression to the queryKey so changing the expression triggers a fresh query; configures drain3 with all punctuation as extra delimiters; uses reconstructTemplate to restore separators in the displayed pattern.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[User types expression\nin PatternColumnSelector] --> B[draftPatternColumn\nlocal state]
    B --> C{User submits\nonSubmit}
    C --> D[setPatternColumn\nURL query state]
    D --> E[buildPatternColumnExpression\nwraps in toString]
    E --> F[effectiveBodyValueExpression]
    F --> G[useGroupedPatterns\nbodyValueExpression + queryKey]
    G --> H[ClickHouse query\nfetches sample rows]
    H --> I[mineEventPatterns\ndrain3 with all punctuation\nas extra delimiters]
    I --> J[reconstructTemplate\nrestores separators]
    J --> K[Pattern displayed\nin PatternTable]

    style J fill:#f66,color:#fff
Loading

Fix All in Claude Code Fix All in Conductor Fix All in Cursor Fix All in Codex

Reviews (2): Last reviewed commit: "Update packages/app/src/components/Patte..." | Re-trigger Greptile

Comment thread packages/app/src/components/Patterns/reconstructTemplate.ts Outdated
Comment thread packages/app/src/components/Patterns/reconstructTemplate.ts Outdated
Comment on lines +14 to +15
if (!patternColumn) return fallback;
return `toString(${patternColumn})`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 buildPatternColumnExpression unconditionally wraps the user input in toString(…). If a user enters an expression that already returns a string (e.g. toString(Body)), the generated SQL becomes toString(toString(Body)). ClickHouse handles this gracefully for actual strings, but a simple guard prevents the redundant wrapping.

Suggested change
if (!patternColumn) return fallback;
return `toString(${patternColumn})`;
if (!patternColumn) return fallback;
const trimmed = patternColumn.trim();
if (/^toString\s*\(/i.test(trimmed)) return trimmed;
return `toString(${trimmed})`;

Fix in Claude Code Fix in Conductor Fix in Cursor Fix in Codex

Comment thread packages/app/src/components/PatternTable.tsx
knudtty and others added 2 commits June 12, 2026 16:00
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

E2E Test Results

All tests passed • 197 passed • 3 skipped • 1395s

Status Count
✅ Passed 197
❌ Failed 0
⚠️ Flaky 6
⏭️ Skipped 3

Tests ran across 4 shards in parallel.

View full report →

Comment on lines +11 to +13
let tokenIdx = 0;
let match: RegExpExecArray | null;
while ((match = tokenOrSeparator.exec(normalized)) !== null) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P0 TOKEN_OR_SEPARATOR is used but never defined anywhere in this file or the codebase. The file has no imports and the grep confirms there is no definition anywhere in src/. TypeScript will refuse to compile this (Cannot find name 'TOKEN_OR_SEPARATOR') and calling .lastIndex on undefined will throw a TypeError at runtime, breaking all pattern matching. The regex /([A-Za-z0-9]+)|([^A-Za-z0-9]+)/g needs to be declared — either as a module-level constant or as a local variable inside the function before the loop.

Fix in Claude Code Fix in Conductor Fix in Cursor Fix in Codex

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review/tier-2 Low risk — AI review + quick human skim

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant