Skip to content

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

@agnewp

Description

@agnewp

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: '',
  },
]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions