1 | // Copyright 2019 The Go Authors. All rights reserved. |
---|---|
2 | // Use of this source code is governed by a BSD-style |
3 | // license that can be found in the LICENSE file. |
4 | |
5 | package metric |
6 | |
7 | import ( |
8 | "fmt" |
9 | "sort" |
10 | "time" |
11 | |
12 | "golang.org/x/tools/internal/event/keys" |
13 | "golang.org/x/tools/internal/event/label" |
14 | ) |
15 | |
16 | // Data represents a single point in the time series of a metric. |
17 | // This provides the common interface to all metrics no matter their data |
18 | // format. |
19 | // To get the actual values for the metric you must type assert to a concrete |
20 | // metric type. |
21 | type Data interface { |
22 | // Handle returns the metric handle this data is for. |
23 | //TODO: rethink the concept of metric handles |
24 | Handle() string |
25 | // Groups reports the rows that currently exist for this metric. |
26 | Groups() [][]label.Label |
27 | } |
28 | |
29 | // Int64Data is a concrete implementation of Data for int64 scalar metrics. |
30 | type Int64Data struct { |
31 | // Info holds the original construction information. |
32 | Info *Scalar |
33 | // IsGauge is true for metrics that track values, rather than increasing over time. |
34 | IsGauge bool |
35 | // Rows holds the per group values for the metric. |
36 | Rows []int64 |
37 | // End is the last time this metric was updated. |
38 | EndTime time.Time |
39 | |
40 | groups [][]label.Label |
41 | key *keys.Int64 |
42 | } |
43 | |
44 | // Float64Data is a concrete implementation of Data for float64 scalar metrics. |
45 | type Float64Data struct { |
46 | // Info holds the original construction information. |
47 | Info *Scalar |
48 | // IsGauge is true for metrics that track values, rather than increasing over time. |
49 | IsGauge bool |
50 | // Rows holds the per group values for the metric. |
51 | Rows []float64 |
52 | // End is the last time this metric was updated. |
53 | EndTime time.Time |
54 | |
55 | groups [][]label.Label |
56 | key *keys.Float64 |
57 | } |
58 | |
59 | // HistogramInt64Data is a concrete implementation of Data for int64 histogram metrics. |
60 | type HistogramInt64Data struct { |
61 | // Info holds the original construction information. |
62 | Info *HistogramInt64 |
63 | // Rows holds the per group values for the metric. |
64 | Rows []*HistogramInt64Row |
65 | // End is the last time this metric was updated. |
66 | EndTime time.Time |
67 | |
68 | groups [][]label.Label |
69 | key *keys.Int64 |
70 | } |
71 | |
72 | // HistogramInt64Row holds the values for a single row of a HistogramInt64Data. |
73 | type HistogramInt64Row struct { |
74 | // Values is the counts per bucket. |
75 | Values []int64 |
76 | // Count is the total count. |
77 | Count int64 |
78 | // Sum is the sum of all the values recorded. |
79 | Sum int64 |
80 | // Min is the smallest recorded value. |
81 | Min int64 |
82 | // Max is the largest recorded value. |
83 | Max int64 |
84 | } |
85 | |
86 | // HistogramFloat64Data is a concrete implementation of Data for float64 histogram metrics. |
87 | type HistogramFloat64Data struct { |
88 | // Info holds the original construction information. |
89 | Info *HistogramFloat64 |
90 | // Rows holds the per group values for the metric. |
91 | Rows []*HistogramFloat64Row |
92 | // End is the last time this metric was updated. |
93 | EndTime time.Time |
94 | |
95 | groups [][]label.Label |
96 | key *keys.Float64 |
97 | } |
98 | |
99 | // HistogramFloat64Row holds the values for a single row of a HistogramFloat64Data. |
100 | type HistogramFloat64Row struct { |
101 | // Values is the counts per bucket. |
102 | Values []int64 |
103 | // Count is the total count. |
104 | Count int64 |
105 | // Sum is the sum of all the values recorded. |
106 | Sum float64 |
107 | // Min is the smallest recorded value. |
108 | Min float64 |
109 | // Max is the largest recorded value. |
110 | Max float64 |
111 | } |
112 | |
113 | func labelListEqual(a, b []label.Label) bool { |
114 | //TODO: make this more efficient |
115 | return fmt.Sprint(a) == fmt.Sprint(b) |
116 | } |
117 | |
118 | func labelListLess(a, b []label.Label) bool { |
119 | //TODO: make this more efficient |
120 | return fmt.Sprint(a) < fmt.Sprint(b) |
121 | } |
122 | |
123 | func getGroup(lm label.Map, g *[][]label.Label, keys []label.Key) (int, bool) { |
124 | group := make([]label.Label, len(keys)) |
125 | for i, key := range keys { |
126 | l := lm.Find(key) |
127 | if l.Valid() { |
128 | group[i] = l |
129 | } |
130 | } |
131 | old := *g |
132 | index := sort.Search(len(old), func(i int) bool { |
133 | return !labelListLess(old[i], group) |
134 | }) |
135 | if index < len(old) && labelListEqual(group, old[index]) { |
136 | // not a new group |
137 | return index, false |
138 | } |
139 | *g = make([][]label.Label, len(old)+1) |
140 | copy(*g, old[:index]) |
141 | copy((*g)[index+1:], old[index:]) |
142 | (*g)[index] = group |
143 | return index, true |
144 | } |
145 | |
146 | func (data *Int64Data) Handle() string { return data.Info.Name } |
147 | func (data *Int64Data) Groups() [][]label.Label { return data.groups } |
148 | |
149 | func (data *Int64Data) modify(at time.Time, lm label.Map, f func(v int64) int64) Data { |
150 | index, insert := getGroup(lm, &data.groups, data.Info.Keys) |
151 | old := data.Rows |
152 | if insert { |
153 | data.Rows = make([]int64, len(old)+1) |
154 | copy(data.Rows, old[:index]) |
155 | copy(data.Rows[index+1:], old[index:]) |
156 | } else { |
157 | data.Rows = make([]int64, len(old)) |
158 | copy(data.Rows, old) |
159 | } |
160 | data.Rows[index] = f(data.Rows[index]) |
161 | data.EndTime = at |
162 | frozen := *data |
163 | return &frozen |
164 | } |
165 | |
166 | func (data *Int64Data) count(at time.Time, lm label.Map, l label.Label) Data { |
167 | return data.modify(at, lm, func(v int64) int64 { |
168 | return v + 1 |
169 | }) |
170 | } |
171 | |
172 | func (data *Int64Data) sum(at time.Time, lm label.Map, l label.Label) Data { |
173 | return data.modify(at, lm, func(v int64) int64 { |
174 | return v + data.key.From(l) |
175 | }) |
176 | } |
177 | |
178 | func (data *Int64Data) latest(at time.Time, lm label.Map, l label.Label) Data { |
179 | return data.modify(at, lm, func(v int64) int64 { |
180 | return data.key.From(l) |
181 | }) |
182 | } |
183 | |
184 | func (data *Float64Data) Handle() string { return data.Info.Name } |
185 | func (data *Float64Data) Groups() [][]label.Label { return data.groups } |
186 | |
187 | func (data *Float64Data) modify(at time.Time, lm label.Map, f func(v float64) float64) Data { |
188 | index, insert := getGroup(lm, &data.groups, data.Info.Keys) |
189 | old := data.Rows |
190 | if insert { |
191 | data.Rows = make([]float64, len(old)+1) |
192 | copy(data.Rows, old[:index]) |
193 | copy(data.Rows[index+1:], old[index:]) |
194 | } else { |
195 | data.Rows = make([]float64, len(old)) |
196 | copy(data.Rows, old) |
197 | } |
198 | data.Rows[index] = f(data.Rows[index]) |
199 | data.EndTime = at |
200 | frozen := *data |
201 | return &frozen |
202 | } |
203 | |
204 | func (data *Float64Data) sum(at time.Time, lm label.Map, l label.Label) Data { |
205 | return data.modify(at, lm, func(v float64) float64 { |
206 | return v + data.key.From(l) |
207 | }) |
208 | } |
209 | |
210 | func (data *Float64Data) latest(at time.Time, lm label.Map, l label.Label) Data { |
211 | return data.modify(at, lm, func(v float64) float64 { |
212 | return data.key.From(l) |
213 | }) |
214 | } |
215 | |
216 | func (data *HistogramInt64Data) Handle() string { return data.Info.Name } |
217 | func (data *HistogramInt64Data) Groups() [][]label.Label { return data.groups } |
218 | |
219 | func (data *HistogramInt64Data) modify(at time.Time, lm label.Map, f func(v *HistogramInt64Row)) Data { |
220 | index, insert := getGroup(lm, &data.groups, data.Info.Keys) |
221 | old := data.Rows |
222 | var v HistogramInt64Row |
223 | if insert { |
224 | data.Rows = make([]*HistogramInt64Row, len(old)+1) |
225 | copy(data.Rows, old[:index]) |
226 | copy(data.Rows[index+1:], old[index:]) |
227 | } else { |
228 | data.Rows = make([]*HistogramInt64Row, len(old)) |
229 | copy(data.Rows, old) |
230 | v = *data.Rows[index] |
231 | } |
232 | oldValues := v.Values |
233 | v.Values = make([]int64, len(data.Info.Buckets)) |
234 | copy(v.Values, oldValues) |
235 | f(&v) |
236 | data.Rows[index] = &v |
237 | data.EndTime = at |
238 | frozen := *data |
239 | return &frozen |
240 | } |
241 | |
242 | func (data *HistogramInt64Data) record(at time.Time, lm label.Map, l label.Label) Data { |
243 | return data.modify(at, lm, func(v *HistogramInt64Row) { |
244 | value := data.key.From(l) |
245 | v.Sum += value |
246 | if v.Min > value || v.Count == 0 { |
247 | v.Min = value |
248 | } |
249 | if v.Max < value || v.Count == 0 { |
250 | v.Max = value |
251 | } |
252 | v.Count++ |
253 | for i, b := range data.Info.Buckets { |
254 | if value <= b { |
255 | v.Values[i]++ |
256 | } |
257 | } |
258 | }) |
259 | } |
260 | |
261 | func (data *HistogramFloat64Data) Handle() string { return data.Info.Name } |
262 | func (data *HistogramFloat64Data) Groups() [][]label.Label { return data.groups } |
263 | |
264 | func (data *HistogramFloat64Data) modify(at time.Time, lm label.Map, f func(v *HistogramFloat64Row)) Data { |
265 | index, insert := getGroup(lm, &data.groups, data.Info.Keys) |
266 | old := data.Rows |
267 | var v HistogramFloat64Row |
268 | if insert { |
269 | data.Rows = make([]*HistogramFloat64Row, len(old)+1) |
270 | copy(data.Rows, old[:index]) |
271 | copy(data.Rows[index+1:], old[index:]) |
272 | } else { |
273 | data.Rows = make([]*HistogramFloat64Row, len(old)) |
274 | copy(data.Rows, old) |
275 | v = *data.Rows[index] |
276 | } |
277 | oldValues := v.Values |
278 | v.Values = make([]int64, len(data.Info.Buckets)) |
279 | copy(v.Values, oldValues) |
280 | f(&v) |
281 | data.Rows[index] = &v |
282 | data.EndTime = at |
283 | frozen := *data |
284 | return &frozen |
285 | } |
286 | |
287 | func (data *HistogramFloat64Data) record(at time.Time, lm label.Map, l label.Label) Data { |
288 | return data.modify(at, lm, func(v *HistogramFloat64Row) { |
289 | value := data.key.From(l) |
290 | v.Sum += value |
291 | if v.Min > value || v.Count == 0 { |
292 | v.Min = value |
293 | } |
294 | if v.Max < value || v.Count == 0 { |
295 | v.Max = value |
296 | } |
297 | v.Count++ |
298 | for i, b := range data.Info.Buckets { |
299 | if value <= b { |
300 | v.Values[i]++ |
301 | } |
302 | } |
303 | }) |
304 | } |
305 |
Members