fix: honor default prefix for all metric columns (#8640)

* fix: honor default prefix for metric columns

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* fix: cr issue

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

---------

Signed-off-by: shuiyisong <xixing.sys@gmail.com>
This commit is contained in:
shuiyisong
2026-07-27 07:35:28 +00:00
committed by GitHub
parent f5f5d468bb
commit b462d5d19e
19 changed files with 189 additions and 136 deletions
+42
View File
@@ -853,6 +853,7 @@ fn encode_summary(
#[cfg(test)]
mod tests {
use common_query::prelude::set_default_prefix;
use otel_arrow_rust::proto::opentelemetry::common::v1::AnyValue;
use otel_arrow_rust::proto::opentelemetry::common::v1::any_value::Value as Val;
use otel_arrow_rust::proto::opentelemetry::metrics::v1::number_data_point::Value;
@@ -1054,6 +1055,47 @@ mod tests {
);
}
#[test]
fn test_encode_legacy_summary_keeps_legacy_column_names() {
set_default_prefix(Some("custom")).unwrap();
let mut tables = MultiTableData::default();
let summary = Summary {
data_points: vec![SummaryDataPoint {
attributes: vec![keyvalue("host", "testserver")],
time_unix_nano: 100,
count: 25,
quantile_values: vec![ValueAtQuantile {
quantile: 0.90,
value: 1000.0,
}],
..Default::default()
}],
};
encode_summary(
&mut tables,
"datamon",
&summary,
None,
None,
&OtlpMetricCtx {
is_legacy: true,
..Default::default()
},
)
.unwrap();
let table = tables.get_or_default_table_data("datamon", 0, 0);
assert_eq!(
table
.columns()
.iter()
.map(|column| column.column_name.as_str())
.collect::<Vec<_>>(),
vec!["host", "custom_timestamp", "greptime_p90", GREPTIME_COUNT,]
);
}
#[test]
fn test_encode_histogram() {
let mut tables = MultiTableData::default();
+4 -2
View File
@@ -25,7 +25,7 @@ flowchart TD
J --> K["same metric-engine flag as samples, no batcher"]
K --> L["table: <metric>"]
L --> M["field: greptime_native_histogram Struct"]
L --> M["field: configured native-histogram Struct"]
M --> N["struct children: counts, spans, buckets, sum, schema"]
H --> P["written headers and counters"]
K --> P
@@ -41,7 +41,9 @@ Native histogram rows follow the same metric-engine switch as samples. They do
not use the pending rows batcher yet because the batcher assumes the classic
timestamp + Float64 value + string tags shape.
Each histogram row stores `greptime_native_histogram` as one Struct field:
Each histogram row stores one Struct field named
`<default_column_prefix>_native_histogram`. The default name is
`greptime_native_histogram`; an empty prefix produces `native_histogram`.
- common scalar children: `schema`, `zero_threshold`, `sum`, `reset_hint`,
`start_timestamp`;
+25 -9
View File
@@ -25,7 +25,7 @@ use api::v1::{ColumnSchema, ListValue, RowInsertRequest, Rows, SemanticType, Val
use bytes::Bytes;
use common_grpc::precision::Precision;
use common_query::native_histogram::*;
use common_query::prelude::{greptime_timestamp, greptime_value};
use common_query::prelude::{greptime_native_histogram, greptime_timestamp, greptime_value};
use pipeline::{ContextOpt, ContextReq};
use prost::Message;
use snafu::{OptionExt, ResultExt, ensure};
@@ -270,7 +270,7 @@ fn native_histogram_column_schema() -> ColumnSchema {
.into_parts();
ColumnSchema {
column_name: NATIVE_HISTOGRAM_FIELD.to_string(),
column_name: greptime_native_histogram().to_string(),
datatype: datatype as i32,
semantic_type: SemanticType::Field as i32,
datatype_extension,
@@ -400,7 +400,7 @@ fn ensure_no_internal_histogram_labels(tags: &PromTags) -> Result<()> {
// The histogram field column is generated from the protobuf payload.
for (name, _) in tags {
ensure!(
name != NATIVE_HISTOGRAM_FIELD,
name != greptime_native_histogram() && name != NATIVE_HISTOGRAM_FIELD,
error::InvalidPromRemoteRequestSnafu {
msg: format!(
"remote write v2 label `{name}` conflicts with an internal native histogram label"
@@ -625,7 +625,7 @@ mod tests {
use std::sync::Arc;
use api::v1::value::ValueData;
use common_query::prelude::{greptime_timestamp, greptime_value};
use common_query::prelude::{greptime_timestamp, greptime_value, set_default_prefix};
use session::context::QueryContext;
use super::*;
@@ -854,7 +854,7 @@ mod tests {
"internal histogram label on samples",
request_with_sample(vec![
(METRIC_NAME_LABEL, "metric"),
(NATIVE_HISTOGRAM_FIELD, "user_value"),
(greptime_native_histogram(), "user_value"),
]),
"conflicts with an internal native histogram label",
));
@@ -962,7 +962,7 @@ mod tests {
.iter()
.map(|col| col.column_name.as_str())
.collect::<Vec<_>>(),
vec![greptime_timestamp(), NATIVE_HISTOGRAM_FIELD]
vec![greptime_timestamp(), greptime_native_histogram()]
);
assert_eq!(
rows.rows[0].values[0].value_data,
@@ -1005,7 +1005,7 @@ mod tests {
let mut request = test_util::request_with_labels_and_samples(
vec![
(METRIC_NAME_LABEL, "metric"),
(NATIVE_HISTOGRAM_FIELD, "user_value"),
(greptime_native_histogram(), "user_value"),
],
vec![],
);
@@ -1021,6 +1021,22 @@ mod tests {
);
}
#[test]
fn test_rejects_legacy_histogram_label_after_prefix_change() {
set_default_prefix(Some("custom")).unwrap();
assert_eq!(greptime_native_histogram(), "custom_native_histogram");
let err = ensure_no_internal_histogram_labels(&vec![(
NATIVE_HISTOGRAM_FIELD.to_string(),
"user_value".to_string(),
)])
.unwrap_err();
assert!(
err.to_string()
.contains("conflicts with an internal native histogram label")
);
}
#[test]
fn test_into_context_req_converts_int_and_float_histograms_to_one_schema() {
let float_histogram = Histogram {
@@ -1070,7 +1086,7 @@ mod tests {
.iter()
.map(|col| col.column_name.as_str())
.collect::<Vec<_>>(),
vec![greptime_timestamp(), NATIVE_HISTOGRAM_FIELD]
vec![greptime_timestamp(), greptime_native_histogram()]
);
assert_eq!(
@@ -1138,7 +1154,7 @@ mod tests {
}
fn histogram_field_value(rows: &Rows, row_idx: usize, field_name: &str) -> Option<ValueData> {
let histogram_idx = column_index(&rows.schema, NATIVE_HISTOGRAM_FIELD);
let histogram_idx = column_index(&rows.schema, greptime_native_histogram());
let Some(ValueData::StructValue(histogram)) =
&rows.rows[row_idx].values[histogram_idx].value_data
else {
+4 -3
View File
@@ -28,8 +28,9 @@ use async_trait::async_trait;
use axum::Router;
use axum::http::HeaderMap;
use common_query::Output;
use common_query::native_histogram::NATIVE_HISTOGRAM_FIELD;
use common_query::prelude::{GREPTIME_PHYSICAL_TABLE, greptime_timestamp, greptime_value};
use common_query::prelude::{
GREPTIME_PHYSICAL_TABLE, greptime_native_histogram, greptime_timestamp, greptime_value,
};
use common_test_util::ports;
use datafusion_expr::LogicalPlan;
use prost::Message;
@@ -675,7 +676,7 @@ async fn test_prometheus_remote_write_v2_writes_histogram_only_series() {
assert!(
rows.schema
.iter()
.any(|column| column.column_name == NATIVE_HISTOGRAM_FIELD
.any(|column| column.column_name == greptime_native_histogram()
&& column.datatype == ColumnDataType::Struct as i32)
);
assert!(write_rx.try_recv().is_err());
@@ -18,10 +18,10 @@ use api::v1::value::ValueData;
use api::v1::{ColumnSchema, Rows};
use bytes::Bytes;
use common_query::native_histogram::{
COUNT_U64_FIELD, NATIVE_HISTOGRAM_FIELD, NATIVE_HISTOGRAM_FIELD_NAMES,
POSITIVE_BUCKETS_F64_FIELD, POSITIVE_BUCKETS_I64_FIELD, POSITIVE_SPAN_OFFSETS_FIELD,
SCHEMA_FIELD,
COUNT_U64_FIELD, NATIVE_HISTOGRAM_FIELD_NAMES, POSITIVE_BUCKETS_F64_FIELD,
POSITIVE_BUCKETS_I64_FIELD, POSITIVE_SPAN_OFFSETS_FIELD, SCHEMA_FIELD,
};
use common_query::prelude::greptime_native_histogram;
use servers::prom_remote_write::v2::test_util as remote_write_v2;
#[test]
@@ -126,7 +126,7 @@ fn column_index(schema: &[ColumnSchema], column_name: &str) -> usize {
}
fn histogram_field_value(rows: &Rows, row_idx: usize, field_name: &str) -> Option<ValueData> {
let histogram_idx = column_index(&rows.schema, NATIVE_HISTOGRAM_FIELD);
let histogram_idx = column_index(&rows.schema, greptime_native_histogram());
let Some(ValueData::StructValue(histogram)) =
&rows.rows[row_idx].values[histogram_idx].value_data
else {