-
Notifications
You must be signed in to change notification settings - Fork 0
/
utilities.go
207 lines (182 loc) · 5.4 KB
/
utilities.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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
package api
import (
"fmt"
"sort"
)
// DeepCopy returns a clone of the original Metrics. It provides a deep copy
// of both the key and the value of the original Hierarchy.
func (h Hierarchy) DeepCopy() Hierarchy {
clone := make(Hierarchy, len(h))
for k, v := range h {
var clonedV []string
clonedV = append(clonedV, v...)
clone[k] = clonedV
}
return clone
}
// AddHierarchyToMetrics takes the provided hierarchy structure, and uses it
// to determine how the metrics, m, are affected, incrementing parent metrics
// based on the value of the parents child/children metrics.
// Returns new Metrics, leaving metrics m in it's original state.
func (m Metrics) AddHierarchyToMetrics(hierarchy Hierarchy) Metrics {
metrics := m.DeepCopy()
for parent, children := range hierarchy {
for metric, v := range metrics {
if contains(metric, children) {
if _, known := metrics[parent]; known {
metrics.Add(parent, v)
} else {
metrics.Set(parent, v)
}
}
}
}
return metrics
}
// SubtractHierarchyFromMetrics takes the provided hierarchy structure, and uses it
// to determine how the metrics, m, are affected, decrementing parent metrics
// based on the value of the parents child/children metrics.
// Returns new Metrics, leaving metrics m in it's original state.
func (m Metrics) SubtractHierarchyFromMetrics(hierarchy Hierarchy) Metrics {
metrics := m.DeepCopy()
for parent, children := range hierarchy {
for metric, v := range metrics {
if contains(metric, children) {
if value, known := metrics[parent]; known {
newValue := value - v
if newValue < 0 {
delete(metrics, parent)
continue
}
metrics.Set(parent, newValue)
}
}
}
}
return metrics
}
// Add takes a provided key and value and adds them to the Metric 'm'
// If the metric already existed in 'm', then the value will be added (if positive) or subtracted (if negative) from the existing value.
// If a subtraction leads to a negative value Add returns an error and the change will be discarded.
// Returns the updated value (or current value in error cases) as well as the error.
func (m Metrics) Add(name string, value int) (int, error) {
if currentValue, ok := m[name]; ok {
newValue := currentValue + value
if newValue < 0 {
return currentValue, fmt.Errorf("invalid value for metric %s post computation. this will result in 403 from 3scale", name)
}
m[name] = newValue
return newValue, nil
}
m[name] = value
return value, nil
}
// Set takes a provided key and value and sets that value of the key in 'm', overwriting any value that exists previously.
func (m Metrics) Set(name string, value int) error {
if value < 0 {
return fmt.Errorf("invalid value for metric %s post computation. this will result in 403 from 3scale", name)
}
m[name] = value
return nil
}
// Delete a metric m['name'] if present
func (m Metrics) Delete(name string) {
delete(m, name)
}
// DeepCopy returns a clone of the original Metrics
func (m Metrics) DeepCopy() Metrics {
clone := make(Metrics, len(m))
for k, v := range m {
clone[k] = v
}
return clone
}
// String returns a string representation of the Period
func (p Period) String() string {
return [...]string{"minute", "hour", "day", "week", "month", "year", "eternity"}[p]
}
// IsEqual compares two PeriodWindows. They are equal if the period is the same
// and timestamps for start and end do not differ
func (pw PeriodWindow) IsEqual(window PeriodWindow) bool {
if pw != window {
return false
}
return true
}
func (ur UsageReport) IsForEternity() bool {
if ur.PeriodWindow.Period != Eternity {
return false
}
return true
}
func (ur UsageReport) IsForYear() bool {
if ur.PeriodWindow.Period != Year {
return false
}
return true
}
func (ur UsageReport) IsForMonth() bool {
if ur.PeriodWindow.Period != Month {
return false
}
return true
}
func (ur UsageReport) IsForWeek() bool {
if ur.PeriodWindow.Period != Week {
return false
}
return true
}
func (ur UsageReport) IsForDay() bool {
if ur.PeriodWindow.Period != Day {
return false
}
return true
}
func (ur UsageReport) IsForHour() bool {
if ur.PeriodWindow.Period != Hour {
return false
}
return true
}
func (ur UsageReport) IsForMinute() bool {
if ur.PeriodWindow.Period != Minute {
return false
}
return true
}
// IsSame does a comparison of two usage reports. They are considered the same only if their PeriodWindows are equal
// and the max value for the limit has not changed. Current limit values are ignored.
func (ur UsageReport) IsSame(usageReport UsageReport) bool {
if !ur.PeriodWindow.IsEqual(usageReport.PeriodWindow) {
return false
}
if ur.MaxValue != usageReport.MaxValue {
return false
}
return true
}
// OrderByAscendingGranularity sorts each slice in the usage reports in order of ascending granularity
func (urs UsageReports) OrderByAscendingGranularity() {
for _, reports := range urs {
sort.SliceStable(reports, func(i, j int) bool {
return reports[i].PeriodWindow.Period < reports[j].PeriodWindow.Period
})
}
}
// OrderByDescendingGranularity sorts each slice in the usage reports in order of descending granularity
func (urs UsageReports) OrderByDescendingGranularity() {
for _, reports := range urs {
sort.SliceStable(reports, func(i, j int) bool {
return reports[i].PeriodWindow.Period > reports[j].PeriodWindow.Period
})
}
}
func contains(key string, in []string) bool {
for _, i := range in {
if key == i {
return true
}
}
return false
}