Skip to content

[HDX-3964] Add event pattern mining to CLI (Shift+P)#2106

Merged
kodiakhq[bot] merged 11 commits intomainfrom
HDX-3964
Apr 14, 2026
Merged

[HDX-3964] Add event pattern mining to CLI (Shift+P)#2106
kodiakhq[bot] merged 11 commits intomainfrom
HDX-3964

Conversation

@wrn14897
Copy link
Copy Markdown
Member

@wrn14897 wrn14897 commented Apr 11, 2026

Summary

Adds a pattern mining feature to the CLI, accessible via Shift+P. This mirrors the web app's Pattern Table functionality but runs entirely in TypeScript — no Pyodide/Python WASM needed.

Linear: https://linear.app/hyperdx/issue/HDX-3964

What changed

1. Drain library in common-utils (packages/common-utils/src/drain/)

Ported the browser-drain TypeScript library into @hyperdx/common-utils. This is a pure TypeScript implementation of the Drain3 log template mining algorithm, including:

  • TemplateMiner / TemplateMinerConfig — main API
  • Drain — core algorithm with prefix tree and LRU cluster cache
  • LogMasker — regex-based token masking (IPs, numbers, etc.)
  • LruCache — custom LRU cache matching Python Drain3's eviction semantics
  • 11 Jest tests ported from the original node:test suite

2. CLI pattern view (packages/cli/src/components/EventViewer/)

Keybinding: Shift+P toggles pattern view (pauses follow mode, restores on exit)

Data flow (mirrors web app's useGroupedPatterns):

  • Issues SELECT ... ORDER BY rand() LIMIT 100000 to randomly sample up to 100K events
  • Issues parallel SELECT count() to get true total event count
  • Feeds sampled log bodies through the TypeScript TemplateMiner
  • Estimates pattern counts via sampleMultiplier = totalCount / sampledRowCount
  • Computes time-bucketed trend data per pattern

UI:

  • Pattern list with columns: Est. Count (with ~ prefix), Pattern
  • l/Enter expands a pattern to show its sample events (full table columns)
  • h/Esc returns to pattern list
  • j/k/G/g/Ctrl+D/Ctrl+U navigation throughout
  • Loading spinner while sampling query runs

Alias fix: Pattern and count queries compute WITH clauses from the source's defaultTableSelectExpression so Lucene searches using aliases (e.g. level:error where level is an alias for SeverityText) resolve correctly.

New files

  • packages/common-utils/src/drain/ — 7 source files + barrel index
  • packages/common-utils/src/__tests__/drain.test.ts
  • packages/cli/src/components/EventViewer/usePatternData.ts
  • packages/cli/src/components/EventViewer/PatternView.tsx
  • packages/cli/src/components/EventViewer/PatternSamplesView.tsx

Modified files

  • packages/cli/src/api/eventQuery.ts — added buildPatternSampleQuery, buildTotalCountQuery, buildAliasWithClauses
  • packages/cli/src/components/EventViewer/EventViewer.tsx — wired in pattern state + rendering
  • packages/cli/src/components/EventViewer/useKeybindings.ts — added P, l, h keybindings + pattern/sample navigation
  • packages/cli/src/components/EventViewer/SubComponents.tsx — added P to help screen

Demo

Screen.Recording.2026-04-10.at.6.06.18.PM.mov

@github-actions github-actions Bot added the review/tier-4 Critical — deep review + domain expert sign-off label Apr 11, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 11, 2026

🔴 Tier 4 — Critical

Touches auth, data models, config, tasks, OTel pipeline, ClickHouse, or CI/CD.

Why this tier:

  • Large diff: 1837 lines changed (threshold: 1000)

Review process: Deep review from a domain expert. Synchronous walkthrough may be required.
SLA: Schedule synchronous review within 2 business days.

Stats
  • Files changed: 21
  • Lines changed: 1837 (+ 287 in test files, excluded from tier calculation)
  • Branch: HDX-3964
  • Author: wrn14897

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

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 11, 2026

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

Project Deployment Actions Updated (UTC)
hyperdx-oss Ready Ready Preview, Comment Apr 14, 2026 5:57pm

Request Review

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 11, 2026

🦋 Changeset detected

Latest commit: 00c8507

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

This PR includes changesets to release 2 packages
Name Type
@hyperdx/cli Patch
@hyperdx/common-utils 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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 11, 2026

PR Review

  • ⚠️ PatternSamplesView cursor highlight is broken — The view slices samples with tableMaxRows = maxRows - 3 (reserving 3 header rows), but useKeybindings uses bare maxRows as the visible window size for navigation bounds (if (next >= maxRows), visibleCount = Math.min(sampleCount - sampleScrollOffset, maxRows)). The i === selectedRow check maps into the visible slice (max index tableMaxRows - 1), so the cursor will be invisible for the bottom 3 positions, and scrolling triggers 3 rows too late. Fix: use tableMaxRows (i.e. maxRows - 3) in the sample navigation bounds in useKeybindings, or pass the effective row limit as a prop.

  • ⚠️ expandedPattern not reset when reopening pattern view — The P keybinding that opens patterns resets patternSelectedRow/patternScrollOffset but not expandedPattern. If the user expands a pattern, closes the view, then reopens it, they'll land directly in the samples view of the previously selected pattern with potentially stale data. Fix: add setExpandedPattern(null) in the open-pattern handler.

  • ℹ️ usePatternData.ts is 333 lines — CLAUDE.md specifies keeping files under 300 lines. Consider extracting the time-bucketing utilities or the pattern mining loop into a helper.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 11, 2026

E2E Test Results

All tests passed • 132 passed • 3 skipped • 1032s

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

Tests ran across 4 shards in parallel.

View full report →

- Press P to mine event patterns using Drain algorithm from common-utils
- Pattern list shows count, percentage, and mined template
- Press l/Enter to expand a pattern and view its sample events
- Press h/Esc to go back, P/Esc to return to events view
- Following mode is paused while in pattern view
…mated counts

- Issue separate ORDER BY rand() LIMIT 100000 sampling query when P is pressed
- Issue parallel count() query to get true total event count
- Estimate pattern counts via sampleMultiplier (totalCount / sampledRowCount)
- Display estimated counts with ~ prefix and percentage of total
- Fix alias resolution: compute WITH clauses from source select aliases
  so Lucene searches like level:error work in pattern/count queries
…play

- Pattern sample query now uses defaultTableSelectExpression instead of
  just body+timestamp, so sample rows have all fields (Timestamp, service,
  level, Body, etc.)
- Fix timestamp column detection to use source.timestampValueExpression
- Remove Pct and Trend columns from pattern view
@kodiakhq kodiakhq Bot merged commit 418f70c into main Apr 14, 2026
17 checks passed
@kodiakhq kodiakhq Bot deleted the HDX-3964 branch April 14, 2026 18:04
knudtty pushed a commit that referenced this pull request Apr 16, 2026
## Summary

Adds a pattern mining feature to the CLI, accessible via `Shift+P`. This mirrors the web app's Pattern Table functionality but runs entirely in TypeScript — no Pyodide/Python WASM needed.

**Linear:** https://linear.app/hyperdx/issue/HDX-3964

## What changed

### 1. Drain library in common-utils (`packages/common-utils/src/drain/`)

Ported the [browser-drain](https://github.com/DeploySentinel/browser-drain) TypeScript library into `@hyperdx/common-utils`. This is a pure TypeScript implementation of the Drain3 log template mining algorithm, including:

- `TemplateMiner` / `TemplateMinerConfig` — main API
- `Drain` — core algorithm with prefix tree and LRU cluster cache
- `LogMasker` — regex-based token masking (IPs, numbers, etc.)
- `LruCache` — custom LRU cache matching Python Drain3's eviction semantics
- 11 Jest tests ported from the original `node:test` suite

### 2. CLI pattern view (`packages/cli/src/components/EventViewer/`)

**Keybinding:** `Shift+P` toggles pattern view (pauses follow mode, restores on exit)

**Data flow (mirrors web app's `useGroupedPatterns`):**
- Issues `SELECT ... ORDER BY rand() LIMIT 100000` to randomly sample up to 100K events
- Issues parallel `SELECT count()` to get true total event count
- Feeds sampled log bodies through the TypeScript `TemplateMiner`
- Estimates pattern counts via `sampleMultiplier = totalCount / sampledRowCount`
- Computes time-bucketed trend data per pattern

**UI:**
- Pattern list with columns: Est. Count (with `~` prefix), Pattern
- `l`/`Enter` expands a pattern to show its sample events (full table columns)
- `h`/`Esc` returns to pattern list
- `j/k/G/g/Ctrl+D/Ctrl+U` navigation throughout
- Loading spinner while sampling query runs

**Alias fix:** Pattern and count queries compute `WITH` clauses from the source's `defaultTableSelectExpression` so Lucene searches using aliases (e.g. `level:error` where `level` is an alias for `SeverityText`) resolve correctly.

### New files
- `packages/common-utils/src/drain/` — 7 source files + barrel index
- `packages/common-utils/src/__tests__/drain.test.ts`
- `packages/cli/src/components/EventViewer/usePatternData.ts`
- `packages/cli/src/components/EventViewer/PatternView.tsx`
- `packages/cli/src/components/EventViewer/PatternSamplesView.tsx`

### Modified files
- `packages/cli/src/api/eventQuery.ts` — added `buildPatternSampleQuery`, `buildTotalCountQuery`, `buildAliasWithClauses`
- `packages/cli/src/components/EventViewer/EventViewer.tsx` — wired in pattern state + rendering
- `packages/cli/src/components/EventViewer/useKeybindings.ts` — added P, l, h keybindings + pattern/sample navigation
- `packages/cli/src/components/EventViewer/SubComponents.tsx` — added P to help screen

### Demo

https://github.com/user-attachments/assets/50a2edfc-8891-43ae-ab86-b96fca778c66
Copilot AI pushed a commit that referenced this pull request Apr 20, 2026
## Summary

Adds a pattern mining feature to the CLI, accessible via `Shift+P`. This mirrors the web app's Pattern Table functionality but runs entirely in TypeScript — no Pyodide/Python WASM needed.

**Linear:** https://linear.app/hyperdx/issue/HDX-3964

## What changed

### 1. Drain library in common-utils (`packages/common-utils/src/drain/`)

Ported the [browser-drain](https://github.com/DeploySentinel/browser-drain) TypeScript library into `@hyperdx/common-utils`. This is a pure TypeScript implementation of the Drain3 log template mining algorithm, including:

- `TemplateMiner` / `TemplateMinerConfig` — main API
- `Drain` — core algorithm with prefix tree and LRU cluster cache
- `LogMasker` — regex-based token masking (IPs, numbers, etc.)
- `LruCache` — custom LRU cache matching Python Drain3's eviction semantics
- 11 Jest tests ported from the original `node:test` suite

### 2. CLI pattern view (`packages/cli/src/components/EventViewer/`)

**Keybinding:** `Shift+P` toggles pattern view (pauses follow mode, restores on exit)

**Data flow (mirrors web app's `useGroupedPatterns`):**
- Issues `SELECT ... ORDER BY rand() LIMIT 100000` to randomly sample up to 100K events
- Issues parallel `SELECT count()` to get true total event count
- Feeds sampled log bodies through the TypeScript `TemplateMiner`
- Estimates pattern counts via `sampleMultiplier = totalCount / sampledRowCount`
- Computes time-bucketed trend data per pattern

**UI:**
- Pattern list with columns: Est. Count (with `~` prefix), Pattern
- `l`/`Enter` expands a pattern to show its sample events (full table columns)
- `h`/`Esc` returns to pattern list
- `j/k/G/g/Ctrl+D/Ctrl+U` navigation throughout
- Loading spinner while sampling query runs

**Alias fix:** Pattern and count queries compute `WITH` clauses from the source's `defaultTableSelectExpression` so Lucene searches using aliases (e.g. `level:error` where `level` is an alias for `SeverityText`) resolve correctly.

### New files
- `packages/common-utils/src/drain/` — 7 source files + barrel index
- `packages/common-utils/src/__tests__/drain.test.ts`
- `packages/cli/src/components/EventViewer/usePatternData.ts`
- `packages/cli/src/components/EventViewer/PatternView.tsx`
- `packages/cli/src/components/EventViewer/PatternSamplesView.tsx`

### Modified files
- `packages/cli/src/api/eventQuery.ts` — added `buildPatternSampleQuery`, `buildTotalCountQuery`, `buildAliasWithClauses`
- `packages/cli/src/components/EventViewer/EventViewer.tsx` — wired in pattern state + rendering
- `packages/cli/src/components/EventViewer/useKeybindings.ts` — added P, l, h keybindings + pattern/sample navigation
- `packages/cli/src/components/EventViewer/SubComponents.tsx` — added P to help screen

### Demo

https://github.com/user-attachments/assets/50a2edfc-8891-43ae-ab86-b96fca778c66
Co-authored-by: peter-leonov-ch <209667683+peter-leonov-ch@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

automerge review/tier-4 Critical — deep review + domain expert sign-off

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants