aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/go.opencensus.io/stats/view/aggregation_data.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/go.opencensus.io/stats/view/aggregation_data.go')
-rw-r--r--vendor/go.opencensus.io/stats/view/aggregation_data.go235
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
16package view
17
18import (
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.
27type AggregationData interface {
28 isAggregationData() bool
29 addSample(e *exemplar.Exemplar)
30 clone() AggregationData
31 equal(other AggregationData) bool
32}
33
34const 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.
40type CountData struct {
41 Value int64
42}
43
44func (a *CountData) isAggregationData() bool { return true }
45
46func (a *CountData) addSample(_ *exemplar.Exemplar) {
47 a.Value = a.Value + 1
48}
49
50func (a *CountData) clone() AggregationData {
51 return &CountData{Value: a.Value}
52}
53
54func (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.
67type SumData struct {
68 Value float64
69}
70
71func (a *SumData) isAggregationData() bool { return true }
72
73func (a *SumData) addSample(e *exemplar.Exemplar) {
74 a.Value += e.Value
75}
76
77func (a *SumData) clone() AggregationData {
78 return &SumData{Value: a.Value}
79}
80
81func (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.
96type 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
109func 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.
121func (a *DistributionData) Sum() float64 { return a.Mean * float64(a.Count) }
122
123func (a *DistributionData) variance() float64 {
124 if a.Count <= 1 {
125 return 0
126 }
127 return a.SumOfSquaredDev / float64(a.Count-1)
128}
129
130func (a *DistributionData) isAggregationData() bool { return true }
131
132func (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
153func (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
171func 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
186func (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
193func (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.
213type LastValueData struct {
214 Value float64
215}
216
217func (l *LastValueData) isAggregationData() bool {
218 return true
219}
220
221func (l *LastValueData) addSample(e *exemplar.Exemplar) {
222 l.Value = e.Value
223}
224
225func (l *LastValueData) clone() AggregationData {
226 return &LastValueData{l.Value}
227}
228
229func (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}