hyperdxio / hyperdxio/hyperdx

count_distinct aggFn on metric tiles ignores valueExpression, always counts distinct metric Values

Open Beginner friendly
#2,311 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
9.9k
Forks
471
Avg merge
2d 4h
Merged PRs (30d)
117

Description

Bug Description

When using count_distinct as the aggFn on a metric tile, the valueExpression is ignored. The generated SQL always counts distinct values of the metric's float Value column rather than the specified attribute expression.

Steps to Reproduce

  1. Create a dashboard tile with displayType: "number" and a metric select using count_distinct with a valueExpression pointing to an attribute:
    {
      "displayType": "number",
      "source": "Metrics",
      "select": [
        {
          "aggFn": "count_distinct",
          "valueExpression": "Attributes['name']",
          "metricName": "argocd_app_info",
          "metricType": "gauge"
        }
      ]
    }
    
  2. Observe the number displayed — for an info metric (where Value is always 1.0), the tile shows 1 or 2 instead of the actual count of distinct attribute values.

Expected Behavior

The tile should display the count of distinct values of Attributes['name'] across all time series for the metric — i.e., the number of distinct applications reported by argocd_app_info.

Direct ClickHouse query gives the correct answer:

SELECT uniqExact(Attributes['name'])
FROM default.otel_metrics_gauge
WHERE MetricName = 'argocd_app_info'
  AND TimeUnix >= now() - INTERVAL 1 HOUR
-- returns 53

Actual Behavior

The generated SQL uses count(DISTINCT LastValue) where LastValue = last_value(Value) — the gauge's numeric value — not the attribute expression:

-- Generated by HyperDX
...
Bucketed AS (
  SELECT
    ...,
    last_value(Value) AS LastValue,   -- <-- always the float metric value
    any(Attributes) AS Attributes
  FROM Source
  GROUP BY AttributesHash, __hdx_time_bucket2
)
SELECT count(DISTINCT LastValue)      -- <-- counts distinct 1.0, 0.0, etc.
FROM Bucketed

Result: 2 (distinct float values) instead of 53 (distinct app names).

Root Cause

In packages/common-utils/src/core/renderChartConfig.ts, translateMetricChartConfig unconditionally overwrites valueExpression with 'LastValue' for gauge metrics before passing the select config to SQL generation:

select: [
  {
    ..._select,
    valueExpression: 'LastValue',  // overwrites user-provided Attributes['name']
    aggCondition: '',
  },
]

The original valueExpression from the user config is never used in metric query translation.

Additional Context

  • The zod schema (externalDashboardSelectItemSchema in packages/api/src/utils/zod.ts) accepts and even requires valueExpression for non-count aggFns on metrics — so the intent to support this exists, but the query translator doesn't honour it.
  • The UI currently has no input for valueExpression on metric tiles, which makes sense given it's ignored — but fixing the translator would enable useful aggregations like counting distinct label values.
  • Confirmed present in v2.27.0. No prior issue or fix found.

Suggested Fix

For count_distinct (and potentially other aggFns where valueExpression refers to an attribute), use the user-provided expression instead of hardcoding 'LastValue':

// In translateMetricChartConfig for gauge metrics:
const effectiveValueExpression =
  _select.aggFn === 'count_distinct' && _select.valueExpression
    ? _select.valueExpression
    : 'LastValue';

select: [
  {
    ..._select,
    valueExpression: effectiveValueExpression,
    aggCondition: '',
  },
]

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in packages/common-utils/src/core/renderChartConfig.ts at translateMetricChartConfig and inspect how gauge select items are translated before SQL generation. Reproduce the count_distinct metric configuration from the issue, preserve its attribute valueExpression, and verify the generated query counts distinct attribute values rather than LastValue.

Written by the indexing model from the issue text.

Assessment

Tech stack
clickhouse, sql, typescript
Domain
analytics, backend, data
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.