This repository has been archived by the owner on Aug 23, 2023. It is now read-only.
/
indexrules.go
120 lines (105 loc) · 2.88 KB
/
indexrules.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package conf
import (
"fmt"
"regexp"
"strings"
"time"
"github.com/alyu/configparser"
"github.com/raintank/dur"
)
// IndexRules holds the index rule definitions
type IndexRules struct {
Rules []IndexRule
Default IndexRule
}
type IndexRule struct {
Name string
Pattern *regexp.Regexp
MaxStale time.Duration
}
// NewIndexRules create instance of IndexRules
// it has a default catchall that doesn't prune
func NewIndexRules() IndexRules {
return IndexRules{
Default: IndexRule{
Name: "default",
Pattern: regexp.MustCompile(""),
},
}
}
// ReadIndexRules returns the defined index rule from a index-rules.conf file
// and adds the default
func ReadIndexRules(file string) (IndexRules, error) {
config, err := configparser.Read(file)
if err != nil {
return IndexRules{}, err
}
sections, err := config.AllSections()
if err != nil {
return IndexRules{}, err
}
result := NewIndexRules()
for _, s := range sections {
item := IndexRule{}
item.Name = strings.Trim(strings.SplitN(s.String(), "\n", 2)[0], " []")
if item.Name == "" || strings.HasPrefix(item.Name, "#") {
continue
}
item.Pattern, err = regexp.Compile(s.ValueOf("pattern"))
if err != nil {
return IndexRules{}, fmt.Errorf("[%s]: failed to parse pattern %q: %s", item.Name, s.ValueOf("pattern"), err.Error())
}
duration, err := dur.ParseDuration(s.ValueOf("max-stale"))
if err != nil {
return IndexRules{}, fmt.Errorf("[%s]: failed to parse max-stale %q: %s", item.Name, s.ValueOf("max-stale"), err.Error())
}
item.MaxStale = time.Duration(duration) * time.Second
result.Rules = append(result.Rules, item)
}
return result, nil
}
// Match returns the correct index rule setting for the given metric
// it can always find a valid setting, because there's a default catch all
// also returns the index of the setting, to efficiently reference it
func (a IndexRules) Match(metric string) (uint16, IndexRule) {
for i, s := range a.Rules {
if s.Pattern.MatchString(metric) {
return uint16(i), s
}
}
return uint16(len(a.Rules)), a.Default
}
// Get returns the index rule setting corresponding to the given index
func (a IndexRules) Get(i uint16) IndexRule {
if i >= uint16(len(a.Rules)) {
return a.Default
}
return a.Rules[i]
}
// Prunable returns whether there's any entries that require pruning
func (a IndexRules) Prunable() bool {
for _, r := range a.Rules {
if r.MaxStale > 0 {
return true
}
}
return (a.Default.MaxStale > 0)
}
// Cutoffs returns a set of cutoffs corresponding to a given timestamp and the set of all rules
func (a IndexRules) Cutoffs(now time.Time) []int64 {
out := make([]int64, len(a.Rules)+1)
for i := 0; i <= len(a.Rules); i++ {
var rule IndexRule
if i < len(a.Rules) {
rule = a.Rules[i]
} else {
rule = a.Default
}
if rule.MaxStale == 0 {
out[i] = 0
} else {
out[i] = int64(now.Add(rule.MaxStale * -1).Unix())
}
}
return out
}