Add gauge/counter semantics to metric declarations (ticket 097)
Metrics previously only declared a data type (String/Number/...), so rate() could be applied to a point-in-time gauge reading and sum()/avg() could be applied directly to a cumulative counter reading with no guard against either. Adds a MetricSemantics enum (Gauge, default; Counter) threaded through DeclareMetricRequest, the engine's MetricDeclaration data value, profile persistence, the API/MCP declaration routes, and the Metrics panel's declaration form, then uses it in evaluate_promql to reject rate() on a declared gauge and bare sum()/avg() on a declared counter (suggesting rate() first). The guard only applies to metrics with a captured value_param — bare occurrence-count metrics are always safe under both operations, so existing dashboards are unaffected. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TeyhRfMYjMditek6geDRoQ
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
c3108677ce
commit
4a0fe92ce8
@@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::config::Settings;
|
||||
use crate::consts::{DEFAULT_PROFILE_NAME, SEEDED_METRIC_LABEL, SEEDED_METRIC_NAME};
|
||||
use crate::engine::data_value::MetricPrimitiveKind;
|
||||
use crate::engine::data_value::{MetricPrimitiveKind, MetricSemantics};
|
||||
use crate::engine::{DeclareMetricRequest, DeclareParamRequest, EngineHandle, EngineMessage};
|
||||
use tokio::sync::oneshot;
|
||||
|
||||
@@ -122,6 +122,8 @@ pub struct MetricDeclarationRecord {
|
||||
pub matched_labels: Option<std::collections::BTreeMap<String, String>>,
|
||||
#[serde(default)]
|
||||
pub unmatched_labels: Option<std::collections::BTreeMap<String, String>>,
|
||||
#[serde(default)]
|
||||
pub semantics: MetricSemantics,
|
||||
#[serde(default, rename = "params", skip_serializing_if = "Vec::is_empty")]
|
||||
legacy_params: Vec<LegacyMetricParamRecord>,
|
||||
}
|
||||
@@ -135,6 +137,7 @@ impl From<&DeclareMetricRequest> for MetricDeclarationRecord {
|
||||
value_param: request.value_param.clone(),
|
||||
matched_labels: request.matched_labels.clone(),
|
||||
unmatched_labels: request.unmatched_labels.clone(),
|
||||
semantics: request.semantics,
|
||||
legacy_params: Vec::new(),
|
||||
}
|
||||
}
|
||||
@@ -149,6 +152,7 @@ impl From<&MetricDeclarationRecord> for DeclareMetricRequest {
|
||||
value_param: record.value_param.clone(),
|
||||
matched_labels: record.matched_labels.clone(),
|
||||
unmatched_labels: record.unmatched_labels.clone(),
|
||||
semantics: record.semantics,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -295,6 +299,7 @@ impl MetricDeclarationRecord {
|
||||
SEEDED_METRIC_LABEL.to_string(),
|
||||
"other".to_string(),
|
||||
)])),
|
||||
semantics: MetricSemantics::default(),
|
||||
legacy_params: Vec::new(),
|
||||
}
|
||||
}
|
||||
@@ -741,6 +746,7 @@ mod tests {
|
||||
unmatched_labels: None,
|
||||
label_params: vec![param_name.to_string()],
|
||||
value_param: None,
|
||||
semantics: MetricSemantics::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user