Skip to content

Commit

Permalink
Track number of optimised regexp label matchers (#4813)
Browse files Browse the repository at this point in the history
* Track number of optimised regexp label matchers

Signed-off-by: dhanu <andreasdhanu@gmail.com>

* track-number-of-optimised-regexp-label-matchers - add changelog

* track-number-of-optimised-regexp-label-matchers - revert

* track-number-of-optimised-regexp-label-matchers - fix review

* track-number-of-optimised-regexp-label-matchers - fix

* track-number-of-optimised-regexp-label-matchers - rebase main

* track-number-of-optimised-regexp-label-matchers - rebase main

---------

Signed-off-by: dhanu <andreasdhanu@gmail.com>
Co-authored-by: Marco Pracucci <marco@pracucci.com>
  • Loading branch information
dhanusaputra and pracucci authored May 29, 2023
1 parent bdd80b6 commit 3543b63
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
* [ENHANCEMENT] Add native histogram support for `cortex_request_duration_seconds` metric family. #4987
* [ENHANCEMENT] Ruler: do not list rule groups in the object storage for disabled tenants. #5004
* [ENHANCEMENT] Query-frontend and querier: add HTTP API endpoint `<prometheus-http-prefix>/api/v1/format_query` to format a PromQL query. #4373
* [ENHANCEMENT] Query-frontend: Add `cortex_query_frontend_regexp_matcher_count` and `cortex_query_frontend_regexp_matcher_optimized_count` metrics to track optimization of regular expression label matchers. #4813
* [ENHANCEMENT] Alertmanager: Add configuration option to enable or disable the deletion of alertmanager state from object storage. This is useful when migrating alertmanager tenants from one cluster to another, because it avoids a condition where the state object is copied but then deleted before the configuration object is copied. #4989
* [ENHANCEMENT] Querier: only use the minimum set of chunks from ingesters when querying, and cancel unnecessary requests to ingesters sooner if we know their results won't be used. #5016
* [ENHANCEMENT] Add `-enable-go-runtime-metrics` flag to expose all go runtime metrics as Prometheus metrics. #5009
Expand Down
37 changes: 33 additions & 4 deletions pkg/frontend/querymiddleware/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,37 @@ import (

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prometheus/prometheus/model/labels"
"github.com/prometheus/prometheus/promql/parser"
)

type queryStatsMiddleware struct {
nonAlignedQueries prometheus.Counter
next Handler
nonAlignedQueries prometheus.Counter
regexpMatcherCount prometheus.Counter
regexpMatcherOptimizedCount prometheus.Counter
next Handler
}

func newQueryStatsMiddleware(reg prometheus.Registerer) Middleware {
nonAlignedQueries := promauto.With(reg).NewCounter(prometheus.CounterOpts{
Name: "cortex_query_frontend_non_step_aligned_queries_total",
Help: "Total queries sent that are not step aligned.",
})
regexpMatcherCount := promauto.With(reg).NewCounter(prometheus.CounterOpts{
Name: "cortex_query_frontend_regexp_matcher_count",
Help: "Total number of regexp matchers",
})
regexpMatcherOptimizedCount := promauto.With(reg).NewCounter(prometheus.CounterOpts{
Name: "cortex_query_frontend_regexp_matcher_optimized_count",
Help: "Total number of optimized regexp matchers",
})

return MiddlewareFunc(func(next Handler) Handler {
return &queryStatsMiddleware{
nonAlignedQueries: nonAlignedQueries,
next: next,
nonAlignedQueries: nonAlignedQueries,
regexpMatcherCount: regexpMatcherCount,
regexpMatcherOptimizedCount: regexpMatcherOptimizedCount,
next: next,
}
})
}
Expand All @@ -33,5 +47,20 @@ func (s queryStatsMiddleware) Do(ctx context.Context, req Request) (Response, er
s.nonAlignedQueries.Inc()
}

if expr, err := parser.ParseExpr(req.GetQuery()); err == nil {
for _, selectors := range parser.ExtractSelectors(expr) {
for _, matcher := range selectors {
if matcher.Type != labels.MatchRegexp && matcher.Type != labels.MatchNotRegexp {
continue
}

s.regexpMatcherCount.Inc()
if matcher.IsRegexOptimized() {
s.regexpMatcherOptimizedCount.Inc()
}
}
}
}

return s.next.Do(ctx, req)
}
84 changes: 84 additions & 0 deletions pkg/frontend/querymiddleware/stats_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// SPDX-License-Identifier: AGPL-3.0-only

package querymiddleware

import (
"context"
"strings"
"testing"

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/weaveworks/common/user"

"github.com/grafana/mimir/pkg/util"
)

func Test_queryStatsMiddleware_Do(t *testing.T) {
type args struct {
req Request
}
tests := []struct {
name string
args args
expectedMetrics *strings.Reader
}{
{
name: "happy path",
args: args{
req: &PrometheusRangeQueryRequest{
Path: "/query_range",
Start: util.TimeToMillis(start),
End: util.TimeToMillis(end),
Step: step.Milliseconds(),
Query: `sum(sum_over_time(metric{app="test",namespace=~"short"}[5m]))`,
},
},
expectedMetrics: strings.NewReader(`
# HELP cortex_query_frontend_non_step_aligned_queries_total Total queries sent that are not step aligned.
# TYPE cortex_query_frontend_non_step_aligned_queries_total counter
cortex_query_frontend_non_step_aligned_queries_total 1
# HELP cortex_query_frontend_regexp_matcher_count Total number of regexp matchers
# TYPE cortex_query_frontend_regexp_matcher_count counter
cortex_query_frontend_regexp_matcher_count 1
# HELP cortex_query_frontend_regexp_matcher_optimized_count Total number of optimized regexp matchers
# TYPE cortex_query_frontend_regexp_matcher_optimized_count counter
cortex_query_frontend_regexp_matcher_optimized_count 1
`),
},
{
name: "parseExpr failed",
args: args{
req: &PrometheusRangeQueryRequest{
Path: "/query_range",
Start: util.TimeToMillis(start),
End: util.TimeToMillis(end),
Step: step.Milliseconds(),
Query: `?`,
},
},
expectedMetrics: strings.NewReader(`
# HELP cortex_query_frontend_non_step_aligned_queries_total Total queries sent that are not step aligned.
# TYPE cortex_query_frontend_non_step_aligned_queries_total counter
cortex_query_frontend_non_step_aligned_queries_total 1
# HELP cortex_query_frontend_regexp_matcher_count Total number of regexp matchers
# TYPE cortex_query_frontend_regexp_matcher_count counter
cortex_query_frontend_regexp_matcher_count 0
# HELP cortex_query_frontend_regexp_matcher_optimized_count Total number of optimized regexp matchers
# TYPE cortex_query_frontend_regexp_matcher_optimized_count counter
cortex_query_frontend_regexp_matcher_optimized_count 0
`),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
reg := prometheus.NewPedanticRegistry()
mw := newQueryStatsMiddleware(reg)
_, err := mw.Wrap(mockHandlerWith(nil, nil)).Do(user.InjectOrgID(context.Background(), "test"), tt.args.req)
require.NoError(t, err)
assert.NoError(t, testutil.GatherAndCompare(reg, tt.expectedMetrics))
})
}
}

0 comments on commit 3543b63

Please sign in to comment.