Skip to content

Release HyperDX#2310

Merged
wrn14897 merged 1 commit into
mainfrom
changeset-release/main
May 29, 2026
Merged

Release HyperDX#2310
wrn14897 merged 1 commit into
mainfrom
changeset-release/main

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot commented May 19, 2026

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

@hyperdx/cli@0.5.0

Minor Changes

  • 3123db5: feat: experimental promql support

Patch Changes

  • b20275c: fix(cli): exit with non-zero code when upload-sourcemaps fails

    The upload-sourcemaps command now exits with code 1 when uploads fail
    (missing source maps, pre-signed URL request failure, authentication failure,
    or any per-file upload failure after retries). Previously these failures were
    logged to stderr but the process exited cleanly with code 0, causing CI
    pipelines to treat failed uploads as successes.

  • 19cd7c9: fix: only use pk and row uniqueness to look up a row

  • 8810ff0: feat: Add option for force-enabling/disabling text index support

@hyperdx/api@2.28.0

Minor Changes

  • 3123db5: feat: experimental promql support

  • cb6a74c: fix(otel-collector): allow CUSTOM_OTELCOL_CONFIG_FILE to override the
    default memory_limiter, batch (and other pipeline processors)

    Pipeline processors: lists used to be defined in the OpAMP remote config
    sent by the API (packages/api/src/opamp/controllers/opampController.ts).
    That meant the remote config overwrote any pipeline processors: list a
    user supplied via CUSTOM_OTELCOL_CONFIG_FILE, making it impossible to
    substitute the default memory_limiter with one configured for
    limit_percentage/spike_limit_percentage mode (ClickStack OTel collector hard-codes memory_limiter and custom config cannot override it #2145).

    The pipeline processors: lists now live in the bootstrap config
    (docker/otel-collector/config.yaml for supervisor mode, and
    docker/otel-collector/config.standalone.yaml for standalone mode). The
    OpAMP remote config no longer sets processors: on these pipelines, so the
    bootstrap+custom merge wins. Receivers and exporters are still configured
    dynamically by the OpAMP controller.

    To override memory_limiter, define a new processor with a different name
    in CUSTOM_OTELCOL_CONFIG_FILE and swap the pipeline processors: lists:

    processors:
      memory_limiter/custom:
        check_interval: 5s
        limit_percentage: 75
        spike_limit_percentage: 25
    
    service:
      pipelines:
        traces:
          processors: [memory_limiter/custom, batch]
        metrics:
          processors: [memory_limiter/custom, batch]
        logs/out-default:
          processors: [memory_limiter/custom, transform, batch]
        logs/out-rrweb:
          processors: [memory_limiter/custom, batch]

    The default memory_limiter block defined in the base config is left in
    the merged config but is no longer referenced by any pipeline; the
    collector only instantiates memory_limiter/custom at runtime.

    The same swap pattern works for the batch processor (and any other base
    processor). For example, to lower the export timeout on a specific
    pipeline:

    processors:
      batch/lowlatency:
        send_batch_size: 1000
        send_batch_max_size: 2000
        timeout: 500ms
    
    service:
      pipelines:
        traces:
          processors: [memory_limiter, batch/lowlatency]
        logs/out-default:
          processors: [memory_limiter, transform, batch/lowlatency]

    Lighter-weight env-var tuning is also available for the default batch
    processor without writing a custom config file:
    HYPERDX_OTEL_BATCH_SEND_BATCH_SIZE,
    HYPERDX_OTEL_BATCH_SEND_BATCH_MAX_SIZE, and HYPERDX_OTEL_BATCH_TIMEOUT.
    See the README for details.

Patch Changes

  • d134212: feat(mcp): add hyperdx_describe_source tool and slim list_sources to catalog

    Add hyperdx_describe_source — returns full column schema, map attribute
    keys, and sampled low-cardinality values (SeverityText, StatusCode,
    ServiceName, etc.) for a single source. Uses existing rollup tables for
    performant value sampling.

    Slim hyperdx_list_sources to a lightweight MongoDB-only catalog (no
    ClickHouse queries). Source tools moved to a dedicated tools/sources/
    module.

    All query tool descriptions and prompts updated to reference the two-step
    list_sources → describe_source discovery workflow.

  • a945fa0: feat(mcp): add hyperdx_event_deltas tool

    Add hyperdx_event_deltas MCP tool that compares two row groups (target
    vs baseline) and ranks properties by how much their value distributions
    differ. Same algorithm as the in-app Event Deltas view.

    Extract shared event-deltas algorithm from the UI into
    @hyperdx/common-utils/src/core/eventDeltas.ts so it can be used by
    both the frontend and the MCP server.

  • e1c4381: fix: bare-text Lucene search now falls back from Implicit Column Expression to
    Body Expression on log sources

    Previously, a log source configured with bodyExpression set but
    implicitColumnExpression unset threw Can not search bare text without an implicit column set. on every bare-token search, even though the row panel
    rendered correctly using the body column.

    Search now reuses the same one-way fallback that getEventBody already
    implements: when no Implicit Column Expression is set, bare-text search runs
    against the configured Body Expression. Trace sources are unchanged
    (spanNameExpression is not a body equivalent for trace search).

  • c3a8aa5: feat(mcp): rewrite dashboard authoring prompts and expose filters on hyperdx_save_dashboard

    The create_dashboard prompt now leads with a design checklist (alias every select item including number tiles, schema gap on groupBy so tables don't render arrayElement(SpanAttributes, '...') as the column header, RED columns with aliases, per-series numberFormat for durations, groupByColumnsOnLeft for inventory tables, dashboard-level filters instead of per-tile where literals, one-metric-per-tile for metric sources, required containers at five or more tiles, post-save validation of every tile, no title-recap markdown). The wall-of-JSON canonical example is gone; the dashboard_examples patterns carry the concrete shapes.

    The dashboard_examples set is replaced with four verified patterns (service_inventory, service_detail, log_analytics, backend_dependencies) plus the existing infrastructure_sql. Each non-SQL example leads with a "When to use" header and a "Why this shape" note so the model picks by intent, not by surface keyword match. Examples were built and rendered on a live dev stack before landing.

    The query_guide prompt gains a DASHBOARD FILTERS section that documents the filters: [{ type, name, expression, sourceId, where?, whereLanguage? }] shape, a NUMBER FORMAT section that explains the per-series vs. chart-level distinction, and a PER-TILE TYPE CONSTRAINTS note that metric tiles take exactly one select item per tile.

    hyperdx_save_dashboard now accepts filters on its input schema, reusing externalDashboardFilterSchemaWithId so the MCP and REST surfaces stay in lockstep and the existing convertExternalFiltersToInternal helper handles the conversion without translation. Filters round-trip through create, get, and update.

    Voice pass: every prompt string is now em-dash-free.

  • a4b9fa8: feat(mcp): improve MCP tool quality — error hints, shared helpers, better messages

    Extract duplicated ClickHouse error handling into a shared helper with
    pattern-matched error hints (DateTime64 casting, AS alias quoting, response
    size limits) so agents get actionable guidance on common failures. Add
    reusable mergeWhereIntoSelectItems() helper for consistent top-level where
    injection. Improve source/connection-not-found messages to suggest calling
    hyperdx_list_sources.

  • 07911fd: feat(mcp): add trace waterfall and breakdown tools

    Add hyperdx_trace_waterfall — fetch all spans in a single trace as a
    parent/child waterfall tree with optional correlated logs. Supports
    auto-pick by slowest, first error, or most recent trace.

    Add hyperdx_trace_top_time_consuming_operations — aggregate breakdown
    of child operations consuming the most cumulative time across traces
    matching a parent-span filter. Same algorithm as the in-app "Top Most
    Time Consuming Operations" chart.

  • 04a5a92: feat: Add source scoping to dashboard filters

  • 8810ff0: feat: Add option for force-enabling/disabling text index support

  • a8eb27d: feat: filters reflect all values, not search aware; filters use metadata MVs if available

  • Updated dependencies [3123db5]

  • Updated dependencies [dcab1cb]

  • Updated dependencies [a945fa0]

  • Updated dependencies [1df7583]

  • Updated dependencies [6a5ac3e]

  • Updated dependencies [e1c4381]

  • Updated dependencies [b30dfe0]

  • Updated dependencies [dcb8582]

  • Updated dependencies [b5148c8]

  • Updated dependencies [04a5a92]

  • Updated dependencies [8810ff0]

  • Updated dependencies [a8eb27d]

    • @hyperdx/common-utils@0.20.0

@hyperdx/app@2.28.0

Minor Changes

  • 3123db5: feat: experimental promql support

  • 1df7583: feat: emit Lucene conditions from sidebar/dashboard filters to enable KV items direct_read optimization on Map columns

    Legacy type: 'sql' filters in URLs are automatically migrated to Lucene
    on page load. The persisted DashboardFilter.expression in MongoDB is unchanged.

  • cb6a74c: fix(otel-collector): allow CUSTOM_OTELCOL_CONFIG_FILE to override the
    default memory_limiter, batch (and other pipeline processors)

    Pipeline processors: lists used to be defined in the OpAMP remote config
    sent by the API (packages/api/src/opamp/controllers/opampController.ts).
    That meant the remote config overwrote any pipeline processors: list a
    user supplied via CUSTOM_OTELCOL_CONFIG_FILE, making it impossible to
    substitute the default memory_limiter with one configured for
    limit_percentage/spike_limit_percentage mode (ClickStack OTel collector hard-codes memory_limiter and custom config cannot override it #2145).

    The pipeline processors: lists now live in the bootstrap config
    (docker/otel-collector/config.yaml for supervisor mode, and
    docker/otel-collector/config.standalone.yaml for standalone mode). The
    OpAMP remote config no longer sets processors: on these pipelines, so the
    bootstrap+custom merge wins. Receivers and exporters are still configured
    dynamically by the OpAMP controller.

    To override memory_limiter, define a new processor with a different name
    in CUSTOM_OTELCOL_CONFIG_FILE and swap the pipeline processors: lists:

    processors:
      memory_limiter/custom:
        check_interval: 5s
        limit_percentage: 75
        spike_limit_percentage: 25
    
    service:
      pipelines:
        traces:
          processors: [memory_limiter/custom, batch]
        metrics:
          processors: [memory_limiter/custom, batch]
        logs/out-default:
          processors: [memory_limiter/custom, transform, batch]
        logs/out-rrweb:
          processors: [memory_limiter/custom, batch]

    The default memory_limiter block defined in the base config is left in
    the merged config but is no longer referenced by any pipeline; the
    collector only instantiates memory_limiter/custom at runtime.

    The same swap pattern works for the batch processor (and any other base
    processor). For example, to lower the export timeout on a specific
    pipeline:

    processors:
      batch/lowlatency:
        send_batch_size: 1000
        send_batch_max_size: 2000
        timeout: 500ms
    
    service:
      pipelines:
        traces:
          processors: [memory_limiter, batch/lowlatency]
        logs/out-default:
          processors: [memory_limiter, transform, batch/lowlatency]

    Lighter-weight env-var tuning is also available for the default batch
    processor without writing a custom config file:
    HYPERDX_OTEL_BATCH_SEND_BATCH_SIZE,
    HYPERDX_OTEL_BATCH_SEND_BATCH_MAX_SIZE, and HYPERDX_OTEL_BATCH_TIMEOUT.
    See the README for details.

  • b8f51ed: feat: upgrade to clickhouse-server 26.5

Patch Changes

  • 55926e5: fix: "Add to Filters" on a JSON-typed ClickHouse column no longer produces an
    unparseable Lucene query

    Previously, clicking "Add to Filters" on a field under a JSON column wrapped
    the field path with toString(...) before handing it off as a Lucene filter
    key. Lucene's grammar forbids parentheses inside field names, so the resulting
    condition like toString(JSONColumn.\foo`):"…"failed to parse withExpected … but ":" found.`

    The handler now passes the clean dot-notation path (e.g. JSONColumn.foo)
    to the filter setter.

  • 1648c22: feat(dashboard): add Table of Contents right rail with bulk collapse/expand

    Adds a toggleable right-rail Table of Contents to the dashboard page, plus
    "Collapse all sections" and "Expand all sections" actions. All three live
    under a new "View" section in the dashboard's existing menu. TOC visibility
    is persisted per-user via localStorage; bulk collapse uses the same
    per-viewer URL state as single-section toggling, so it's shareable via link
    and does not change the dashboard's stored defaults. Clicking a TOC entry
    scrolls the section into view, auto-expanding it first if collapsed.

  • 937e043: fix: collapse duplicate map sub-key entries in the search filter sidebar (HDX-4340)

    A map sub-field stored in filterState under dot notation (e.g. LogAttributes.time,
    from a Lucene URL round-trip) and the same key returned by the facet query under
    bracket notation (e.g. LogAttributes['time']) no longer render as two separate
    accordion items. The merged entry keeps the bracket form so "Load more" stays
    valid, and the user's selection still resolves via a tolerant filterState lookup.

  • dcab1cb: feat: default the direct_read map column optimization on supported ClickHouse versions

    The full-text-search logs schema (00002_otel_logs.sql) now ships with
    ResourceAttributeItems, ScopeAttributeItems, and LogAttributeItems
    ALIAS columns plus their text(tokenizer='array') skip indexes. The
    traces schema (00005_otel_traces.sql) similarly gains
    ResourceAttributeItems and SpanAttributeItems ALIAS columns with
    matching items indexes. New installs and freshly migrated tables get
    the optimization automatically — no manual ALTER TABLE required.

    Note: the traces table previously used only bloom_filter skip indexes
    and worked on any ClickHouse version. The added text(tokenizer='array')
    items indexes raise the minimum ClickHouse version required to create
    the traces table to >= 26.2. Existing tables on older clusters are
    unaffected (CREATE TABLE IF NOT EXISTS is a no-op).

    At query time, the app gates the Map['key'] = 'value'
    has(<MapItems>, concat('key', '=', 'value')) rewrite on the connected
    ClickHouse server version (SELECT version(), cached per connection).
    The gate only applies to ALIAS items columns, which are computed at
    query time and therefore depend on the server being able to perform a
    direct_read against the underlying Map's tuple storage. The direct_read
    feature was backported into multiple stable 26.x release lines, so the
    gate uses a per-branch minimum:

    • 26.2 line: >= 26.2.19.43
    • 26.3 line: >= 26.3.12.3
    • 26.4 line: >= 26.4.3.37
    • 26.5+ : always supported

    ALIAS items columns on servers below their branch's threshold continue
    to compile filters into the original Map-subscript form.

    MATERIALIZED items columns are always used when available, regardless
    of ClickHouse version. MATERIALIZED columns are physically stored on
    disk, so has(items, ...) reads them directly and works on any
    ClickHouse version that supports the text index itself. Operators who
    want the optimization on servers below the backport cutoffs can
    ALTER TABLE to materialize the items columns.

  • 923b544: feat: preserve compatible filters when switching sources

  • b94b8ef: fix: persist column widths in search results table

  • 996a113: fix(row-panel): hide empty attribute sections and stop showing "[Empty]"
    when the source's body column isn't configured

    The row-expand side panel always rendered Log/Span Attributes and
    Resource Attributes accordion sections, even when both were empty. The
    body header fell back to a literal [Empty] paper in two visually
    identical cases that meant different things: the body column was
    configured but the value was empty, or the body column wasn't configured
    on the source at all.

    The two attribute accordions now mirror the existing topLevelAttributes
    pattern and only render when their content is non-empty. The body header
    takes a new bodyConfigured prop: when false (source has neither body
    nor implicit column expression configured), the body paper is suppressed
    entirely. When true and the content is empty, the placeholder reads
    "No body for this event." instead of [Empty].

    DBRowOverviewPanel derives bodyConfigured from
    getEventBody(source) !== undefined, which already returns undefined
    when neither expression is set.

    Fixes HDX-4373.

  • e1c4381: fix: bare-text Lucene search now falls back from Implicit Column Expression to
    Body Expression on log sources

    Previously, a log source configured with bodyExpression set but
    implicitColumnExpression unset threw Can not search bare text without an implicit column set. on every bare-token search, even though the row panel
    rendered correctly using the body column.

    Search now reuses the same one-way fallback that getEventBody already
    implements: when no Implicit Column Expression is set, bare-text search runs
    against the configured Body Expression. Trace sources are unchanged
    (spanNameExpression is not a body equivalent for trace search).

  • 19cd7c9: fix: only use pk and row uniqueness to look up a row

  • a44fa21: Number tile: pick a static color from the palette in Display Settings. The color picker stores a palette token (not a hex value) so the choice reflows correctly across light, dark, and IDE themes.

  • b5148c8: Dashboard table tiles configured with a row-click action now show a hover hint describing where the click will go (for example, Search HyperDX Logs or Open dashboard "API Latency Drilldown"). The cell wrapper is now a real link, so cmd-click and middle-click open the destination in a new tab, right-click shows the browser context menu with "Open in New Tab" and "Copy Link Address", and the destination URL appears in the browser status bar on hover. Keyboard users can Tab to a cell and press Enter to navigate, with a visible focus ring.

  • 0e8a5b3: chore: use PageHeader title prop on Alerts, Dashboards, and Saved Searches list pages for consistency with the shared header API.

  • 800081c: chore: migrate the ClickHouse dashboard to shared PageLayout with breadcrumbs and a sticky header (connection selector, time range, refresh) instead of a duplicate page title.

  • 41d6760: chore: migrate the Kubernetes dashboard to shared PageLayout with breadcrumbs and a sticky header (log + metric sources, time range, refresh) instead of a duplicate page title.

  • 4d248bf: chore: migrate Service Map to shared PageLayout with a sticky toolbar (source, sampling, time range) and no duplicate page title.

  • 633eda6: refactor: Use new VirtualMultiSelect for dashboard filter inputs

  • 8938b05: fix: let "Load more" surface unselected values in exact filter mode

  • 04a5a92: feat: Add source scoping to dashboard filters

  • b24cb88: fix(app): copy correct session URL on first Share Session click

    The Share Session button captured window.location.href at render time, which ran before nuqs flushed sid/sfrom/sto into the URL. The button now reads the URL at click time via the shared copyTextToClipboard util, so the first copy always contains the session params (no reload needed).

  • 8810ff0: feat: Add option for force-enabling/disabling text index support

  • a8eb27d: feat: filters reflect all values, not search aware; filters use metadata MVs if available

  • Updated dependencies [3123db5]

  • Updated dependencies [d134212]

  • Updated dependencies [dcab1cb]

  • Updated dependencies [a945fa0]

  • Updated dependencies [1df7583]

  • Updated dependencies [cb6a74c]

  • Updated dependencies [6a5ac3e]

  • Updated dependencies [e1c4381]

  • Updated dependencies [b30dfe0]

  • Updated dependencies [dcb8582]

  • Updated dependencies [c3a8aa5]

  • Updated dependencies [a4b9fa8]

  • Updated dependencies [07911fd]

  • Updated dependencies [b5148c8]

  • Updated dependencies [04a5a92]

  • Updated dependencies [8810ff0]

  • Updated dependencies [a8eb27d]

    • @hyperdx/common-utils@0.20.0
    • @hyperdx/api@2.28.0

@hyperdx/common-utils@0.20.0

Minor Changes

  • 3123db5: feat: experimental promql support

  • dcab1cb: feat: default the direct_read map column optimization on supported ClickHouse versions

    The full-text-search logs schema (00002_otel_logs.sql) now ships with
    ResourceAttributeItems, ScopeAttributeItems, and LogAttributeItems
    ALIAS columns plus their text(tokenizer='array') skip indexes. The
    traces schema (00005_otel_traces.sql) similarly gains
    ResourceAttributeItems and SpanAttributeItems ALIAS columns with
    matching items indexes. New installs and freshly migrated tables get
    the optimization automatically — no manual ALTER TABLE required.

    Note: the traces table previously used only bloom_filter skip indexes
    and worked on any ClickHouse version. The added text(tokenizer='array')
    items indexes raise the minimum ClickHouse version required to create
    the traces table to >= 26.2. Existing tables on older clusters are
    unaffected (CREATE TABLE IF NOT EXISTS is a no-op).

    At query time, the app gates the Map['key'] = 'value'
    has(<MapItems>, concat('key', '=', 'value')) rewrite on the connected
    ClickHouse server version (SELECT version(), cached per connection).
    The gate only applies to ALIAS items columns, which are computed at
    query time and therefore depend on the server being able to perform a
    direct_read against the underlying Map's tuple storage. The direct_read
    feature was backported into multiple stable 26.x release lines, so the
    gate uses a per-branch minimum:

    • 26.2 line: >= 26.2.19.43
    • 26.3 line: >= 26.3.12.3
    • 26.4 line: >= 26.4.3.37
    • 26.5+ : always supported

    ALIAS items columns on servers below their branch's threshold continue
    to compile filters into the original Map-subscript form.

    MATERIALIZED items columns are always used when available, regardless
    of ClickHouse version. MATERIALIZED columns are physically stored on
    disk, so has(items, ...) reads them directly and works on any
    ClickHouse version that supports the text index itself. Operators who
    want the optimization on servers below the backport cutoffs can
    ALTER TABLE to materialize the items columns.

  • 1df7583: feat: emit Lucene conditions from sidebar/dashboard filters to enable KV items direct_read optimization on Map columns

    Legacy type: 'sql' filters in URLs are automatically migrated to Lucene
    on page load. The persisted DashboardFilter.expression in MongoDB is unchanged.

Patch Changes

  • a945fa0: feat(mcp): add hyperdx_event_deltas tool

    Add hyperdx_event_deltas MCP tool that compares two row groups (target
    vs baseline) and ranks properties by how much their value distributions
    differ. Same algorithm as the in-app Event Deltas view.

    Extract shared event-deltas algorithm from the UI into
    @hyperdx/common-utils/src/core/eventDeltas.ts so it can be used by
    both the frontend and the MCP server.

  • 6a5ac3e: fix(charts): histogram bucket picks the highest-precision DateTime column when
    Timestamp Column lists multiple columns

    When a source's Timestamp Column listed multiple columns (e.g.
    "EventDate, EventTime" for partition-pruning), the histogram bucket was
    built from only the first token. If that token was a Date column, every
    row in a day collapsed into a single bar at midnight UTC of that day.

    The bucket resolver now walks the comma-split list, queries each column's
    type via metadata, and returns the highest-precision DateTime / DateTime64
    token. Date columns are skipped. If no DateTime-typed token is found, the
    original first-token behavior is preserved with a console.warn.

    The WHERE clause continues to use the multi-column form, so partition
    pruning via the Date column keeps working. The same resolved column is
    also used for the argMin / argMax / min / max time math in delta
    expressions.

    Fixes HDX-4371.

  • e1c4381: fix: bare-text Lucene search now falls back from Implicit Column Expression to
    Body Expression on log sources

    Previously, a log source configured with bodyExpression set but
    implicitColumnExpression unset threw Can not search bare text without an implicit column set. on every bare-token search, even though the row panel
    rendered correctly using the body column.

    Search now reuses the same one-way fallback that getEventBody already
    implements: when no Implicit Column Expression is set, bare-text search runs
    against the configured Body Expression. Trace sources are unchanged
    (spanNameExpression is not a body equivalent for trace search).

  • b30dfe0: fix: support text index on lower(Body) with no preprocessor

  • dcb8582: fix: escape colons in Lucene field names so filters on Map sub-keys containing
    : (e.g. LogAttributes['foo:bar']) parse correctly

    filtersToQuery now backslash-escapes : and \ in the emitted Lucene field
    name, and parseLuceneFilter + the SQL serializer decode those placeholders
    when consuming the AST so the original key is restored end-to-end.

  • b5148c8: Dashboard table tiles configured with a row-click action now show a hover hint describing where the click will go (for example, Search HyperDX Logs or Open dashboard "API Latency Drilldown"). The cell wrapper is now a real link, so cmd-click and middle-click open the destination in a new tab, right-click shows the browser context menu with "Open in New Tab" and "Copy Link Address", and the destination URL appears in the browser status bar on hover. Keyboard users can Tab to a cell and press Enter to navigate, with a visible focus ring.

  • 04a5a92: feat: Add source scoping to dashboard filters

  • 8810ff0: feat: Add option for force-enabling/disabling text index support

  • a8eb27d: feat: filters reflect all values, not search aware; filters use metadata MVs if available

@hyperdx/otel-collector@2.28.0

Minor Changes

  • 3123db5: feat: experimental promql support

  • cb6a74c: fix(otel-collector): allow CUSTOM_OTELCOL_CONFIG_FILE to override the
    default memory_limiter, batch (and other pipeline processors)

    Pipeline processors: lists used to be defined in the OpAMP remote config
    sent by the API (packages/api/src/opamp/controllers/opampController.ts).
    That meant the remote config overwrote any pipeline processors: list a
    user supplied via CUSTOM_OTELCOL_CONFIG_FILE, making it impossible to
    substitute the default memory_limiter with one configured for
    limit_percentage/spike_limit_percentage mode (ClickStack OTel collector hard-codes memory_limiter and custom config cannot override it #2145).

    The pipeline processors: lists now live in the bootstrap config
    (docker/otel-collector/config.yaml for supervisor mode, and
    docker/otel-collector/config.standalone.yaml for standalone mode). The
    OpAMP remote config no longer sets processors: on these pipelines, so the
    bootstrap+custom merge wins. Receivers and exporters are still configured
    dynamically by the OpAMP controller.

    To override memory_limiter, define a new processor with a different name
    in CUSTOM_OTELCOL_CONFIG_FILE and swap the pipeline processors: lists:

    processors:
      memory_limiter/custom:
        check_interval: 5s
        limit_percentage: 75
        spike_limit_percentage: 25
    
    service:
      pipelines:
        traces:
          processors: [memory_limiter/custom, batch]
        metrics:
          processors: [memory_limiter/custom, batch]
        logs/out-default:
          processors: [memory_limiter/custom, transform, batch]
        logs/out-rrweb:
          processors: [memory_limiter/custom, batch]

    The default memory_limiter block defined in the base config is left in
    the merged config but is no longer referenced by any pipeline; the
    collector only instantiates memory_limiter/custom at runtime.

    The same swap pattern works for the batch processor (and any other base
    processor). For example, to lower the export timeout on a specific
    pipeline:

    processors:
      batch/lowlatency:
        send_batch_size: 1000
        send_batch_max_size: 2000
        timeout: 500ms
    
    service:
      pipelines:
        traces:
          processors: [memory_limiter, batch/lowlatency]
        logs/out-default:
          processors: [memory_limiter, transform, batch/lowlatency]

    Lighter-weight env-var tuning is also available for the default batch
    processor without writing a custom config file:
    HYPERDX_OTEL_BATCH_SEND_BATCH_SIZE,
    HYPERDX_OTEL_BATCH_SEND_BATCH_MAX_SIZE, and HYPERDX_OTEL_BATCH_TIMEOUT.
    See the README for details.

Patch Changes

  • ad3f1c9: fix(otel-collector): skip string severity inference when JSON body has a
    level/severity field

    When the log body parsed as JSON and contained a level-like field, the
    pipeline still ran its \b(alert|crit|emerg|fatal|error|err|warn|notice|debug|dbug|trace)
    keyword scan over the raw body string. The leading-only \b boundary
    matched any word starting with a severity keyword, so bodies containing
    words like alertmanager, alerting, errors, warning, etc. produced
    the wrong severity. A Grafana sidecar log with body
    {"level":"INFO", "msg":"... mimir-alertmanager-dashboard ..."} was being
    tagged SeverityText="fatal", SeverityNumber=21 because alert matched
    inside alertmanager, even though the JSON level said INFO.

    A new OTTL log_statements block in
    docker/otel-collector/config.yaml runs between the existing JSON-parse
    block and the string-inference block. It promotes a JSON-derived level
    field (now in log.attributes) to log.severity_text, which causes the
    string-inference block to be skipped via its existing
    severity_number == 0 and severity_text == "" guard. The block is
    case-insensitive across keys by enumerating common casings of common field
    names used by mainstream logging frameworks: level / Level / LEVEL
    (pino, winston, zerolog, zap, logrus, slog, Serilog, NLog),
    severity / Severity / SEVERITY (Datadog, GCP Cloud Logging), and
    log.level (Elastic ECS, flattened from nested JSON). Each set
    self-guards on severity_text == "" so the first match wins (priority:
    level > severity > log.level). The block as a whole is gated on no
    producer-set severity, so explicit producer values are always preserved.

    severity_number is mapped via case-insensitive (?i) regex over
    severity_text, mirroring the existing string-inference keyword set.
    Unrecognized values (e.g. "verbose") fall back to INFO, matching
    block 2's else-branch. The existing ConvertCase(severity_text, "lower")
    normalization is unchanged.

    Behavior preserved for: non-JSON bodies, JSON bodies without a level
    field, and any log record where the producer already set
    severity_text or severity_number.

    Fixes HDX-4383.

@vercel
Copy link
Copy Markdown

vercel Bot commented May 19, 2026

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

Project Deployment Actions Updated (UTC)
hyperdx-oss Ready Ready Preview, Comment May 29, 2026 8:50pm
hyperdx-storybook Ready Ready Preview, Comment May 29, 2026 8:50pm

Request Review

@github-actions github-actions Bot force-pushed the changeset-release/main branch from 14d6127 to ad88f40 Compare May 19, 2026 21:35
@github-actions github-actions Bot force-pushed the changeset-release/main branch from ad88f40 to 1477141 Compare May 20, 2026 14:28
@github-actions github-actions Bot force-pushed the changeset-release/main branch from 1477141 to efd4cd7 Compare May 20, 2026 14:53
@github-actions github-actions Bot force-pushed the changeset-release/main branch from efd4cd7 to 3482782 Compare May 20, 2026 16:16
@github-actions github-actions Bot force-pushed the changeset-release/main branch from 3482782 to a9c2676 Compare May 20, 2026 19:59
@github-actions github-actions Bot force-pushed the changeset-release/main branch from a9c2676 to 7167ac6 Compare May 21, 2026 15:20
@github-actions github-actions Bot force-pushed the changeset-release/main branch from 7167ac6 to d6c7094 Compare May 21, 2026 20:43
@github-actions github-actions Bot force-pushed the changeset-release/main branch from d6c7094 to 7db11bc Compare May 22, 2026 15:02
@github-actions github-actions Bot force-pushed the changeset-release/main branch from 7db11bc to 4b68fd7 Compare May 22, 2026 16:09
@github-actions github-actions Bot force-pushed the changeset-release/main branch from 4b68fd7 to 7c686ab Compare May 22, 2026 17:09
@github-actions github-actions Bot force-pushed the changeset-release/main branch from 7c686ab to 4a66379 Compare May 22, 2026 19:08
@github-actions github-actions Bot force-pushed the changeset-release/main branch from 4a66379 to 8b3c16e Compare May 25, 2026 12:22
@github-actions github-actions Bot force-pushed the changeset-release/main branch from 8b3c16e to 4b98ea6 Compare May 25, 2026 20:29
@github-actions github-actions Bot force-pushed the changeset-release/main branch from 4b98ea6 to 8d707ee Compare May 26, 2026 08:24
@github-actions github-actions Bot force-pushed the changeset-release/main branch from 55e6431 to af37bf2 Compare May 27, 2026 08:08
@github-actions github-actions Bot force-pushed the changeset-release/main branch from af37bf2 to e39ccfc Compare May 27, 2026 14:38
@github-actions github-actions Bot force-pushed the changeset-release/main branch from e39ccfc to 71578bb Compare May 27, 2026 15:19
@github-actions github-actions Bot force-pushed the changeset-release/main branch from 71578bb to 1b44fac Compare May 27, 2026 20:57
@github-actions github-actions Bot force-pushed the changeset-release/main branch from 1b44fac to 1ed76a0 Compare May 27, 2026 23:59
@github-actions github-actions Bot force-pushed the changeset-release/main branch from 1ed76a0 to ef2b64e Compare May 28, 2026 11:25
@github-actions github-actions Bot force-pushed the changeset-release/main branch from ef2b64e to 6ecbdc7 Compare May 28, 2026 11:38
@github-actions github-actions Bot force-pushed the changeset-release/main branch 2 times, most recently from 2c4c9bd to cf8430e Compare May 28, 2026 14:28
@github-actions github-actions Bot force-pushed the changeset-release/main branch from cf8430e to e043e45 Compare May 28, 2026 14:39
@github-actions github-actions Bot force-pushed the changeset-release/main branch from e043e45 to b27719f Compare May 28, 2026 14:48
@github-actions github-actions Bot force-pushed the changeset-release/main branch from b27719f to 7fbc80f Compare May 28, 2026 14:57
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