aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/go.opencensus.io/stats
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
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')
-rw-r--r--vendor/go.opencensus.io/stats/doc.go69
-rw-r--r--vendor/go.opencensus.io/stats/internal/record.go25
-rw-r--r--vendor/go.opencensus.io/stats/internal/validation.go28
-rw-r--r--vendor/go.opencensus.io/stats/measure.go123
-rw-r--r--vendor/go.opencensus.io/stats/measure_float64.go36
-rw-r--r--vendor/go.opencensus.io/stats/measure_int64.go36
-rw-r--r--vendor/go.opencensus.io/stats/record.go69
-rw-r--r--vendor/go.opencensus.io/stats/units.go25
-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
16 files changed, 1555 insertions, 0 deletions
diff --git a/vendor/go.opencensus.io/stats/doc.go b/vendor/go.opencensus.io/stats/doc.go
new file mode 100644
index 0000000..00d473e
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/doc.go
@@ -0,0 +1,69 @@
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/*
17Package stats contains support for OpenCensus stats recording.
18
19OpenCensus allows users to create typed measures, record measurements,
20aggregate the collected data, and export the aggregated data.
21
22Measures
23
24A measure represents a type of data point to be tracked and recorded.
25For example, latency, request Mb/s, and response Mb/s are measures
26to collect from a server.
27
28Measure constructors such as Int64 and Float64 automatically
29register the measure by the given name. Each registered measure needs
30to be unique by name. Measures also have a description and a unit.
31
32Libraries can define and export measures. Application authors can then
33create views and collect and break down measures by the tags they are
34interested in.
35
36Recording measurements
37
38Measurement is a data point to be collected for a measure. For example,
39for a latency (ms) measure, 100 is a measurement that represents a 100ms
40latency event. Measurements are created from measures with
41the current context. Tags from the current context are recorded with the
42measurements if they are any.
43
44Recorded measurements are dropped immediately if no views are registered for them.
45There is usually no need to conditionally enable and disable
46recording to reduce cost. Recording of measurements is cheap.
47
48Libraries can always record measurements, and applications can later decide
49on which measurements they want to collect by registering views. This allows
50libraries to turn on the instrumentation by default.
51
52Exemplars
53
54For a given recorded measurement, the associated exemplar is a diagnostic map
55that gives more information about the measurement.
56
57When aggregated using a Distribution aggregation, an exemplar is kept for each
58bucket in the Distribution. This allows you to easily find an example of a
59measurement that fell into each bucket.
60
61For example, if you also use the OpenCensus trace package and you
62record a measurement with a context that contains a sampled trace span,
63then the trace span will be added to the exemplar associated with the measurement.
64
65When exported to a supporting back end, you should be able to easily navigate
66to example traces that fell into each bucket in the Distribution.
67
68*/
69package stats // import "go.opencensus.io/stats"
diff --git a/vendor/go.opencensus.io/stats/internal/record.go b/vendor/go.opencensus.io/stats/internal/record.go
new file mode 100644
index 0000000..ed54552
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/internal/record.go
@@ -0,0 +1,25 @@
1// Copyright 2018, 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 internal
16
17import (
18 "go.opencensus.io/tag"
19)
20
21// DefaultRecorder will be called for each Record call.
22var DefaultRecorder func(tags *tag.Map, measurement interface{}, attachments map[string]string)
23
24// SubscriptionReporter reports when a view subscribed with a measure.
25var SubscriptionReporter func(measure string)
diff --git a/vendor/go.opencensus.io/stats/internal/validation.go b/vendor/go.opencensus.io/stats/internal/validation.go
new file mode 100644
index 0000000..b946667
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/internal/validation.go
@@ -0,0 +1,28 @@
1// Copyright 2018, 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 internal // import "go.opencensus.io/stats/internal"
16
17const (
18 MaxNameLength = 255
19)
20
21func IsPrintable(str string) bool {
22 for _, r := range str {
23 if !(r >= ' ' && r <= '~') {
24 return false
25 }
26 }
27 return true
28}
diff --git a/vendor/go.opencensus.io/stats/measure.go b/vendor/go.opencensus.io/stats/measure.go
new file mode 100644
index 0000000..64d02b1
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/measure.go
@@ -0,0 +1,123 @@
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 stats
17
18import (
19 "sync"
20 "sync/atomic"
21)
22
23// Measure represents a single numeric value to be tracked and recorded.
24// For example, latency, request bytes, and response bytes could be measures
25// to collect from a server.
26//
27// Measures by themselves have no outside effects. In order to be exported,
28// the measure needs to be used in a View. If no Views are defined over a
29// measure, there is very little cost in recording it.
30type Measure interface {
31 // Name returns the name of this measure.
32 //
33 // Measure names are globally unique (among all libraries linked into your program).
34 // We recommend prefixing the measure name with a domain name relevant to your
35 // project or application.
36 //
37 // Measure names are never sent over the wire or exported to backends.
38 // They are only used to create Views.
39 Name() string
40
41 // Description returns the human-readable description of this measure.
42 Description() string
43
44 // Unit returns the units for the values this measure takes on.
45 //
46 // Units are encoded according to the case-sensitive abbreviations from the
47 // Unified Code for Units of Measure: http://unitsofmeasure.org/ucum.html
48 Unit() string
49}
50
51// measureDescriptor is the untyped descriptor associated with each measure.
52// Int64Measure and Float64Measure wrap measureDescriptor to provide typed
53// recording APIs.
54// Two Measures with the same name will have the same measureDescriptor.
55type measureDescriptor struct {
56 subs int32 // access atomically
57
58 name string
59 description string
60 unit string
61}
62
63func (m *measureDescriptor) subscribe() {
64 atomic.StoreInt32(&m.subs, 1)
65}
66
67func (m *measureDescriptor) subscribed() bool {
68 return atomic.LoadInt32(&m.subs) == 1
69}
70
71// Name returns the name of the measure.
72func (m *measureDescriptor) Name() string {
73 return m.name
74}
75
76// Description returns the description of the measure.
77func (m *measureDescriptor) Description() string {
78 return m.description
79}
80
81// Unit returns the unit of the measure.
82func (m *measureDescriptor) Unit() string {
83 return m.unit
84}
85
86var (
87 mu sync.RWMutex
88 measures = make(map[string]*measureDescriptor)
89)
90
91func registerMeasureHandle(name, desc, unit string) *measureDescriptor {
92 mu.Lock()
93 defer mu.Unlock()
94
95 if stored, ok := measures[name]; ok {
96 return stored
97 }
98 m := &measureDescriptor{
99 name: name,
100 description: desc,
101 unit: unit,
102 }
103 measures[name] = m
104 return m
105}
106
107// Measurement is the numeric value measured when recording stats. Each measure
108// provides methods to create measurements of their kind. For example, Int64Measure
109// provides M to convert an int64 into a measurement.
110type Measurement struct {
111 v float64
112 m *measureDescriptor
113}
114
115// Value returns the value of the Measurement as a float64.
116func (m Measurement) Value() float64 {
117 return m.v
118}
119
120// Measure returns the Measure from which this Measurement was created.
121func (m Measurement) Measure() Measure {
122 return m.m
123}
diff --git a/vendor/go.opencensus.io/stats/measure_float64.go b/vendor/go.opencensus.io/stats/measure_float64.go
new file mode 100644
index 0000000..acedb21
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/measure_float64.go
@@ -0,0 +1,36 @@
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 stats
17
18// Float64Measure is a measure for float64 values.
19type Float64Measure struct {
20 *measureDescriptor
21}
22
23// M creates a new float64 measurement.
24// Use Record to record measurements.
25func (m *Float64Measure) M(v float64) Measurement {
26 return Measurement{m: m.measureDescriptor, v: v}
27}
28
29// Float64 creates a new measure for float64 values.
30//
31// See the documentation for interface Measure for more guidance on the
32// parameters of this function.
33func Float64(name, description, unit string) *Float64Measure {
34 mi := registerMeasureHandle(name, description, unit)
35 return &Float64Measure{mi}
36}
diff --git a/vendor/go.opencensus.io/stats/measure_int64.go b/vendor/go.opencensus.io/stats/measure_int64.go
new file mode 100644
index 0000000..c4243ba
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/measure_int64.go
@@ -0,0 +1,36 @@
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 stats
17
18// Int64Measure is a measure for int64 values.
19type Int64Measure struct {
20 *measureDescriptor
21}
22
23// M creates a new int64 measurement.
24// Use Record to record measurements.
25func (m *Int64Measure) M(v int64) Measurement {
26 return Measurement{m: m.measureDescriptor, v: float64(v)}
27}
28
29// Int64 creates a new measure for int64 values.
30//
31// See the documentation for interface Measure for more guidance on the
32// parameters of this function.
33func Int64(name, description, unit string) *Int64Measure {
34 mi := registerMeasureHandle(name, description, unit)
35 return &Int64Measure{mi}
36}
diff --git a/vendor/go.opencensus.io/stats/record.go b/vendor/go.opencensus.io/stats/record.go
new file mode 100644
index 0000000..0aced02
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/record.go
@@ -0,0 +1,69 @@
1// Copyright 2018, 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 stats
17
18import (
19 "context"
20
21 "go.opencensus.io/exemplar"
22 "go.opencensus.io/stats/internal"
23 "go.opencensus.io/tag"
24)
25
26func init() {
27 internal.SubscriptionReporter = func(measure string) {
28 mu.Lock()
29 measures[measure].subscribe()
30 mu.Unlock()
31 }
32}
33
34// Record records one or multiple measurements with the same context at once.
35// If there are any tags in the context, measurements will be tagged with them.
36func Record(ctx context.Context, ms ...Measurement) {
37 recorder := internal.DefaultRecorder
38 if recorder == nil {
39 return
40 }
41 if len(ms) == 0 {
42 return
43 }
44 record := false
45 for _, m := range ms {
46 if m.m.subscribed() {
47 record = true
48 break
49 }
50 }
51 if !record {
52 return
53 }
54 recorder(tag.FromContext(ctx), ms, exemplar.AttachmentsFromContext(ctx))
55}
56
57// RecordWithTags records one or multiple measurements at once.
58//
59// Measurements will be tagged with the tags in the context mutated by the mutators.
60// RecordWithTags is useful if you want to record with tag mutations but don't want
61// to propagate the mutations in the context.
62func RecordWithTags(ctx context.Context, mutators []tag.Mutator, ms ...Measurement) error {
63 ctx, err := tag.New(ctx, mutators...)
64 if err != nil {
65 return err
66 }
67 Record(ctx, ms...)
68 return nil
69}
diff --git a/vendor/go.opencensus.io/stats/units.go b/vendor/go.opencensus.io/stats/units.go
new file mode 100644
index 0000000..6931a5f
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/units.go
@@ -0,0 +1,25 @@
1// Copyright 2018, 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 stats
17
18// Units are encoded according to the case-sensitive abbreviations from the
19// Unified Code for Units of Measure: http://unitsofmeasure.org/ucum.html
20const (
21 UnitNone = "1" // Deprecated: Use UnitDimensionless.
22 UnitDimensionless = "1"
23 UnitBytes = "By"
24 UnitMilliseconds = "ms"
25)
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}