mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-01-05 21:02:58 +00:00
feat: name label regex matcher in label values api (#6799)
* test: add failing test for #6791 * test: add support for = and =~ * fix: lint * fix: code merge issue Signed-off-by: Ning Sun <sunning@greptime.com> --------- Signed-off-by: Ning Sun <sunning@greptime.com>
This commit is contained in:
@@ -1002,30 +1002,11 @@ pub async fn label_values_query(
|
||||
|
||||
if label_name == METRIC_NAME_LABEL {
|
||||
let catalog_manager = handler.catalog_manager();
|
||||
let mut tables_stream = catalog_manager.tables(&catalog, &schema, Some(&query_ctx));
|
||||
let mut table_names = Vec::new();
|
||||
while let Some(table) = tables_stream.next().await {
|
||||
// filter out physical tables
|
||||
match table {
|
||||
Ok(table) => {
|
||||
if table
|
||||
.table_info()
|
||||
.meta
|
||||
.options
|
||||
.extra_options
|
||||
.contains_key(PHYSICAL_TABLE_METADATA_KEY)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
table_names.push(table.table_info().name.clone());
|
||||
}
|
||||
Err(e) => {
|
||||
return PrometheusJsonResponse::error(e.status_code(), e.output_msg());
|
||||
}
|
||||
}
|
||||
}
|
||||
table_names.sort_unstable();
|
||||
let mut table_names = try_call_return_response!(
|
||||
retrieve_table_names(&query_ctx, catalog_manager, params.matches.0).await
|
||||
);
|
||||
|
||||
truncate_results(&mut table_names, params.limit);
|
||||
return PrometheusJsonResponse::success(PrometheusResponse::LabelValues(table_names));
|
||||
} else if label_name == FIELD_NAME_LABEL {
|
||||
@@ -1040,17 +1021,11 @@ pub async fn label_values_query(
|
||||
} else if label_name == SCHEMA_LABEL || label_name == DATABASE_LABEL {
|
||||
let catalog_manager = handler.catalog_manager();
|
||||
|
||||
match retrieve_schema_names(&query_ctx, catalog_manager, params.matches.0).await {
|
||||
Ok(mut schema_names) => {
|
||||
truncate_results(&mut schema_names, params.limit);
|
||||
return PrometheusJsonResponse::success(PrometheusResponse::LabelValues(
|
||||
schema_names,
|
||||
));
|
||||
}
|
||||
Err(e) => {
|
||||
return PrometheusJsonResponse::error(e.status_code(), e.output_msg());
|
||||
}
|
||||
}
|
||||
let mut schema_names = try_call_return_response!(
|
||||
retrieve_schema_names(&query_ctx, catalog_manager, params.matches.0).await
|
||||
);
|
||||
truncate_results(&mut schema_names, params.limit);
|
||||
return PrometheusJsonResponse::success(PrometheusResponse::LabelValues(schema_names));
|
||||
}
|
||||
|
||||
let queries = params.matches.0;
|
||||
@@ -1136,6 +1111,77 @@ fn take_metric_name(selector: &mut VectorSelector) -> Option<String> {
|
||||
Some(name)
|
||||
}
|
||||
|
||||
async fn retrieve_table_names(
|
||||
query_ctx: &QueryContext,
|
||||
catalog_manager: CatalogManagerRef,
|
||||
matches: Vec<String>,
|
||||
) -> Result<Vec<String>> {
|
||||
let catalog = query_ctx.current_catalog();
|
||||
let schema = query_ctx.current_schema();
|
||||
|
||||
let mut tables_stream = catalog_manager.tables(catalog, &schema, Some(query_ctx));
|
||||
let mut table_names = Vec::new();
|
||||
|
||||
// we only provide very limited support for matcher against __name__
|
||||
let name_matcher = matches
|
||||
.first()
|
||||
.and_then(|matcher| promql_parser::parser::parse(matcher).ok())
|
||||
.and_then(|expr| {
|
||||
if let PromqlExpr::VectorSelector(vector_selector) = expr {
|
||||
let matchers = vector_selector.matchers.matchers;
|
||||
for matcher in matchers {
|
||||
if matcher.name == METRIC_NAME_LABEL {
|
||||
return Some(matcher);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
while let Some(table) = tables_stream.next().await {
|
||||
let table = table.context(CatalogSnafu)?;
|
||||
if table
|
||||
.table_info()
|
||||
.meta
|
||||
.options
|
||||
.extra_options
|
||||
.contains_key(PHYSICAL_TABLE_METADATA_KEY)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let table_name = &table.table_info().name;
|
||||
|
||||
if let Some(matcher) = &name_matcher {
|
||||
match &matcher.op {
|
||||
MatchOp::Equal => {
|
||||
if table_name == &matcher.value {
|
||||
table_names.push(table_name.clone());
|
||||
}
|
||||
}
|
||||
MatchOp::Re(reg) => {
|
||||
if reg.is_match(table_name) {
|
||||
table_names.push(table_name.clone());
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// != and !~ are not supported:
|
||||
// vector must contains at least one non-empty matcher
|
||||
table_names.push(table_name.clone());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
table_names.push(table_name.clone());
|
||||
}
|
||||
}
|
||||
|
||||
table_names.sort_unstable();
|
||||
Ok(table_names)
|
||||
}
|
||||
|
||||
async fn retrieve_field_names(
|
||||
query_ctx: &QueryContext,
|
||||
manager: CatalogManagerRef,
|
||||
|
||||
@@ -1104,15 +1104,51 @@ pub async fn test_prom_http_api(store_type: StorageType) {
|
||||
assert!(prom_resp.error_type.is_none());
|
||||
assert_eq!(
|
||||
prom_resp.data,
|
||||
PrometheusResponse::Labels(vec![
|
||||
"demo".to_string(),
|
||||
"demo_metrics".to_string(),
|
||||
"demo_metrics_with_nanos".to_string(),
|
||||
"logic_table".to_string(),
|
||||
"mito".to_string(),
|
||||
"multi_labels".to_string(),
|
||||
"numbers".to_string()
|
||||
])
|
||||
serde_json::from_value::<PrometheusResponse>(json!([
|
||||
"demo",
|
||||
"demo_metrics",
|
||||
"demo_metrics_with_nanos",
|
||||
"logic_table",
|
||||
"mito",
|
||||
"multi_labels",
|
||||
"numbers"
|
||||
]))
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
// query `__name__`
|
||||
let res = client
|
||||
.get("/v1/prometheus/api/v1/label/__name__/values?match[]={__name__=\"demo\"}")
|
||||
.send()
|
||||
.await;
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
let prom_resp = res.json::<PrometheusJsonResponse>().await;
|
||||
assert_eq!(prom_resp.status, "success");
|
||||
assert!(prom_resp.error.is_none());
|
||||
assert!(prom_resp.error_type.is_none());
|
||||
assert_eq!(
|
||||
prom_resp.data,
|
||||
serde_json::from_value::<PrometheusResponse>(json!(["demo",])).unwrap()
|
||||
);
|
||||
|
||||
// query `__name__`
|
||||
let res = client
|
||||
.get("/v1/prometheus/api/v1/label/__name__/values?match[]={__name__=~\".*demo.*\"}")
|
||||
.send()
|
||||
.await;
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
let prom_resp = res.json::<PrometheusJsonResponse>().await;
|
||||
assert_eq!(prom_resp.status, "success");
|
||||
assert!(prom_resp.error.is_none());
|
||||
assert!(prom_resp.error_type.is_none());
|
||||
assert_eq!(
|
||||
prom_resp.data,
|
||||
serde_json::from_value::<PrometheusResponse>(json!([
|
||||
"demo",
|
||||
"demo_metrics",
|
||||
"demo_metrics_with_nanos",
|
||||
]))
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
// buildinfo
|
||||
|
||||
Reference in New Issue
Block a user