diff --git a/filter/cache_storage.go b/filter/cache_storage.go index 077c5839d..077a8c306 100644 --- a/filter/cache_storage.go +++ b/filter/cache_storage.go @@ -2,6 +2,8 @@ package filter import ( "bufio" + "errors" + "fmt" "io" "regexp" "strconv" @@ -11,7 +13,12 @@ import ( "github.com/moira-alert/moira/metrics" ) -var defaultRetention = 60 +const defaultRetention = 60 + +var ( + invalidRetentionsFormatErr = errors.New("Invalid retentions format, it is correct to write in the format 'retentions = timePerPoint:timeToStore, timePerPoint:timeToStore, ...'") + invalidPatternFormatErr = errors.New("Invalid pattern format, it is correct to write in the format 'pattern = regex'") +) type retentionMatcher struct { pattern *regexp.Regexp @@ -82,33 +89,43 @@ func (storage *Storage) buildRetentions(retentionScanner *bufio.Scanner) error { storage.retentions = make([]retentionMatcher, 0, 100) for retentionScanner.Scan() { - line1 := retentionScanner.Text() - if strings.HasPrefix(line1, "#") || strings.Count(line1, "=") != 1 { + patternLine := retentionScanner.Text() + if strings.HasPrefix(patternLine, "#") || strings.Count(patternLine, "=") < 1 { continue } - patternString := strings.TrimSpace(strings.Split(line1, "=")[1]) + _, after, found := strings.Cut(patternLine, "=") + if !found { + storage.logger.Error(). + Error(invalidPatternFormatErr). + String("pattern_line", patternLine). + Msg("Invalid pattern format") + continue + } + + patternString := strings.TrimSpace(after) pattern, err := regexp.Compile(patternString) if err != nil { - return err + return fmt.Errorf("failed to compile regexp pattern '%s': %w", patternString, err) } retentionScanner.Scan() - line2 := retentionScanner.Text() - splitted := strings.Split(line2, "=") + retentionsLine := retentionScanner.Text() + splitted := strings.Split(retentionsLine, "=") if len(splitted) < 2 { //nolint storage.logger.Error(). - String("pattern", patternString). - Msg("Invalid pattern found") - + Error(invalidRetentionsFormatErr). + String("pattern_line", patternLine). + String("retentions_line", retentionsLine). + Msg("Invalid retentions format") continue } retentions := strings.TrimSpace(splitted[1]) retention, err := rawRetentionToSeconds(retentions[0:strings.Index(retentions, ":")]) if err != nil { - return err + return fmt.Errorf("failed to convert raw retentions '%s' to seconds: %w", retentions, err) } storage.retentions = append(storage.retentions, retentionMatcher{ diff --git a/filter/cache_storage_test.go b/filter/cache_storage_test.go index c0c3271e5..d3b3904e8 100644 --- a/filter/cache_storage_test.go +++ b/filter/cache_storage_test.go @@ -35,12 +35,16 @@ var testRetentions = ` pattern = yearly$ retentions = 1y:100y + [tagged metrics] + pattern = ;tag1=val1(;.*)?$ + retentions = 10s:2d,1m:30d,15m:1y + [default] pattern = .* retentions = 120:7d ` -var expectedRetentionIntervals = []int{60, 1200, 3600, 86400, 604800, 31536000, 120} +var expectedRetentionIntervals = []int{60, 1200, 3600, 86400, 604800, 31536000, 10, 120} var matchedMetrics = []moira.MatchedMetric{ { @@ -229,4 +233,36 @@ func TestRetentions(t *testing.T) { So(metr.Retention, ShouldEqual, 120) So(metr.RetentionTimestamp, ShouldEqual, 120) }) + + Convey("Tagged metrics", t, func() { + Convey("should be 10sec", func() { + matchedMetric := moira.MatchedMetric{ + Metric: "my_super_metric;tag1=val1;tag2=val2", + Value: 12, + Timestamp: 151, + RetentionTimestamp: 0, + Retention: 10, + } + buffer := make(map[string]*moira.MatchedMetric) + storage.EnrichMatchedMetric(buffer, &matchedMetric) + So(len(buffer), ShouldEqual, 1) + So(matchedMetric.Retention, ShouldEqual, 10) + So(matchedMetric.RetentionTimestamp, ShouldEqual, 150) + }) + + Convey("should be default 120sec", func() { + matchedMetric := moira.MatchedMetric{ + Metric: "my_super_metric;tag2=val2", + Value: 12, + Timestamp: 151, + RetentionTimestamp: 0, + Retention: 60, + } + buffer := make(map[string]*moira.MatchedMetric) + storage.EnrichMatchedMetric(buffer, &matchedMetric) + So(len(buffer), ShouldEqual, 1) + So(matchedMetric.Retention, ShouldEqual, 120) + So(matchedMetric.RetentionTimestamp, ShouldEqual, 120) + }) + }) }