51 lines
2.5 KiB
Markdown
51 lines
2.5 KiB
Markdown
# 097 — Metrics have no gauge/counter distinction, so `rate()`/`sum()`/`avg()` can be applied without a semantics guard
|
|
|
|
## Summary
|
|
|
|
`MetricPrimitiveKind` only distinguishes data *type*
|
|
(`String`/`Number`/`Timestamp`/`Duration`/`Boolean`), not metric
|
|
*semantics* (counter vs. gauge). PromQL's `gauge()` op is a bespoke
|
|
query-time "take the last point" function rather than something tied
|
|
to how a metric was declared, and nothing stops calling `rate()` on a
|
|
metric that's conceptually a gauge, or `sum()`/`avg()` on a
|
|
monotonically-increasing counter without rating it first.
|
|
|
|
## Where
|
|
|
|
- `src/engine/data_value.rs:70-76` — `MetricPrimitiveKind`:
|
|
`String, Number, Timestamp, Duration, Boolean`. No `Counter`/`Gauge`
|
|
variant.
|
|
- `src/engine/metric_primitive.rs:8-14` — `MetricPrimitive` mirrors
|
|
the same type-only distinction (`String, Number(Number), Timestamp,
|
|
Duration(i64), Boolean`).
|
|
- `src/engine/promql.rs:9-16` — `AggOp` includes `Gauge` as one of six
|
|
query-time aggregation ops (`Sum, Avg, Count, Rate, Histogram,
|
|
Gauge`), evaluated in `src/engine/snapshot/mod.rs:993-1001` by
|
|
taking only `points.last()` per series — a query-side convenience,
|
|
not a property of the declared metric.
|
|
- The only type guard on aggregation today is
|
|
`src/engine/snapshot/mod.rs:888-896`, which rejects `sum`/`avg` on
|
|
`MetricPrimitiveKind::String` — there's no equivalent guard for
|
|
applying `rate()` to a non-monotonic value or `sum()`/`avg()` to an
|
|
un-rated counter.
|
|
|
|
## Scope
|
|
|
|
- Add a semantics field to metric declarations (e.g. extend
|
|
`MetricPrimitiveKind` with `Counter`/`Gauge` variants, or add a
|
|
separate `MetricSemantics` enum alongside the existing type field —
|
|
decide which based on whether type and semantics should ever vary
|
|
independently for the same declaration).
|
|
- Thread that through `DeclareMetricRequest`/`MetricDeclarationRecord`/
|
|
`MetricDeclarationDto` (the same three-places pattern noted in this
|
|
repo's `CLAUDE.md` for declaration features: `engine.rs` message +
|
|
handler, `settings.rs`/`profile.rs` persistence, `api.rs` route,
|
|
plus a webapp UI affordance in `Params.tsx`/`Metrics`'s declaration
|
|
form).
|
|
- Use it to validate PromQL queries at evaluation time (e.g. warn or
|
|
reject `rate()` on a declared gauge, or `sum()`/`avg()` directly on a
|
|
declared counter without an inner `rate()`), and consider whether
|
|
the current ad hoc `gauge()` PromQL wrapper becomes redundant once
|
|
the declaration itself carries this information (a bare selector on
|
|
a declared gauge could just work the way `gauge()` does today).
|