diff options
Diffstat (limited to 'vendor/go.opencensus.io/stats/view/aggregation_data.go')
-rw-r--r-- | vendor/go.opencensus.io/stats/view/aggregation_data.go | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/vendor/go.opencensus.io/stats/view/aggregation_data.go b/vendor/go.opencensus.io/stats/view/aggregation_data.go new file mode 100644 index 0000000..960b946 --- /dev/null +++ b/vendor/go.opencensus.io/stats/view/aggregation_data.go | |||
@@ -0,0 +1,235 @@ | |||
1 | // Copyright 2017, OpenCensus Authors | ||
2 | // | ||
3 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | // you may not use this file except in compliance with the License. | ||
5 | // You may obtain a copy of the License at | ||
6 | // | ||
7 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | // | ||
9 | // Unless required by applicable law or agreed to in writing, software | ||
10 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | // See the License for the specific language governing permissions and | ||
13 | // limitations under the License. | ||
14 | // | ||
15 | |||
16 | package view | ||
17 | |||
18 | import ( | ||
19 | "math" | ||
20 | |||
21 | "go.opencensus.io/exemplar" | ||
22 | ) | ||
23 | |||
24 | // AggregationData represents an aggregated value from a collection. | ||
25 | // They are reported on the view data during exporting. | ||
26 | // Mosts users won't directly access aggregration data. | ||
27 | type AggregationData interface { | ||
28 | isAggregationData() bool | ||
29 | addSample(e *exemplar.Exemplar) | ||
30 | clone() AggregationData | ||
31 | equal(other AggregationData) bool | ||
32 | } | ||
33 | |||
34 | const epsilon = 1e-9 | ||
35 | |||
36 | // CountData is the aggregated data for the Count aggregation. | ||
37 | // A count aggregation processes data and counts the recordings. | ||
38 | // | ||
39 | // Most users won't directly access count data. | ||
40 | type CountData struct { | ||
41 | Value int64 | ||
42 | } | ||
43 | |||
44 | func (a *CountData) isAggregationData() bool { return true } | ||
45 | |||
46 | func (a *CountData) addSample(_ *exemplar.Exemplar) { | ||
47 | a.Value = a.Value + 1 | ||
48 | } | ||
49 | |||
50 | func (a *CountData) clone() AggregationData { | ||
51 | return &CountData{Value: a.Value} | ||
52 | } | ||
53 | |||
54 | func (a *CountData) equal(other AggregationData) bool { | ||
55 | a2, ok := other.(*CountData) | ||
56 | if !ok { | ||
57 | return false | ||
58 | } | ||
59 | |||
60 | return a.Value == a2.Value | ||
61 | } | ||
62 | |||
63 | // SumData is the aggregated data for the Sum aggregation. | ||
64 | // A sum aggregation processes data and sums up the recordings. | ||
65 | // | ||
66 | // Most users won't directly access sum data. | ||
67 | type SumData struct { | ||
68 | Value float64 | ||
69 | } | ||
70 | |||
71 | func (a *SumData) isAggregationData() bool { return true } | ||
72 | |||
73 | func (a *SumData) addSample(e *exemplar.Exemplar) { | ||
74 | a.Value += e.Value | ||
75 | } | ||
76 | |||
77 | func (a *SumData) clone() AggregationData { | ||
78 | return &SumData{Value: a.Value} | ||
79 | } | ||
80 | |||
81 | func (a *SumData) equal(other AggregationData) bool { | ||
82 | a2, ok := other.(*SumData) | ||
83 | if !ok { | ||
84 | return false | ||
85 | } | ||
86 | return math.Pow(a.Value-a2.Value, 2) < epsilon | ||
87 | } | ||
88 | |||
89 | // DistributionData is the aggregated data for the | ||
90 | // Distribution aggregation. | ||
91 | // | ||
92 | // Most users won't directly access distribution data. | ||
93 | // | ||
94 | // For a distribution with N bounds, the associated DistributionData will have | ||
95 | // N+1 buckets. | ||
96 | type DistributionData struct { | ||
97 | Count int64 // number of data points aggregated | ||
98 | Min float64 // minimum value in the distribution | ||
99 | Max float64 // max value in the distribution | ||
100 | Mean float64 // mean of the distribution | ||
101 | SumOfSquaredDev float64 // sum of the squared deviation from the mean | ||
102 | CountPerBucket []int64 // number of occurrences per bucket | ||
103 | // ExemplarsPerBucket is slice the same length as CountPerBucket containing | ||
104 | // an exemplar for the associated bucket, or nil. | ||
105 | ExemplarsPerBucket []*exemplar.Exemplar | ||
106 | bounds []float64 // histogram distribution of the values | ||
107 | } | ||
108 | |||
109 | func newDistributionData(bounds []float64) *DistributionData { | ||
110 | bucketCount := len(bounds) + 1 | ||
111 | return &DistributionData{ | ||
112 | CountPerBucket: make([]int64, bucketCount), | ||
113 | ExemplarsPerBucket: make([]*exemplar.Exemplar, bucketCount), | ||
114 | bounds: bounds, | ||
115 | Min: math.MaxFloat64, | ||
116 | Max: math.SmallestNonzeroFloat64, | ||
117 | } | ||
118 | } | ||
119 | |||
120 | // Sum returns the sum of all samples collected. | ||
121 | func (a *DistributionData) Sum() float64 { return a.Mean * float64(a.Count) } | ||
122 | |||
123 | func (a *DistributionData) variance() float64 { | ||
124 | if a.Count <= 1 { | ||
125 | return 0 | ||
126 | } | ||
127 | return a.SumOfSquaredDev / float64(a.Count-1) | ||
128 | } | ||
129 | |||
130 | func (a *DistributionData) isAggregationData() bool { return true } | ||
131 | |||
132 | func (a *DistributionData) addSample(e *exemplar.Exemplar) { | ||
133 | f := e.Value | ||
134 | if f < a.Min { | ||
135 | a.Min = f | ||
136 | } | ||
137 | if f > a.Max { | ||
138 | a.Max = f | ||
139 | } | ||
140 | a.Count++ | ||
141 | a.addToBucket(e) | ||
142 | |||
143 | if a.Count == 1 { | ||
144 | a.Mean = f | ||
145 | return | ||
146 | } | ||
147 | |||
148 | oldMean := a.Mean | ||
149 | a.Mean = a.Mean + (f-a.Mean)/float64(a.Count) | ||
150 | a.SumOfSquaredDev = a.SumOfSquaredDev + (f-oldMean)*(f-a.Mean) | ||
151 | } | ||
152 | |||
153 | func (a *DistributionData) addToBucket(e *exemplar.Exemplar) { | ||
154 | var count *int64 | ||
155 | var ex **exemplar.Exemplar | ||
156 | for i, b := range a.bounds { | ||
157 | if e.Value < b { | ||
158 | count = &a.CountPerBucket[i] | ||
159 | ex = &a.ExemplarsPerBucket[i] | ||
160 | break | ||
161 | } | ||
162 | } | ||
163 | if count == nil { | ||
164 | count = &a.CountPerBucket[len(a.bounds)] | ||
165 | ex = &a.ExemplarsPerBucket[len(a.bounds)] | ||
166 | } | ||
167 | *count++ | ||
168 | *ex = maybeRetainExemplar(*ex, e) | ||
169 | } | ||
170 | |||
171 | func maybeRetainExemplar(old, cur *exemplar.Exemplar) *exemplar.Exemplar { | ||
172 | if old == nil { | ||
173 | return cur | ||
174 | } | ||
175 | |||
176 | // Heuristic to pick the "better" exemplar: first keep the one with a | ||
177 | // sampled trace attachment, if neither have a trace attachment, pick the | ||
178 | // one with more attachments. | ||
179 | _, haveTraceID := cur.Attachments[exemplar.KeyTraceID] | ||
180 | if haveTraceID || len(cur.Attachments) >= len(old.Attachments) { | ||
181 | return cur | ||
182 | } | ||
183 | return old | ||
184 | } | ||
185 | |||
186 | func (a *DistributionData) clone() AggregationData { | ||
187 | c := *a | ||
188 | c.CountPerBucket = append([]int64(nil), a.CountPerBucket...) | ||
189 | c.ExemplarsPerBucket = append([]*exemplar.Exemplar(nil), a.ExemplarsPerBucket...) | ||
190 | return &c | ||
191 | } | ||
192 | |||
193 | func (a *DistributionData) equal(other AggregationData) bool { | ||
194 | a2, ok := other.(*DistributionData) | ||
195 | if !ok { | ||
196 | return false | ||
197 | } | ||
198 | if a2 == nil { | ||
199 | return false | ||
200 | } | ||
201 | if len(a.CountPerBucket) != len(a2.CountPerBucket) { | ||
202 | return false | ||
203 | } | ||
204 | for i := range a.CountPerBucket { | ||
205 | if a.CountPerBucket[i] != a2.CountPerBucket[i] { | ||
206 | return false | ||
207 | } | ||
208 | } | ||
209 | return a.Count == a2.Count && a.Min == a2.Min && a.Max == a2.Max && math.Pow(a.Mean-a2.Mean, 2) < epsilon && math.Pow(a.variance()-a2.variance(), 2) < epsilon | ||
210 | } | ||
211 | |||
212 | // LastValueData returns the last value recorded for LastValue aggregation. | ||
213 | type LastValueData struct { | ||
214 | Value float64 | ||
215 | } | ||
216 | |||
217 | func (l *LastValueData) isAggregationData() bool { | ||
218 | return true | ||
219 | } | ||
220 | |||
221 | func (l *LastValueData) addSample(e *exemplar.Exemplar) { | ||
222 | l.Value = e.Value | ||
223 | } | ||
224 | |||
225 | func (l *LastValueData) clone() AggregationData { | ||
226 | return &LastValueData{l.Value} | ||
227 | } | ||
228 | |||
229 | func (l *LastValueData) equal(other AggregationData) bool { | ||
230 | a2, ok := other.(*LastValueData) | ||
231 | if !ok { | ||
232 | return false | ||
233 | } | ||
234 | return l.Value == a2.Value | ||
235 | } | ||