forked from go-graphite/go-carbon
/
whisper_schema.go
146 lines (123 loc) · 3.78 KB
/
whisper_schema.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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package persister
/*
Schemas read code from https://github.com/grobian/carbonwriter/
*/
import (
"fmt"
"regexp"
"sort"
"strconv"
"strings"
"github.com/Sirupsen/logrus"
"github.com/alyu/configparser"
"github.com/lomik/go-whisper"
)
type whisperSchemaItem struct {
name string
pattern *regexp.Regexp
retentionStr string
retentions whisper.Retentions
priority int64
}
type whisperSchemaItemByPriority []*whisperSchemaItem
func (v whisperSchemaItemByPriority) Len() int { return len(v) }
func (v whisperSchemaItemByPriority) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
func (v whisperSchemaItemByPriority) Less(i, j int) bool { return v[i].priority >= v[j].priority }
// WhisperSchemas ...
type WhisperSchemas struct {
Data []*whisperSchemaItem
}
// ParseRetentionDefs copy of original ParseRetentionDefs from go-whisper
// With support where old format:
// secondsPerPoint:numberOfPoints
func ParseRetentionDefs(retentionDefs string) (whisper.Retentions, error) {
retentions := make(whisper.Retentions, 0)
for _, retentionDef := range strings.Split(retentionDefs, ",") {
retentionDef = strings.TrimSpace(retentionDef)
// check if old format
row := strings.Split(retentionDef, ":")
if len(row) == 2 {
val1, err1 := strconv.ParseInt(row[0], 10, 0)
val2, err2 := strconv.ParseInt(row[1], 10, 0)
if err1 == nil && err2 == nil {
retentionDef = fmt.Sprintf("%d:%d", val1, val1*val2)
}
}
// new format
retention, err := whisper.ParseRetentionDef(retentionDef)
if err != nil {
return nil, err
}
retentions = append(retentions, retention)
}
return retentions, nil
}
// NewWhisperSchemas create instance of WhisperSchemas
func NewWhisperSchemas() *WhisperSchemas {
return &WhisperSchemas{
Data: make([]*whisperSchemaItem, 0),
}
}
// ReadWhisperSchemas ...
func ReadWhisperSchemas(file string) (*WhisperSchemas, error) {
config, err := configparser.Read(file)
if err != nil {
return nil, err
}
sections, err := config.AllSections()
if err != nil {
return nil, err
}
result := NewWhisperSchemas()
for index, s := range sections {
item := &whisperSchemaItem{}
// this is mildly stupid, but I don't feel like forking
// configparser just for this
item.name =
strings.Trim(strings.SplitN(s.String(), "\n", 2)[0], " []")
if item.name == "" || strings.HasPrefix(item.name, "#") {
continue
}
patternStr := s.ValueOf("pattern")
if patternStr == "" {
return nil, fmt.Errorf("[persister] Empty pattern '%s' for [%s]", item.name)
}
item.pattern, err = regexp.Compile(patternStr)
if err != nil {
return nil, fmt.Errorf("[persister] Failed to parse pattern '%s' for [%s]: %s",
s.ValueOf("pattern"), item.name, err.Error())
}
item.retentionStr = s.ValueOf("retentions")
item.retentions, err = ParseRetentionDefs(item.retentionStr)
if err != nil {
return nil, fmt.Errorf("[persister] Failed to parse retentions '%s' for [%s]: %s",
s.ValueOf("retentions"), item.name, err.Error())
}
priorityStr := s.ValueOf("priority")
var p int64
if priorityStr == "" {
p = 0
} else {
p, err = strconv.ParseInt(priorityStr, 10, 0)
if err != nil {
return nil, fmt.Errorf("[persister] wrong priority in schema: %s", err)
}
}
item.priority = int64(p)<<32 - int64(index) // for sort records with same priority
// item.priority = (s.ValueOf("priority"))
logrus.Debugf("[persister] Adding schema [%s] pattern = %s retentions = %s",
item.name, s.ValueOf("pattern"), item.retentionStr)
result.Data = append(result.Data, item)
}
sort.Sort(whisperSchemaItemByPriority(result.Data))
return result, nil
}
// Match find schema for metric
func (s *WhisperSchemas) match(metric string) *whisperSchemaItem {
for _, s := range s.Data {
if s.pattern.MatchString(metric) {
return s
}
}
return nil
}