mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-14 10:45:57 +08:00
feat: add support for not regex (#1328)
* feat: add support for not regex Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
This commit is contained in:
parent
091d769ad8
commit
da368ab5e8
@ -50,6 +50,7 @@ import (
|
|||||||
"go.signoz.io/query-service/constants"
|
"go.signoz.io/query-service/constants"
|
||||||
am "go.signoz.io/query-service/integrations/alertManager"
|
am "go.signoz.io/query-service/integrations/alertManager"
|
||||||
"go.signoz.io/query-service/model"
|
"go.signoz.io/query-service/model"
|
||||||
|
"go.signoz.io/query-service/utils"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -2829,6 +2830,10 @@ func (r *ClickHouseReader) GetMetricAutocompleteMetricNames(ctx context.Context,
|
|||||||
// GetMetricResult runs the query and returns list of time series
|
// GetMetricResult runs the query and returns list of time series
|
||||||
func (r *ClickHouseReader) GetMetricResult(ctx context.Context, query string) ([]*model.Series, error) {
|
func (r *ClickHouseReader) GetMetricResult(ctx context.Context, query string) ([]*model.Series, error) {
|
||||||
|
|
||||||
|
defer utils.Elapsed("GetMetricResult")()
|
||||||
|
|
||||||
|
zap.S().Infof("Executing metric result query: %s", query)
|
||||||
|
|
||||||
rows, err := r.db.Query(ctx, query)
|
rows, err := r.db.Query(ctx, query)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -180,10 +180,10 @@ func writeHttpResponse(w http.ResponseWriter, data interface{}) {
|
|||||||
}
|
}
|
||||||
func (aH *APIHandler) RegisterMetricsRoutes(router *mux.Router) {
|
func (aH *APIHandler) RegisterMetricsRoutes(router *mux.Router) {
|
||||||
subRouter := router.PathPrefix("/api/v2/metrics").Subrouter()
|
subRouter := router.PathPrefix("/api/v2/metrics").Subrouter()
|
||||||
subRouter.HandleFunc("/query_range", aH.queryRangeMetricsV2).Methods(http.MethodPost)
|
subRouter.HandleFunc("/query_range", ViewAccess(aH.queryRangeMetricsV2)).Methods(http.MethodPost)
|
||||||
subRouter.HandleFunc("/autocomplete/list", aH.metricAutocompleteMetricName).Methods(http.MethodGet)
|
subRouter.HandleFunc("/autocomplete/list", ViewAccess(aH.metricAutocompleteMetricName)).Methods(http.MethodGet)
|
||||||
subRouter.HandleFunc("/autocomplete/tagKey", aH.metricAutocompleteTagKey).Methods(http.MethodGet)
|
subRouter.HandleFunc("/autocomplete/tagKey", ViewAccess(aH.metricAutocompleteTagKey)).Methods(http.MethodGet)
|
||||||
subRouter.HandleFunc("/autocomplete/tagValue", aH.metricAutocompleteTagValue).Methods(http.MethodGet)
|
subRouter.HandleFunc("/autocomplete/tagValue", ViewAccess(aH.metricAutocompleteTagValue)).Methods(http.MethodGet)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (aH *APIHandler) respond(w http.ResponseWriter, data interface{}) {
|
func (aH *APIHandler) respond(w http.ResponseWriter, data interface{}) {
|
||||||
|
@ -91,10 +91,9 @@ func BuildMetricsTimeSeriesFilterQuery(fs *model.FilterSet, groupTags []string,
|
|||||||
if fs != nil && len(fs.Items) != 0 {
|
if fs != nil && len(fs.Items) != 0 {
|
||||||
for _, item := range fs.Items {
|
for _, item := range fs.Items {
|
||||||
toFormat := item.Value
|
toFormat := item.Value
|
||||||
|
op := strings.ToLower(strings.TrimSpace(item.Operator))
|
||||||
// if the received value is an array for like/match op, just take the first value
|
// if the received value is an array for like/match op, just take the first value
|
||||||
if strings.ToLower(item.Operation) == "like" ||
|
if op == "like" || op == "match" || op == "nlike" || op == "nmatch" {
|
||||||
strings.ToLower(item.Operation) == "match" ||
|
|
||||||
strings.ToLower(item.Operation) == "nlike" {
|
|
||||||
x, ok := item.Value.([]interface{})
|
x, ok := item.Value.([]interface{})
|
||||||
if ok {
|
if ok {
|
||||||
if len(x) == 0 {
|
if len(x) == 0 {
|
||||||
@ -104,7 +103,7 @@ func BuildMetricsTimeSeriesFilterQuery(fs *model.FilterSet, groupTags []string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmtVal := formattedValue(toFormat)
|
fmtVal := formattedValue(toFormat)
|
||||||
switch op := strings.ToLower(item.Operation); op {
|
switch op {
|
||||||
case "eq":
|
case "eq":
|
||||||
conditions = append(conditions, fmt.Sprintf("labels_object.%s = %s", item.Key, fmtVal))
|
conditions = append(conditions, fmt.Sprintf("labels_object.%s = %s", item.Key, fmtVal))
|
||||||
case "neq":
|
case "neq":
|
||||||
@ -119,6 +118,8 @@ func BuildMetricsTimeSeriesFilterQuery(fs *model.FilterSet, groupTags []string,
|
|||||||
conditions = append(conditions, fmt.Sprintf("notLike(labels_object.%s, %s)", item.Key, fmtVal))
|
conditions = append(conditions, fmt.Sprintf("notLike(labels_object.%s, %s)", item.Key, fmtVal))
|
||||||
case "match":
|
case "match":
|
||||||
conditions = append(conditions, fmt.Sprintf("match(labels_object.%s, %s)", item.Key, fmtVal))
|
conditions = append(conditions, fmt.Sprintf("match(labels_object.%s, %s)", item.Key, fmtVal))
|
||||||
|
case "nmatch":
|
||||||
|
conditions = append(conditions, fmt.Sprintf("not match(labels_object.%s, %s)", item.Key, fmtVal))
|
||||||
default:
|
default:
|
||||||
return "", fmt.Errorf("unsupported operation")
|
return "", fmt.Errorf("unsupported operation")
|
||||||
}
|
}
|
||||||
@ -416,6 +417,5 @@ func PrepareBuilderMetricQueries(qp *model.QueryRangeParamsV2, tableName string)
|
|||||||
if len(errs) != 0 {
|
if len(errs) != 0 {
|
||||||
return &RunQueries{Err: fmt.Errorf("errors with formulas: %s", FormatErrs(errs, "\n"))}
|
return &RunQueries{Err: fmt.Errorf("errors with formulas: %s", FormatErrs(errs, "\n"))}
|
||||||
}
|
}
|
||||||
fmt.Println(namedQueries)
|
|
||||||
return &RunQueries{Queries: namedQueries}
|
return &RunQueries{Queries: namedQueries}
|
||||||
}
|
}
|
||||||
|
@ -42,8 +42,9 @@ func TestBuildQueryWithFilters(t *testing.T) {
|
|||||||
"a": {
|
"a": {
|
||||||
QueryName: "a",
|
QueryName: "a",
|
||||||
MetricName: "name",
|
MetricName: "name",
|
||||||
TagFilters: &model.FilterSet{Operation: "AND", Items: []model.FilterItem{
|
TagFilters: &model.FilterSet{Operator: "AND", Items: []model.FilterItem{
|
||||||
{Key: "a", Value: "b", Operation: "neq"},
|
{Key: "a", Value: "b", Operator: "neq"},
|
||||||
|
{Key: "code", Value: "ERROR_*", Operator: "nmatch"},
|
||||||
}},
|
}},
|
||||||
AggregateOperator: model.RATE_MAX,
|
AggregateOperator: model.RATE_MAX,
|
||||||
Expression: "a",
|
Expression: "a",
|
||||||
@ -56,6 +57,7 @@ func TestBuildQueryWithFilters(t *testing.T) {
|
|||||||
|
|
||||||
So(queries["a"], ShouldContainSubstring, "WHERE metric_name = 'name' AND labels_object.a != 'b'")
|
So(queries["a"], ShouldContainSubstring, "WHERE metric_name = 'name' AND labels_object.a != 'b'")
|
||||||
So(queries["a"], ShouldContainSubstring, "runningDifference(value)/runningDifference(ts)")
|
So(queries["a"], ShouldContainSubstring, "runningDifference(value)/runningDifference(ts)")
|
||||||
|
So(queries["a"], ShouldContainSubstring, "not match(labels_object.code, 'ERROR_*')")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,8 +72,8 @@ func TestBuildQueryWithMultipleQueries(t *testing.T) {
|
|||||||
"a": {
|
"a": {
|
||||||
QueryName: "a",
|
QueryName: "a",
|
||||||
MetricName: "name",
|
MetricName: "name",
|
||||||
TagFilters: &model.FilterSet{Operation: "AND", Items: []model.FilterItem{
|
TagFilters: &model.FilterSet{Operator: "AND", Items: []model.FilterItem{
|
||||||
{Key: "in", Value: []interface{}{"a", "b", "c"}, Operation: "in"},
|
{Key: "in", Value: []interface{}{"a", "b", "c"}, Operator: "in"},
|
||||||
}},
|
}},
|
||||||
AggregateOperator: model.RATE_AVG,
|
AggregateOperator: model.RATE_AVG,
|
||||||
Expression: "a",
|
Expression: "a",
|
||||||
@ -103,8 +105,8 @@ func TestBuildQueryWithMultipleQueriesAndFormula(t *testing.T) {
|
|||||||
"a": {
|
"a": {
|
||||||
QueryName: "a",
|
QueryName: "a",
|
||||||
MetricName: "name",
|
MetricName: "name",
|
||||||
TagFilters: &model.FilterSet{Operation: "AND", Items: []model.FilterItem{
|
TagFilters: &model.FilterSet{Operator: "AND", Items: []model.FilterItem{
|
||||||
{Key: "in", Value: []interface{}{"a", "b", "c"}, Operation: "in"},
|
{Key: "in", Value: []interface{}{"a", "b", "c"}, Operator: "in"},
|
||||||
}},
|
}},
|
||||||
AggregateOperator: model.RATE_MAX,
|
AggregateOperator: model.RATE_MAX,
|
||||||
Expression: "a",
|
Expression: "a",
|
||||||
|
@ -294,17 +294,12 @@ type GetErrorParams struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type FilterItem struct {
|
type FilterItem struct {
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
Value interface{} `json:"value"`
|
Value interface{} `json:"value"`
|
||||||
Operation string `json:"op"`
|
Operator string `json:"op"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FilterSet struct {
|
type FilterSet struct {
|
||||||
Operation string `json:"op,omitempty"`
|
Operator string `json:"op,omitempty"`
|
||||||
Items []FilterItem `json:"items"`
|
Items []FilterItem `json:"items"`
|
||||||
}
|
|
||||||
|
|
||||||
type RemoveTTLParams struct {
|
|
||||||
Type string
|
|
||||||
RemoveAllTTL bool
|
|
||||||
}
|
}
|
||||||
|
14
pkg/query-service/utils/time.go
Normal file
14
pkg/query-service/utils/time.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Elapsed(funcName string) func() {
|
||||||
|
start := time.Now()
|
||||||
|
return func() {
|
||||||
|
zap.S().Infof("%s took %v\n", funcName, time.Since(start))
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user