mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-11 11:48:58 +08:00
fix: add missed variable substitution for promql querires (#3584)
This commit is contained in:
parent
b0861f4fe0
commit
735ab8e118
@ -497,7 +497,7 @@ func PromFormattedValue(v interface{}) string {
|
|||||||
case float32, float64:
|
case float32, float64:
|
||||||
return fmt.Sprintf("%f", x)
|
return fmt.Sprintf("%f", x)
|
||||||
case string:
|
case string:
|
||||||
return fmt.Sprintf("%s", x)
|
return x
|
||||||
case bool:
|
case bool:
|
||||||
return fmt.Sprintf("%v", x)
|
return fmt.Sprintf("%v", x)
|
||||||
case []interface{}:
|
case []interface{}:
|
||||||
@ -506,7 +506,12 @@ func PromFormattedValue(v interface{}) string {
|
|||||||
}
|
}
|
||||||
switch x[0].(type) {
|
switch x[0].(type) {
|
||||||
case string, int, float32, float64, bool:
|
case string, int, float32, float64, bool:
|
||||||
return strings.Trim(strings.Join(strings.Fields(fmt.Sprint(x)), "|"), "[]")
|
// list of values joined by | for promql - a value can contain whitespace
|
||||||
|
var str []string
|
||||||
|
for _, sVal := range x {
|
||||||
|
str = append(str, fmt.Sprintf("%v", sVal))
|
||||||
|
}
|
||||||
|
return strings.Join(str, "|")
|
||||||
default:
|
default:
|
||||||
zap.L().Error("invalid type for prom formatted value", zap.Any("type", reflect.TypeOf(x[0])))
|
zap.L().Error("invalid type for prom formatted value", zap.Any("type", reflect.TypeOf(x[0])))
|
||||||
return ""
|
return ""
|
||||||
|
@ -1044,5 +1044,29 @@ func ParseQueryRangeParams(r *http.Request) (*v3.QueryRangeParamsV3, *model.ApiE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// replace go template variables in prometheus query
|
||||||
|
if queryRangeParams.CompositeQuery.QueryType == v3.QueryTypePromQL {
|
||||||
|
for _, promQuery := range queryRangeParams.CompositeQuery.PromQueries {
|
||||||
|
if promQuery.Disabled {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
tmpl := template.New("prometheus-query")
|
||||||
|
tmpl, err := tmpl.Parse(promQuery.Query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorBadData, Err: err}
|
||||||
|
}
|
||||||
|
var query bytes.Buffer
|
||||||
|
|
||||||
|
// replace go template variables
|
||||||
|
querytemplate.AssignReservedVarsV3(queryRangeParams)
|
||||||
|
|
||||||
|
err = tmpl.Execute(&query, queryRangeParams.Variables)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorBadData, Err: err}
|
||||||
|
}
|
||||||
|
promQuery.Query = query.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return queryRangeParams, nil
|
return queryRangeParams, nil
|
||||||
}
|
}
|
||||||
|
@ -757,3 +757,108 @@ func TestParseQueryRangeParamsDashboardVarsSubstitution(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseQueryRangeParamsPromQLVars(t *testing.T) {
|
||||||
|
reqCases := []struct {
|
||||||
|
desc string
|
||||||
|
compositeQuery v3.CompositeQuery
|
||||||
|
variables map[string]interface{}
|
||||||
|
expectErr bool
|
||||||
|
errMsg string
|
||||||
|
expectedQuery string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "valid prom query with dashboard variables",
|
||||||
|
compositeQuery: v3.CompositeQuery{
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
|
QueryType: v3.QueryTypePromQL,
|
||||||
|
PromQueries: map[string]*v3.PromQuery{
|
||||||
|
"A": {
|
||||||
|
Query: "http_calls_total{service_name=\"{{.service_name}}\", operation_name=~\"{{.operation_name}}\"}",
|
||||||
|
Disabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
variables: map[string]interface{}{
|
||||||
|
"service_name": "route",
|
||||||
|
"operation_name": []interface{}{
|
||||||
|
"GET /route",
|
||||||
|
"POST /route",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectErr: false,
|
||||||
|
expectedQuery: "http_calls_total{service_name=\"route\", operation_name=~\"GET /route|POST /route\"}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "valid prom query with dashboard variables",
|
||||||
|
compositeQuery: v3.CompositeQuery{
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
|
QueryType: v3.QueryTypePromQL,
|
||||||
|
PromQueries: map[string]*v3.PromQuery{
|
||||||
|
"A": {
|
||||||
|
Query: "http_calls_total{service_name=\"{{.service_name}}\", status_code=~\"{{.status_code}}\"}",
|
||||||
|
Disabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
variables: map[string]interface{}{
|
||||||
|
"service_name": "route",
|
||||||
|
"status_code": []interface{}{
|
||||||
|
200,
|
||||||
|
505,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectErr: false,
|
||||||
|
expectedQuery: "http_calls_total{service_name=\"route\", status_code=~\"200|505\"}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "valid prom query with dashboard variables",
|
||||||
|
compositeQuery: v3.CompositeQuery{
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
|
QueryType: v3.QueryTypePromQL,
|
||||||
|
PromQueries: map[string]*v3.PromQuery{
|
||||||
|
"A": {
|
||||||
|
Query: "http_calls_total{service_name=\"{{.service_name}}\", quantity=~\"{{.quantity}}\"}",
|
||||||
|
Disabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
variables: map[string]interface{}{
|
||||||
|
"service_name": "route",
|
||||||
|
"quantity": []interface{}{
|
||||||
|
4.5,
|
||||||
|
4.6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectErr: false,
|
||||||
|
expectedQuery: "http_calls_total{service_name=\"route\", quantity=~\"4.5|4.6\"}",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range reqCases {
|
||||||
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
|
|
||||||
|
queryRangeParams := &v3.QueryRangeParamsV3{
|
||||||
|
Start: time.Now().Add(-time.Hour).UnixMilli(),
|
||||||
|
End: time.Now().UnixMilli(),
|
||||||
|
Step: time.Minute.Microseconds(),
|
||||||
|
CompositeQuery: &tc.compositeQuery,
|
||||||
|
Variables: tc.variables,
|
||||||
|
}
|
||||||
|
|
||||||
|
body := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(body).Encode(queryRangeParams)
|
||||||
|
require.NoError(t, err)
|
||||||
|
req := httptest.NewRequest(http.MethodPost, "/api/v3/query_range", body)
|
||||||
|
|
||||||
|
parsedQueryRangeParams, apiErr := ParseQueryRangeParams(req)
|
||||||
|
if tc.expectErr {
|
||||||
|
require.Error(t, apiErr)
|
||||||
|
require.Contains(t, apiErr.Error(), tc.errMsg)
|
||||||
|
} else {
|
||||||
|
require.Nil(t, apiErr)
|
||||||
|
require.Equal(t, parsedQueryRangeParams.CompositeQuery.PromQueries["A"].Query, tc.expectedQuery)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user