Skip to content

feat: Enhanced Severity filter for logs - #3437

Draft
SpencerTorres wants to merge 1 commit into
otel-severity-number-uifrom
otel-severity-class-filter
Draft

SpencerTorres wants to merge 1 commit into
otel-severity-number-uifrom
otel-severity-class-filter

Conversation

@SpencerTorres

Copy link
Copy Markdown
Member

Closes HDX-5776. Stacked on the HDX-5768 PR.

Why

HDX-5768 made log levels display from the OTel SeverityNumber, but filters still match the raw SeverityText. A row shown as ERROR because its number is 17 doesn't match SeverityText:error when its text is empty or spelled differently ("ERROR", "err", "critical"). To find errors, users have to know every spelling. This adds a Severity filter that matches on intent instead: the class comes from SeverityNumber (1-24) when that's set, and from the text otherwise. It uses the same rules as the HDX-5768 labels.

SeverityText filters, its facet, and every existing saved search, alert and dashboard behave exactly as before.

Changes

  • Class SQL (@hyperdx/common-utils core/severity): buildSeverityClassExpressionV1 generates the ClickHouse expression from the rules table the UI labels use.

    • It's frozen by a golden-string test, because saved searches and alerts store it. Any rule change ships as V2.
    • It's a plain multiIf: SeverityNumber thresholds first (21+ FATAL … 1+ TRACE), then one SeverityText ILIKE '<word>%' check per common level word (e.g. err, crit, panic, warn, inf), else OTHER. There's no regex. Broader guessing (punctuation, rarer spellings) belongs to the collector.
    • Parity with the JS rules is checked against real ClickHouse in a new integration test.
  • Severity facet: first in the search sidebar, with fixed values in severity order (TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OTHER for unrecognized text). Selecting a value writes <class expression> IN ('ERROR') in the existing filter format. Only, Exclude, Clear and percentages work as on other facets. The facet doesn't fetch its values.

    • It only shows for log sources with Severity Number Expression set, and is hidden when a Known Columns List leaves out either severity column.
  • Pills, saved searches and source switching: pills read Severity = ERROR. The save modal shows Severity: ERROR. Switching sources moves the filter to the new source's expression.

  • Consumers: on sources with the field, the Kubernetes "Errors" log tables and the LLM dashboard error counts match FATAL and ERROR. That also catches critical, fatal, panic and number-only errors.

  • Alert text: notifications show Severity: ERROR instead of about 800 characters of SQL. How the alert is evaluated is unchanged.

  • Source form: the Severity Number Expression help text says it must be an OpenTelemetry SeverityNumber, and the form marks a non-numeric expression as invalid, since the class SQL compares it with numbers.

Compatibility and cost

  • Sources without Severity Number Expression: no facet, no new queries, nothing changes.
  • The class filter only runs when a user selects it. It can't use the text-only facet rollup, or materialized views that are keyed only on SeverityText, so those queries fall back to the raw table (still correct). The changeset suggests adding SeverityNumber to the views' dimensions.
  • Class counts differ from SeverityText counts by design. For example, (9, "error") is INFO, because the number wins.

How to reproduce

  1. Run yarn dev on this branch and register a fresh account. The default Logs source has Severity Number Expression set to SeverityNumber.
  2. Send the test logs from the HDX-5768 PR. Add -H "authorization: <ingestion key>" (Team Settings → API Keys) and use the OTLP HTTP port shown in the dev portal at http://localhost:9900.
  3. On the search page, Severity is the first facet. Select ERROR. Four rows show: "number and text disagree", "number only", "number only, sub-level" and "old HyperDX SDK". For comparison, SeverityText:error only finds "old HyperDX SDK".
  4. The pill reads Severity = ERROR. Save the search and reload: the filter is still applied.
  5. In Team Settings → Sources, clear the Logs source's Severity Number Expression. The Severity facet disappears.

Screenshots

  • TODO

@SpencerTorres
SpencerTorres added this pull request to stack #3428 October 22, 2026 00:17
@changeset-bot

changeset-bot Bot commented Oct 22, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 2faf6d1

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

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

@vercel

vercel Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
hyperdx-oss Ready Ready Preview Oct 22, 2026 12:18am UTC
hyperdx-storybook Ready Ready Preview Oct 22, 2026 12:18am UTC

Request Review

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

E2E Test Results

✅ All tests passed • 456 passed • 1 skipped • 1867s

Status Count
✅ Passed 456
❌ Failed 0
⚠️ Flaky 2
⏭️ Skipped 1

Tests ran across 4 shards in parallel.

View full report →

@SpencerTorres SpencerTorres changed the title feat: Severity filter for logs that considers SeverityNumber and Seve… feat: Enhanced Severity filter for logs Oct 22, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Duplicate code analysis

2 new clones introduced by this PR.

  • packages/app/src/NamespaceDetailsSidePanel.tsx:119-133 ↔ packages/app/src/NodeDetailsSidePanel.tsx:132-146 — 15 lines
  • packages/app/src/NamespaceDetailsSidePanel.tsx:135-198 ↔ packages/app/src/NodeDetailsSidePanel.tsx:148-211 — 64 lines

If one of these duplicates a helper that already exists, import it instead
of redefining it. If the duplication is deliberate, ignore this comment —
the check is advisory and never fails the build.


jscpd compared this branch against origin/main
across app, api and common-utils. Only new clones are listed; the codebase
currently holds 122 in total (1.59%).
Run yarn dupes locally to reproduce, or yarn dupes:all for the full picture.

@greptile-apps

greptile-apps Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 4/5

[Medium impact] The changes reach log search and several log-error views.

Guard string-backed severity numbers before merging so automatic error queries do not fail.

Fix All in Claude CodeFindings

  1. P1 String severity columns break queries ▶

Summary

Adds a fixed Severity facet backed by shared SQL, readable filter pills and alert text, and source-switch support.

  • Log severity classes follow the same number-first rules across the app.
  • Log search offers a fixed Severity filter that saves and displays class selections.
  • Kubernetes and LLM error views use the same severity classes as log search.
  • Alerts and saved-search summaries show severity class names instead of SQL.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Source["Source severity expressions"] --> Class["V1 class SQL"]
  Class --> Facet["Severity facet"]
  Facet --> Stored["URL and saved filters"]
  Stored --> Labels["Readable pills and alert text"]
  Class --> Errors["Kubernetes and LLM error queries"]
Loading

Reviews (1) · Last reviewed commit: "feat: Severity filter for logs that cons..." · Reviewed by Greptile

Comment on lines +28 to +29
const numberExpr = getSelectableSeverityNumberExpression(source);
if (numberExpr == null) return undefined;

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.

P1 String severity columns break queries

If a saved source points severityNumberExpression at a String column, getSeverityClassKey accepts it and builds comparisons such as SeverityNumber >= 21, which ClickHouse rejects. The new LLM error counts and Kubernetes “Errors” tables apply this SQL automatically, so previously working queries now fail. The form warning neither protects existing sources nor blocks saving.

Check the expression’s type before enabling these queries, or convert it safely.

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

This branch was successfully deployed

2 active deployments
Preview – hyperdx-oss — 2faf6d19 Deployed Oct 22, 2026 by vercel[bot]
Preview – hyperdx-storybook — 2faf6d19 Deployed Oct 22, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant