2.5 KiB
2.5 KiB
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. NoCounter/Gaugevariant.src/engine/metric_primitive.rs:8-14—MetricPrimitivemirrors the same type-only distinction (String, Number(Number), Timestamp, Duration(i64), Boolean).src/engine/promql.rs:9-16—AggOpincludesGaugeas one of six query-time aggregation ops (Sum, Avg, Count, Rate, Histogram, Gauge), evaluated insrc/engine/snapshot/mod.rs:993-1001by taking onlypoints.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 rejectssum/avgonMetricPrimitiveKind::String— there's no equivalent guard for applyingrate()to a non-monotonic value orsum()/avg()to an un-rated counter.
Scope
- Add a semantics field to metric declarations (e.g. extend
MetricPrimitiveKindwithCounter/Gaugevariants, or add a separateMetricSemanticsenum 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'sCLAUDE.mdfor declaration features:engine.rsmessage + handler,settings.rs/profile.rspersistence,api.rsroute, plus a webapp UI affordance inParams.tsx/Metrics's declaration form). - Use it to validate PromQL queries at evaluation time (e.g. warn or
reject
rate()on a declared gauge, orsum()/avg()directly on a declared counter without an innerrate()), and consider whether the current ad hocgauge()PromQL wrapper becomes redundant once the declaration itself carries this information (a bare selector on a declared gauge could just work the waygauge()does today).