aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/go.opencensus.io/stats/view
diff options
context:
space:
mode:
authorNathan Dench <ndenc2@gmail.com>2019-05-24 15:16:44 +1000
committerNathan Dench <ndenc2@gmail.com>2019-05-24 15:16:44 +1000
commit107c1cdb09c575aa2f61d97f48d8587eb6bada4c (patch)
treeca7d008643efc555c388baeaf1d986e0b6b3e28c /vendor/go.opencensus.io/stats/view
parent844b5a68d8af4791755b8f0ad293cc99f5959183 (diff)
downloadterraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.gz
terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.zst
terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.zip
Upgrade to 0.12
Diffstat (limited to 'vendor/go.opencensus.io/stats/view')
-rw-r--r--vendor/go.opencensus.io/stats/view/aggregation.go120
-rw-r--r--vendor/go.opencensus.io/stats/view/aggregation_data.go235
-rw-r--r--vendor/go.opencensus.io/stats/view/collector.go87
-rw-r--r--vendor/go.opencensus.io/stats/view/doc.go47
-rw-r--r--vendor/go.opencensus.io/stats/view/export.go58
-rw-r--r--vendor/go.opencensus.io/stats/view/view.go185
-rw-r--r--vendor/go.opencensus.io/stats/view/worker.go229
-rw-r--r--vendor/go.opencensus.io/stats/view/worker_commands.go183
8 files changed, 1144 insertions, 0 deletions
diff --git a/vendor/go.opencensus.io/stats/view/aggregation.go b/vendor/go.opencensus.io/stats/view/aggregation.go
new file mode 100644
index 0000000..b7f169b
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/aggregation.go
@@ -0,0 +1,120 @@
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
18// AggType represents the type of aggregation function used on a View.
19type AggType int
20
21// All available aggregation types.
22const (
23 AggTypeNone AggType = iota // no aggregation; reserved for future use.
24 AggTypeCount // the count aggregation, see Count.
25 AggTypeSum // the sum aggregation, see Sum.
26 AggTypeDistribution // the distribution aggregation, see Distribution.
27 AggTypeLastValue // the last value aggregation, see LastValue.
28)
29
30func (t AggType) String() string {
31 return aggTypeName[t]
32}
33
34var aggTypeName = map[AggType]string{
35 AggTypeNone: "None",
36 AggTypeCount: "Count",
37 AggTypeSum: "Sum",
38 AggTypeDistribution: "Distribution",
39 AggTypeLastValue: "LastValue",
40}
41
42// Aggregation represents a data aggregation method. Use one of the functions:
43// Count, Sum, or Distribution to construct an Aggregation.
44type Aggregation struct {
45 Type AggType // Type is the AggType of this Aggregation.
46 Buckets []float64 // Buckets are the bucket endpoints if this Aggregation represents a distribution, see Distribution.
47
48 newData func() AggregationData
49}
50
51var (
52 aggCount = &Aggregation{
53 Type: AggTypeCount,
54 newData: func() AggregationData {
55 return &CountData{}
56 },
57 }
58 aggSum = &Aggregation{
59 Type: AggTypeSum,
60 newData: func() AggregationData {
61 return &SumData{}
62 },
63 }
64)
65
66// Count indicates that data collected and aggregated
67// with this method will be turned into a count value.
68// For example, total number of accepted requests can be
69// aggregated by using Count.
70func Count() *Aggregation {
71 return aggCount
72}
73
74// Sum indicates that data collected and aggregated
75// with this method will be summed up.
76// For example, accumulated request bytes can be aggregated by using
77// Sum.
78func Sum() *Aggregation {
79 return aggSum
80}
81
82// Distribution indicates that the desired aggregation is
83// a histogram distribution.
84//
85// An distribution aggregation may contain a histogram of the values in the
86// population. The bucket boundaries for that histogram are described
87// by the bounds. This defines len(bounds)+1 buckets.
88//
89// If len(bounds) >= 2 then the boundaries for bucket index i are:
90//
91// [-infinity, bounds[i]) for i = 0
92// [bounds[i-1], bounds[i]) for 0 < i < length
93// [bounds[i-1], +infinity) for i = length
94//
95// If len(bounds) is 0 then there is no histogram associated with the
96// distribution. There will be a single bucket with boundaries
97// (-infinity, +infinity).
98//
99// If len(bounds) is 1 then there is no finite buckets, and that single
100// element is the common boundary of the overflow and underflow buckets.
101func Distribution(bounds ...float64) *Aggregation {
102 return &Aggregation{
103 Type: AggTypeDistribution,
104 Buckets: bounds,
105 newData: func() AggregationData {
106 return newDistributionData(bounds)
107 },
108 }
109}
110
111// LastValue only reports the last value recorded using this
112// aggregation. All other measurements will be dropped.
113func LastValue() *Aggregation {
114 return &Aggregation{
115 Type: AggTypeLastValue,
116 newData: func() AggregationData {
117 return &LastValueData{}
118 },
119 }
120}
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}
diff --git a/vendor/go.opencensus.io/stats/view/collector.go b/vendor/go.opencensus.io/stats/view/collector.go
new file mode 100644
index 0000000..32415d4
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/collector.go
@@ -0,0 +1,87 @@
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 "sort"
20
21 "go.opencensus.io/exemplar"
22
23 "go.opencensus.io/internal/tagencoding"
24 "go.opencensus.io/tag"
25)
26
27type collector struct {
28 // signatures holds the aggregations values for each unique tag signature
29 // (values for all keys) to its aggregator.
30 signatures map[string]AggregationData
31 // Aggregation is the description of the aggregation to perform for this
32 // view.
33 a *Aggregation
34}
35
36func (c *collector) addSample(s string, e *exemplar.Exemplar) {
37 aggregator, ok := c.signatures[s]
38 if !ok {
39 aggregator = c.a.newData()
40 c.signatures[s] = aggregator
41 }
42 aggregator.addSample(e)
43}
44
45// collectRows returns a snapshot of the collected Row values.
46func (c *collector) collectedRows(keys []tag.Key) []*Row {
47 rows := make([]*Row, 0, len(c.signatures))
48 for sig, aggregator := range c.signatures {
49 tags := decodeTags([]byte(sig), keys)
50 row := &Row{Tags: tags, Data: aggregator.clone()}
51 rows = append(rows, row)
52 }
53 return rows
54}
55
56func (c *collector) clearRows() {
57 c.signatures = make(map[string]AggregationData)
58}
59
60// encodeWithKeys encodes the map by using values
61// only associated with the keys provided.
62func encodeWithKeys(m *tag.Map, keys []tag.Key) []byte {
63 vb := &tagencoding.Values{
64 Buffer: make([]byte, len(keys)),
65 }
66 for _, k := range keys {
67 v, _ := m.Value(k)
68 vb.WriteValue([]byte(v))
69 }
70 return vb.Bytes()
71}
72
73// decodeTags decodes tags from the buffer and
74// orders them by the keys.
75func decodeTags(buf []byte, keys []tag.Key) []tag.Tag {
76 vb := &tagencoding.Values{Buffer: buf}
77 var tags []tag.Tag
78 for _, k := range keys {
79 v := vb.ReadValue()
80 if v != nil {
81 tags = append(tags, tag.Tag{Key: k, Value: string(v)})
82 }
83 }
84 vb.ReadIndex = 0
85 sort.Slice(tags, func(i, j int) bool { return tags[i].Key.Name() < tags[j].Key.Name() })
86 return tags
87}
diff --git a/vendor/go.opencensus.io/stats/view/doc.go b/vendor/go.opencensus.io/stats/view/doc.go
new file mode 100644
index 0000000..dced225
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/doc.go
@@ -0,0 +1,47 @@
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 contains support for collecting and exposing aggregates over stats.
17//
18// In order to collect measurements, views need to be defined and registered.
19// A view allows recorded measurements to be filtered and aggregated.
20//
21// All recorded measurements can be grouped by a list of tags.
22//
23// OpenCensus provides several aggregation methods: Count, Distribution and Sum.
24//
25// Count only counts the number of measurement points recorded.
26// Distribution provides statistical summary of the aggregated data by counting
27// how many recorded measurements fall into each bucket.
28// Sum adds up the measurement values.
29// LastValue just keeps track of the most recently recorded measurement value.
30// All aggregations are cumulative.
31//
32// Views can be registerd and unregistered at any time during program execution.
33//
34// Libraries can define views but it is recommended that in most cases registering
35// views be left up to applications.
36//
37// Exporting
38//
39// Collected and aggregated data can be exported to a metric collection
40// backend by registering its exporter.
41//
42// Multiple exporters can be registered to upload the data to various
43// different back ends.
44package view // import "go.opencensus.io/stats/view"
45
46// TODO(acetechnologist): Add a link to the language independent OpenCensus
47// spec when it is available.
diff --git a/vendor/go.opencensus.io/stats/view/export.go b/vendor/go.opencensus.io/stats/view/export.go
new file mode 100644
index 0000000..7cb5971
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/export.go
@@ -0,0 +1,58 @@
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
15package view
16
17import "sync"
18
19var (
20 exportersMu sync.RWMutex // guards exporters
21 exporters = make(map[Exporter]struct{})
22)
23
24// Exporter exports the collected records as view data.
25//
26// The ExportView method should return quickly; if an
27// Exporter takes a significant amount of time to
28// process a Data, that work should be done on another goroutine.
29//
30// It is safe to assume that ExportView will not be called concurrently from
31// multiple goroutines.
32//
33// The Data should not be modified.
34type Exporter interface {
35 ExportView(viewData *Data)
36}
37
38// RegisterExporter registers an exporter.
39// Collected data will be reported via all the
40// registered exporters. Once you no longer
41// want data to be exported, invoke UnregisterExporter
42// with the previously registered exporter.
43//
44// Binaries can register exporters, libraries shouldn't register exporters.
45func RegisterExporter(e Exporter) {
46 exportersMu.Lock()
47 defer exportersMu.Unlock()
48
49 exporters[e] = struct{}{}
50}
51
52// UnregisterExporter unregisters an exporter.
53func UnregisterExporter(e Exporter) {
54 exportersMu.Lock()
55 defer exportersMu.Unlock()
56
57 delete(exporters, e)
58}
diff --git a/vendor/go.opencensus.io/stats/view/view.go b/vendor/go.opencensus.io/stats/view/view.go
new file mode 100644
index 0000000..c2a08af
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/view.go
@@ -0,0 +1,185 @@
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 "bytes"
20 "fmt"
21 "reflect"
22 "sort"
23 "sync/atomic"
24 "time"
25
26 "go.opencensus.io/exemplar"
27
28 "go.opencensus.io/stats"
29 "go.opencensus.io/stats/internal"
30 "go.opencensus.io/tag"
31)
32
33// View allows users to aggregate the recorded stats.Measurements.
34// Views need to be passed to the Register function to be before data will be
35// collected and sent to Exporters.
36type View struct {
37 Name string // Name of View. Must be unique. If unset, will default to the name of the Measure.
38 Description string // Description is a human-readable description for this view.
39
40 // TagKeys are the tag keys describing the grouping of this view.
41 // A single Row will be produced for each combination of associated tag values.
42 TagKeys []tag.Key
43
44 // Measure is a stats.Measure to aggregate in this view.
45 Measure stats.Measure
46
47 // Aggregation is the aggregation function tp apply to the set of Measurements.
48 Aggregation *Aggregation
49}
50
51// WithName returns a copy of the View with a new name. This is useful for
52// renaming views to cope with limitations placed on metric names by various
53// backends.
54func (v *View) WithName(name string) *View {
55 vNew := *v
56 vNew.Name = name
57 return &vNew
58}
59
60// same compares two views and returns true if they represent the same aggregation.
61func (v *View) same(other *View) bool {
62 if v == other {
63 return true
64 }
65 if v == nil {
66 return false
67 }
68 return reflect.DeepEqual(v.Aggregation, other.Aggregation) &&
69 v.Measure.Name() == other.Measure.Name()
70}
71
72// canonicalize canonicalizes v by setting explicit
73// defaults for Name and Description and sorting the TagKeys
74func (v *View) canonicalize() error {
75 if v.Measure == nil {
76 return fmt.Errorf("cannot register view %q: measure not set", v.Name)
77 }
78 if v.Aggregation == nil {
79 return fmt.Errorf("cannot register view %q: aggregation not set", v.Name)
80 }
81 if v.Name == "" {
82 v.Name = v.Measure.Name()
83 }
84 if v.Description == "" {
85 v.Description = v.Measure.Description()
86 }
87 if err := checkViewName(v.Name); err != nil {
88 return err
89 }
90 sort.Slice(v.TagKeys, func(i, j int) bool {
91 return v.TagKeys[i].Name() < v.TagKeys[j].Name()
92 })
93 return nil
94}
95
96// viewInternal is the internal representation of a View.
97type viewInternal struct {
98 view *View // view is the canonicalized View definition associated with this view.
99 subscribed uint32 // 1 if someone is subscribed and data need to be exported, use atomic to access
100 collector *collector
101}
102
103func newViewInternal(v *View) (*viewInternal, error) {
104 return &viewInternal{
105 view: v,
106 collector: &collector{make(map[string]AggregationData), v.Aggregation},
107 }, nil
108}
109
110func (v *viewInternal) subscribe() {
111 atomic.StoreUint32(&v.subscribed, 1)
112}
113
114func (v *viewInternal) unsubscribe() {
115 atomic.StoreUint32(&v.subscribed, 0)
116}
117
118// isSubscribed returns true if the view is exporting
119// data by subscription.
120func (v *viewInternal) isSubscribed() bool {
121 return atomic.LoadUint32(&v.subscribed) == 1
122}
123
124func (v *viewInternal) clearRows() {
125 v.collector.clearRows()
126}
127
128func (v *viewInternal) collectedRows() []*Row {
129 return v.collector.collectedRows(v.view.TagKeys)
130}
131
132func (v *viewInternal) addSample(m *tag.Map, e *exemplar.Exemplar) {
133 if !v.isSubscribed() {
134 return
135 }
136 sig := string(encodeWithKeys(m, v.view.TagKeys))
137 v.collector.addSample(sig, e)
138}
139
140// A Data is a set of rows about usage of the single measure associated
141// with the given view. Each row is specific to a unique set of tags.
142type Data struct {
143 View *View
144 Start, End time.Time
145 Rows []*Row
146}
147
148// Row is the collected value for a specific set of key value pairs a.k.a tags.
149type Row struct {
150 Tags []tag.Tag
151 Data AggregationData
152}
153
154func (r *Row) String() string {
155 var buffer bytes.Buffer
156 buffer.WriteString("{ ")
157 buffer.WriteString("{ ")
158 for _, t := range r.Tags {
159 buffer.WriteString(fmt.Sprintf("{%v %v}", t.Key.Name(), t.Value))
160 }
161 buffer.WriteString(" }")
162 buffer.WriteString(fmt.Sprintf("%v", r.Data))
163 buffer.WriteString(" }")
164 return buffer.String()
165}
166
167// Equal returns true if both rows are equal. Tags are expected to be ordered
168// by the key name. Even both rows have the same tags but the tags appear in
169// different orders it will return false.
170func (r *Row) Equal(other *Row) bool {
171 if r == other {
172 return true
173 }
174 return reflect.DeepEqual(r.Tags, other.Tags) && r.Data.equal(other.Data)
175}
176
177func checkViewName(name string) error {
178 if len(name) > internal.MaxNameLength {
179 return fmt.Errorf("view name cannot be larger than %v", internal.MaxNameLength)
180 }
181 if !internal.IsPrintable(name) {
182 return fmt.Errorf("view name needs to be an ASCII string")
183 }
184 return nil
185}
diff --git a/vendor/go.opencensus.io/stats/view/worker.go b/vendor/go.opencensus.io/stats/view/worker.go
new file mode 100644
index 0000000..63b0ee3
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/worker.go
@@ -0,0 +1,229 @@
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 "fmt"
20 "time"
21
22 "go.opencensus.io/stats"
23 "go.opencensus.io/stats/internal"
24 "go.opencensus.io/tag"
25)
26
27func init() {
28 defaultWorker = newWorker()
29 go defaultWorker.start()
30 internal.DefaultRecorder = record
31}
32
33type measureRef struct {
34 measure string
35 views map[*viewInternal]struct{}
36}
37
38type worker struct {
39 measures map[string]*measureRef
40 views map[string]*viewInternal
41 startTimes map[*viewInternal]time.Time
42
43 timer *time.Ticker
44 c chan command
45 quit, done chan bool
46}
47
48var defaultWorker *worker
49
50var defaultReportingDuration = 10 * time.Second
51
52// Find returns a registered view associated with this name.
53// If no registered view is found, nil is returned.
54func Find(name string) (v *View) {
55 req := &getViewByNameReq{
56 name: name,
57 c: make(chan *getViewByNameResp),
58 }
59 defaultWorker.c <- req
60 resp := <-req.c
61 return resp.v
62}
63
64// Register begins collecting data for the given views.
65// Once a view is registered, it reports data to the registered exporters.
66func Register(views ...*View) error {
67 for _, v := range views {
68 if err := v.canonicalize(); err != nil {
69 return err
70 }
71 }
72 req := &registerViewReq{
73 views: views,
74 err: make(chan error),
75 }
76 defaultWorker.c <- req
77 return <-req.err
78}
79
80// Unregister the given views. Data will not longer be exported for these views
81// after Unregister returns.
82// It is not necessary to unregister from views you expect to collect for the
83// duration of your program execution.
84func Unregister(views ...*View) {
85 names := make([]string, len(views))
86 for i := range views {
87 names[i] = views[i].Name
88 }
89 req := &unregisterFromViewReq{
90 views: names,
91 done: make(chan struct{}),
92 }
93 defaultWorker.c <- req
94 <-req.done
95}
96
97// RetrieveData gets a snapshot of the data collected for the the view registered
98// with the given name. It is intended for testing only.
99func RetrieveData(viewName string) ([]*Row, error) {
100 req := &retrieveDataReq{
101 now: time.Now(),
102 v: viewName,
103 c: make(chan *retrieveDataResp),
104 }
105 defaultWorker.c <- req
106 resp := <-req.c
107 return resp.rows, resp.err
108}
109
110func record(tags *tag.Map, ms interface{}, attachments map[string]string) {
111 req := &recordReq{
112 tm: tags,
113 ms: ms.([]stats.Measurement),
114 attachments: attachments,
115 t: time.Now(),
116 }
117 defaultWorker.c <- req
118}
119
120// SetReportingPeriod sets the interval between reporting aggregated views in
121// the program. If duration is less than or equal to zero, it enables the
122// default behavior.
123//
124// Note: each exporter makes different promises about what the lowest supported
125// duration is. For example, the Stackdriver exporter recommends a value no
126// lower than 1 minute. Consult each exporter per your needs.
127func SetReportingPeriod(d time.Duration) {
128 // TODO(acetechnologist): ensure that the duration d is more than a certain
129 // value. e.g. 1s
130 req := &setReportingPeriodReq{
131 d: d,
132 c: make(chan bool),
133 }
134 defaultWorker.c <- req
135 <-req.c // don't return until the timer is set to the new duration.
136}
137
138func newWorker() *worker {
139 return &worker{
140 measures: make(map[string]*measureRef),
141 views: make(map[string]*viewInternal),
142 startTimes: make(map[*viewInternal]time.Time),
143 timer: time.NewTicker(defaultReportingDuration),
144 c: make(chan command, 1024),
145 quit: make(chan bool),
146 done: make(chan bool),
147 }
148}
149
150func (w *worker) start() {
151 for {
152 select {
153 case cmd := <-w.c:
154 cmd.handleCommand(w)
155 case <-w.timer.C:
156 w.reportUsage(time.Now())
157 case <-w.quit:
158 w.timer.Stop()
159 close(w.c)
160 w.done <- true
161 return
162 }
163 }
164}
165
166func (w *worker) stop() {
167 w.quit <- true
168 <-w.done
169}
170
171func (w *worker) getMeasureRef(name string) *measureRef {
172 if mr, ok := w.measures[name]; ok {
173 return mr
174 }
175 mr := &measureRef{
176 measure: name,
177 views: make(map[*viewInternal]struct{}),
178 }
179 w.measures[name] = mr
180 return mr
181}
182
183func (w *worker) tryRegisterView(v *View) (*viewInternal, error) {
184 vi, err := newViewInternal(v)
185 if err != nil {
186 return nil, err
187 }
188 if x, ok := w.views[vi.view.Name]; ok {
189 if !x.view.same(vi.view) {
190 return nil, fmt.Errorf("cannot register view %q; a different view with the same name is already registered", v.Name)
191 }
192
193 // the view is already registered so there is nothing to do and the
194 // command is considered successful.
195 return x, nil
196 }
197 w.views[vi.view.Name] = vi
198 ref := w.getMeasureRef(vi.view.Measure.Name())
199 ref.views[vi] = struct{}{}
200 return vi, nil
201}
202
203func (w *worker) reportView(v *viewInternal, now time.Time) {
204 if !v.isSubscribed() {
205 return
206 }
207 rows := v.collectedRows()
208 _, ok := w.startTimes[v]
209 if !ok {
210 w.startTimes[v] = now
211 }
212 viewData := &Data{
213 View: v.view,
214 Start: w.startTimes[v],
215 End: time.Now(),
216 Rows: rows,
217 }
218 exportersMu.Lock()
219 for e := range exporters {
220 e.ExportView(viewData)
221 }
222 exportersMu.Unlock()
223}
224
225func (w *worker) reportUsage(now time.Time) {
226 for _, v := range w.views {
227 w.reportView(v, now)
228 }
229}
diff --git a/vendor/go.opencensus.io/stats/view/worker_commands.go b/vendor/go.opencensus.io/stats/view/worker_commands.go
new file mode 100644
index 0000000..b38f26f
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/worker_commands.go
@@ -0,0 +1,183 @@
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 "errors"
20 "fmt"
21 "strings"
22 "time"
23
24 "go.opencensus.io/exemplar"
25
26 "go.opencensus.io/stats"
27 "go.opencensus.io/stats/internal"
28 "go.opencensus.io/tag"
29)
30
31type command interface {
32 handleCommand(w *worker)
33}
34
35// getViewByNameReq is the command to get a view given its name.
36type getViewByNameReq struct {
37 name string
38 c chan *getViewByNameResp
39}
40
41type getViewByNameResp struct {
42 v *View
43}
44
45func (cmd *getViewByNameReq) handleCommand(w *worker) {
46 v := w.views[cmd.name]
47 if v == nil {
48 cmd.c <- &getViewByNameResp{nil}
49 return
50 }
51 cmd.c <- &getViewByNameResp{v.view}
52}
53
54// registerViewReq is the command to register a view.
55type registerViewReq struct {
56 views []*View
57 err chan error
58}
59
60func (cmd *registerViewReq) handleCommand(w *worker) {
61 var errstr []string
62 for _, view := range cmd.views {
63 vi, err := w.tryRegisterView(view)
64 if err != nil {
65 errstr = append(errstr, fmt.Sprintf("%s: %v", view.Name, err))
66 continue
67 }
68 internal.SubscriptionReporter(view.Measure.Name())
69 vi.subscribe()
70 }
71 if len(errstr) > 0 {
72 cmd.err <- errors.New(strings.Join(errstr, "\n"))
73 } else {
74 cmd.err <- nil
75 }
76}
77
78// unregisterFromViewReq is the command to unregister to a view. Has no
79// impact on the data collection for client that are pulling data from the
80// library.
81type unregisterFromViewReq struct {
82 views []string
83 done chan struct{}
84}
85
86func (cmd *unregisterFromViewReq) handleCommand(w *worker) {
87 for _, name := range cmd.views {
88 vi, ok := w.views[name]
89 if !ok {
90 continue
91 }
92
93 // Report pending data for this view before removing it.
94 w.reportView(vi, time.Now())
95
96 vi.unsubscribe()
97 if !vi.isSubscribed() {
98 // this was the last subscription and view is not collecting anymore.
99 // The collected data can be cleared.
100 vi.clearRows()
101 }
102 delete(w.views, name)
103 }
104 cmd.done <- struct{}{}
105}
106
107// retrieveDataReq is the command to retrieve data for a view.
108type retrieveDataReq struct {
109 now time.Time
110 v string
111 c chan *retrieveDataResp
112}
113
114type retrieveDataResp struct {
115 rows []*Row
116 err error
117}
118
119func (cmd *retrieveDataReq) handleCommand(w *worker) {
120 vi, ok := w.views[cmd.v]
121 if !ok {
122 cmd.c <- &retrieveDataResp{
123 nil,
124 fmt.Errorf("cannot retrieve data; view %q is not registered", cmd.v),
125 }
126 return
127 }
128
129 if !vi.isSubscribed() {
130 cmd.c <- &retrieveDataResp{
131 nil,
132 fmt.Errorf("cannot retrieve data; view %q has no subscriptions or collection is not forcibly started", cmd.v),
133 }
134 return
135 }
136 cmd.c <- &retrieveDataResp{
137 vi.collectedRows(),
138 nil,
139 }
140}
141
142// recordReq is the command to record data related to multiple measures
143// at once.
144type recordReq struct {
145 tm *tag.Map
146 ms []stats.Measurement
147 attachments map[string]string
148 t time.Time
149}
150
151func (cmd *recordReq) handleCommand(w *worker) {
152 for _, m := range cmd.ms {
153 if (m == stats.Measurement{}) { // not registered
154 continue
155 }
156 ref := w.getMeasureRef(m.Measure().Name())
157 for v := range ref.views {
158 e := &exemplar.Exemplar{
159 Value: m.Value(),
160 Timestamp: cmd.t,
161 Attachments: cmd.attachments,
162 }
163 v.addSample(cmd.tm, e)
164 }
165 }
166}
167
168// setReportingPeriodReq is the command to modify the duration between
169// reporting the collected data to the registered clients.
170type setReportingPeriodReq struct {
171 d time.Duration
172 c chan bool
173}
174
175func (cmd *setReportingPeriodReq) handleCommand(w *worker) {
176 w.timer.Stop()
177 if cmd.d <= 0 {
178 w.timer = time.NewTicker(defaultReportingDuration)
179 } else {
180 w.timer = time.NewTicker(cmd.d)
181 }
182 cmd.c <- true
183}