diff options
Diffstat (limited to 'vendor/go.opencensus.io/stats')
-rw-r--r-- | vendor/go.opencensus.io/stats/doc.go | 69 | ||||
-rw-r--r-- | vendor/go.opencensus.io/stats/internal/record.go | 25 | ||||
-rw-r--r-- | vendor/go.opencensus.io/stats/internal/validation.go | 28 | ||||
-rw-r--r-- | vendor/go.opencensus.io/stats/measure.go | 123 | ||||
-rw-r--r-- | vendor/go.opencensus.io/stats/measure_float64.go | 36 | ||||
-rw-r--r-- | vendor/go.opencensus.io/stats/measure_int64.go | 36 | ||||
-rw-r--r-- | vendor/go.opencensus.io/stats/record.go | 69 | ||||
-rw-r--r-- | vendor/go.opencensus.io/stats/units.go | 25 | ||||
-rw-r--r-- | vendor/go.opencensus.io/stats/view/aggregation.go | 120 | ||||
-rw-r--r-- | vendor/go.opencensus.io/stats/view/aggregation_data.go | 235 | ||||
-rw-r--r-- | vendor/go.opencensus.io/stats/view/collector.go | 87 | ||||
-rw-r--r-- | vendor/go.opencensus.io/stats/view/doc.go | 47 | ||||
-rw-r--r-- | vendor/go.opencensus.io/stats/view/export.go | 58 | ||||
-rw-r--r-- | vendor/go.opencensus.io/stats/view/view.go | 185 | ||||
-rw-r--r-- | vendor/go.opencensus.io/stats/view/worker.go | 229 | ||||
-rw-r--r-- | vendor/go.opencensus.io/stats/view/worker_commands.go | 183 |
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 | /* | ||
17 | Package stats contains support for OpenCensus stats recording. | ||
18 | |||
19 | OpenCensus allows users to create typed measures, record measurements, | ||
20 | aggregate the collected data, and export the aggregated data. | ||
21 | |||
22 | Measures | ||
23 | |||
24 | A measure represents a type of data point to be tracked and recorded. | ||
25 | For example, latency, request Mb/s, and response Mb/s are measures | ||
26 | to collect from a server. | ||
27 | |||
28 | Measure constructors such as Int64 and Float64 automatically | ||
29 | register the measure by the given name. Each registered measure needs | ||
30 | to be unique by name. Measures also have a description and a unit. | ||
31 | |||
32 | Libraries can define and export measures. Application authors can then | ||
33 | create views and collect and break down measures by the tags they are | ||
34 | interested in. | ||
35 | |||
36 | Recording measurements | ||
37 | |||
38 | Measurement is a data point to be collected for a measure. For example, | ||
39 | for a latency (ms) measure, 100 is a measurement that represents a 100ms | ||
40 | latency event. Measurements are created from measures with | ||
41 | the current context. Tags from the current context are recorded with the | ||
42 | measurements if they are any. | ||
43 | |||
44 | Recorded measurements are dropped immediately if no views are registered for them. | ||
45 | There is usually no need to conditionally enable and disable | ||
46 | recording to reduce cost. Recording of measurements is cheap. | ||
47 | |||
48 | Libraries can always record measurements, and applications can later decide | ||
49 | on which measurements they want to collect by registering views. This allows | ||
50 | libraries to turn on the instrumentation by default. | ||
51 | |||
52 | Exemplars | ||
53 | |||
54 | For a given recorded measurement, the associated exemplar is a diagnostic map | ||
55 | that gives more information about the measurement. | ||
56 | |||
57 | When aggregated using a Distribution aggregation, an exemplar is kept for each | ||
58 | bucket in the Distribution. This allows you to easily find an example of a | ||
59 | measurement that fell into each bucket. | ||
60 | |||
61 | For example, if you also use the OpenCensus trace package and you | ||
62 | record a measurement with a context that contains a sampled trace span, | ||
63 | then the trace span will be added to the exemplar associated with the measurement. | ||
64 | |||
65 | When exported to a supporting back end, you should be able to easily navigate | ||
66 | to example traces that fell into each bucket in the Distribution. | ||
67 | |||
68 | */ | ||
69 | package 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 | |||
15 | package internal | ||
16 | |||
17 | import ( | ||
18 | "go.opencensus.io/tag" | ||
19 | ) | ||
20 | |||
21 | // DefaultRecorder will be called for each Record call. | ||
22 | var DefaultRecorder func(tags *tag.Map, measurement interface{}, attachments map[string]string) | ||
23 | |||
24 | // SubscriptionReporter reports when a view subscribed with a measure. | ||
25 | var 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 | |||
15 | package internal // import "go.opencensus.io/stats/internal" | ||
16 | |||
17 | const ( | ||
18 | MaxNameLength = 255 | ||
19 | ) | ||
20 | |||
21 | func 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 | |||
16 | package stats | ||
17 | |||
18 | import ( | ||
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. | ||
30 | type 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. | ||
55 | type measureDescriptor struct { | ||
56 | subs int32 // access atomically | ||
57 | |||
58 | name string | ||
59 | description string | ||
60 | unit string | ||
61 | } | ||
62 | |||
63 | func (m *measureDescriptor) subscribe() { | ||
64 | atomic.StoreInt32(&m.subs, 1) | ||
65 | } | ||
66 | |||
67 | func (m *measureDescriptor) subscribed() bool { | ||
68 | return atomic.LoadInt32(&m.subs) == 1 | ||
69 | } | ||
70 | |||
71 | // Name returns the name of the measure. | ||
72 | func (m *measureDescriptor) Name() string { | ||
73 | return m.name | ||
74 | } | ||
75 | |||
76 | // Description returns the description of the measure. | ||
77 | func (m *measureDescriptor) Description() string { | ||
78 | return m.description | ||
79 | } | ||
80 | |||
81 | // Unit returns the unit of the measure. | ||
82 | func (m *measureDescriptor) Unit() string { | ||
83 | return m.unit | ||
84 | } | ||
85 | |||
86 | var ( | ||
87 | mu sync.RWMutex | ||
88 | measures = make(map[string]*measureDescriptor) | ||
89 | ) | ||
90 | |||
91 | func 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. | ||
110 | type Measurement struct { | ||
111 | v float64 | ||
112 | m *measureDescriptor | ||
113 | } | ||
114 | |||
115 | // Value returns the value of the Measurement as a float64. | ||
116 | func (m Measurement) Value() float64 { | ||
117 | return m.v | ||
118 | } | ||
119 | |||
120 | // Measure returns the Measure from which this Measurement was created. | ||
121 | func (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 | |||
16 | package stats | ||
17 | |||
18 | // Float64Measure is a measure for float64 values. | ||
19 | type Float64Measure struct { | ||
20 | *measureDescriptor | ||
21 | } | ||
22 | |||
23 | // M creates a new float64 measurement. | ||
24 | // Use Record to record measurements. | ||
25 | func (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. | ||
33 | func 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 | |||
16 | package stats | ||
17 | |||
18 | // Int64Measure is a measure for int64 values. | ||
19 | type Int64Measure struct { | ||
20 | *measureDescriptor | ||
21 | } | ||
22 | |||
23 | // M creates a new int64 measurement. | ||
24 | // Use Record to record measurements. | ||
25 | func (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. | ||
33 | func 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 | |||
16 | package stats | ||
17 | |||
18 | import ( | ||
19 | "context" | ||
20 | |||
21 | "go.opencensus.io/exemplar" | ||
22 | "go.opencensus.io/stats/internal" | ||
23 | "go.opencensus.io/tag" | ||
24 | ) | ||
25 | |||
26 | func 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. | ||
36 | func 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. | ||
62 | func 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 | |||
16 | package 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 | ||
20 | const ( | ||
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 | |||
16 | package view | ||
17 | |||
18 | // AggType represents the type of aggregation function used on a View. | ||
19 | type AggType int | ||
20 | |||
21 | // All available aggregation types. | ||
22 | const ( | ||
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 | |||
30 | func (t AggType) String() string { | ||
31 | return aggTypeName[t] | ||
32 | } | ||
33 | |||
34 | var 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. | ||
44 | type 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 | |||
51 | var ( | ||
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. | ||
70 | func 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. | ||
78 | func 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. | ||
101 | func 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. | ||
113 | func 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 | |||
16 | package view | ||
17 | |||
18 | import ( | ||
19 | "math" | ||
20 | |||
21 | "go.opencensus.io/exemplar" | ||
22 | ) | ||
23 | |||
24 | // AggregationData represents an aggregated value from a collection. | ||
25 | // They are reported on the view data during exporting. | ||
26 | // Mosts users won't directly access aggregration data. | ||
27 | type AggregationData interface { | ||
28 | isAggregationData() bool | ||
29 | addSample(e *exemplar.Exemplar) | ||
30 | clone() AggregationData | ||
31 | equal(other AggregationData) bool | ||
32 | } | ||
33 | |||
34 | const epsilon = 1e-9 | ||
35 | |||
36 | // CountData is the aggregated data for the Count aggregation. | ||
37 | // A count aggregation processes data and counts the recordings. | ||
38 | // | ||
39 | // Most users won't directly access count data. | ||
40 | type CountData struct { | ||
41 | Value int64 | ||
42 | } | ||
43 | |||
44 | func (a *CountData) isAggregationData() bool { return true } | ||
45 | |||
46 | func (a *CountData) addSample(_ *exemplar.Exemplar) { | ||
47 | a.Value = a.Value + 1 | ||
48 | } | ||
49 | |||
50 | func (a *CountData) clone() AggregationData { | ||
51 | return &CountData{Value: a.Value} | ||
52 | } | ||
53 | |||
54 | func (a *CountData) equal(other AggregationData) bool { | ||
55 | a2, ok := other.(*CountData) | ||
56 | if !ok { | ||
57 | return false | ||
58 | } | ||
59 | |||
60 | return a.Value == a2.Value | ||
61 | } | ||
62 | |||
63 | // SumData is the aggregated data for the Sum aggregation. | ||
64 | // A sum aggregation processes data and sums up the recordings. | ||
65 | // | ||
66 | // Most users won't directly access sum data. | ||
67 | type SumData struct { | ||
68 | Value float64 | ||
69 | } | ||
70 | |||
71 | func (a *SumData) isAggregationData() bool { return true } | ||
72 | |||
73 | func (a *SumData) addSample(e *exemplar.Exemplar) { | ||
74 | a.Value += e.Value | ||
75 | } | ||
76 | |||
77 | func (a *SumData) clone() AggregationData { | ||
78 | return &SumData{Value: a.Value} | ||
79 | } | ||
80 | |||
81 | func (a *SumData) equal(other AggregationData) bool { | ||
82 | a2, ok := other.(*SumData) | ||
83 | if !ok { | ||
84 | return false | ||
85 | } | ||
86 | return math.Pow(a.Value-a2.Value, 2) < epsilon | ||
87 | } | ||
88 | |||
89 | // DistributionData is the aggregated data for the | ||
90 | // Distribution aggregation. | ||
91 | // | ||
92 | // Most users won't directly access distribution data. | ||
93 | // | ||
94 | // For a distribution with N bounds, the associated DistributionData will have | ||
95 | // N+1 buckets. | ||
96 | type DistributionData struct { | ||
97 | Count int64 // number of data points aggregated | ||
98 | Min float64 // minimum value in the distribution | ||
99 | Max float64 // max value in the distribution | ||
100 | Mean float64 // mean of the distribution | ||
101 | SumOfSquaredDev float64 // sum of the squared deviation from the mean | ||
102 | CountPerBucket []int64 // number of occurrences per bucket | ||
103 | // ExemplarsPerBucket is slice the same length as CountPerBucket containing | ||
104 | // an exemplar for the associated bucket, or nil. | ||
105 | ExemplarsPerBucket []*exemplar.Exemplar | ||
106 | bounds []float64 // histogram distribution of the values | ||
107 | } | ||
108 | |||
109 | func newDistributionData(bounds []float64) *DistributionData { | ||
110 | bucketCount := len(bounds) + 1 | ||
111 | return &DistributionData{ | ||
112 | CountPerBucket: make([]int64, bucketCount), | ||
113 | ExemplarsPerBucket: make([]*exemplar.Exemplar, bucketCount), | ||
114 | bounds: bounds, | ||
115 | Min: math.MaxFloat64, | ||
116 | Max: math.SmallestNonzeroFloat64, | ||
117 | } | ||
118 | } | ||
119 | |||
120 | // Sum returns the sum of all samples collected. | ||
121 | func (a *DistributionData) Sum() float64 { return a.Mean * float64(a.Count) } | ||
122 | |||
123 | func (a *DistributionData) variance() float64 { | ||
124 | if a.Count <= 1 { | ||
125 | return 0 | ||
126 | } | ||
127 | return a.SumOfSquaredDev / float64(a.Count-1) | ||
128 | } | ||
129 | |||
130 | func (a *DistributionData) isAggregationData() bool { return true } | ||
131 | |||
132 | func (a *DistributionData) addSample(e *exemplar.Exemplar) { | ||
133 | f := e.Value | ||
134 | if f < a.Min { | ||
135 | a.Min = f | ||
136 | } | ||
137 | if f > a.Max { | ||
138 | a.Max = f | ||
139 | } | ||
140 | a.Count++ | ||
141 | a.addToBucket(e) | ||
142 | |||
143 | if a.Count == 1 { | ||
144 | a.Mean = f | ||
145 | return | ||
146 | } | ||
147 | |||
148 | oldMean := a.Mean | ||
149 | a.Mean = a.Mean + (f-a.Mean)/float64(a.Count) | ||
150 | a.SumOfSquaredDev = a.SumOfSquaredDev + (f-oldMean)*(f-a.Mean) | ||
151 | } | ||
152 | |||
153 | func (a *DistributionData) addToBucket(e *exemplar.Exemplar) { | ||
154 | var count *int64 | ||
155 | var ex **exemplar.Exemplar | ||
156 | for i, b := range a.bounds { | ||
157 | if e.Value < b { | ||
158 | count = &a.CountPerBucket[i] | ||
159 | ex = &a.ExemplarsPerBucket[i] | ||
160 | break | ||
161 | } | ||
162 | } | ||
163 | if count == nil { | ||
164 | count = &a.CountPerBucket[len(a.bounds)] | ||
165 | ex = &a.ExemplarsPerBucket[len(a.bounds)] | ||
166 | } | ||
167 | *count++ | ||
168 | *ex = maybeRetainExemplar(*ex, e) | ||
169 | } | ||
170 | |||
171 | func maybeRetainExemplar(old, cur *exemplar.Exemplar) *exemplar.Exemplar { | ||
172 | if old == nil { | ||
173 | return cur | ||
174 | } | ||
175 | |||
176 | // Heuristic to pick the "better" exemplar: first keep the one with a | ||
177 | // sampled trace attachment, if neither have a trace attachment, pick the | ||
178 | // one with more attachments. | ||
179 | _, haveTraceID := cur.Attachments[exemplar.KeyTraceID] | ||
180 | if haveTraceID || len(cur.Attachments) >= len(old.Attachments) { | ||
181 | return cur | ||
182 | } | ||
183 | return old | ||
184 | } | ||
185 | |||
186 | func (a *DistributionData) clone() AggregationData { | ||
187 | c := *a | ||
188 | c.CountPerBucket = append([]int64(nil), a.CountPerBucket...) | ||
189 | c.ExemplarsPerBucket = append([]*exemplar.Exemplar(nil), a.ExemplarsPerBucket...) | ||
190 | return &c | ||
191 | } | ||
192 | |||
193 | func (a *DistributionData) equal(other AggregationData) bool { | ||
194 | a2, ok := other.(*DistributionData) | ||
195 | if !ok { | ||
196 | return false | ||
197 | } | ||
198 | if a2 == nil { | ||
199 | return false | ||
200 | } | ||
201 | if len(a.CountPerBucket) != len(a2.CountPerBucket) { | ||
202 | return false | ||
203 | } | ||
204 | for i := range a.CountPerBucket { | ||
205 | if a.CountPerBucket[i] != a2.CountPerBucket[i] { | ||
206 | return false | ||
207 | } | ||
208 | } | ||
209 | return a.Count == a2.Count && a.Min == a2.Min && a.Max == a2.Max && math.Pow(a.Mean-a2.Mean, 2) < epsilon && math.Pow(a.variance()-a2.variance(), 2) < epsilon | ||
210 | } | ||
211 | |||
212 | // LastValueData returns the last value recorded for LastValue aggregation. | ||
213 | type LastValueData struct { | ||
214 | Value float64 | ||
215 | } | ||
216 | |||
217 | func (l *LastValueData) isAggregationData() bool { | ||
218 | return true | ||
219 | } | ||
220 | |||
221 | func (l *LastValueData) addSample(e *exemplar.Exemplar) { | ||
222 | l.Value = e.Value | ||
223 | } | ||
224 | |||
225 | func (l *LastValueData) clone() AggregationData { | ||
226 | return &LastValueData{l.Value} | ||
227 | } | ||
228 | |||
229 | func (l *LastValueData) equal(other AggregationData) bool { | ||
230 | a2, ok := other.(*LastValueData) | ||
231 | if !ok { | ||
232 | return false | ||
233 | } | ||
234 | return l.Value == a2.Value | ||
235 | } | ||
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 | |||
16 | package view | ||
17 | |||
18 | import ( | ||
19 | "sort" | ||
20 | |||
21 | "go.opencensus.io/exemplar" | ||
22 | |||
23 | "go.opencensus.io/internal/tagencoding" | ||
24 | "go.opencensus.io/tag" | ||
25 | ) | ||
26 | |||
27 | type 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 | |||
36 | func (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. | ||
46 | func (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 | |||
56 | func (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. | ||
62 | func 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. | ||
75 | func 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. | ||
44 | package 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 | |||
15 | package view | ||
16 | |||
17 | import "sync" | ||
18 | |||
19 | var ( | ||
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. | ||
34 | type 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. | ||
45 | func RegisterExporter(e Exporter) { | ||
46 | exportersMu.Lock() | ||
47 | defer exportersMu.Unlock() | ||
48 | |||
49 | exporters[e] = struct{}{} | ||
50 | } | ||
51 | |||
52 | // UnregisterExporter unregisters an exporter. | ||
53 | func 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 | |||
16 | package view | ||
17 | |||
18 | import ( | ||
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. | ||
36 | type 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. | ||
54 | func (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. | ||
61 | func (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 | ||
74 | func (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. | ||
97 | type 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 | |||
103 | func newViewInternal(v *View) (*viewInternal, error) { | ||
104 | return &viewInternal{ | ||
105 | view: v, | ||
106 | collector: &collector{make(map[string]AggregationData), v.Aggregation}, | ||
107 | }, nil | ||
108 | } | ||
109 | |||
110 | func (v *viewInternal) subscribe() { | ||
111 | atomic.StoreUint32(&v.subscribed, 1) | ||
112 | } | ||
113 | |||
114 | func (v *viewInternal) unsubscribe() { | ||
115 | atomic.StoreUint32(&v.subscribed, 0) | ||
116 | } | ||
117 | |||
118 | // isSubscribed returns true if the view is exporting | ||
119 | // data by subscription. | ||
120 | func (v *viewInternal) isSubscribed() bool { | ||
121 | return atomic.LoadUint32(&v.subscribed) == 1 | ||
122 | } | ||
123 | |||
124 | func (v *viewInternal) clearRows() { | ||
125 | v.collector.clearRows() | ||
126 | } | ||
127 | |||
128 | func (v *viewInternal) collectedRows() []*Row { | ||
129 | return v.collector.collectedRows(v.view.TagKeys) | ||
130 | } | ||
131 | |||
132 | func (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. | ||
142 | type 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. | ||
149 | type Row struct { | ||
150 | Tags []tag.Tag | ||
151 | Data AggregationData | ||
152 | } | ||
153 | |||
154 | func (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. | ||
170 | func (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 | |||
177 | func 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 | |||
16 | package view | ||
17 | |||
18 | import ( | ||
19 | "fmt" | ||
20 | "time" | ||
21 | |||
22 | "go.opencensus.io/stats" | ||
23 | "go.opencensus.io/stats/internal" | ||
24 | "go.opencensus.io/tag" | ||
25 | ) | ||
26 | |||
27 | func init() { | ||
28 | defaultWorker = newWorker() | ||
29 | go defaultWorker.start() | ||
30 | internal.DefaultRecorder = record | ||
31 | } | ||
32 | |||
33 | type measureRef struct { | ||
34 | measure string | ||
35 | views map[*viewInternal]struct{} | ||
36 | } | ||
37 | |||
38 | type 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 | |||
48 | var defaultWorker *worker | ||
49 | |||
50 | var 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. | ||
54 | func 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. | ||
66 | func Register(views ...*View) error { | ||
67 | for _, v := range views { | ||
68 | if err := v.canonicalize(); err != nil { | ||
69 | return err | ||
70 | } | ||
71 | } | ||
72 | req := ®isterViewReq{ | ||
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. | ||
84 | func 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. | ||
99 | func 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 | |||
110 | func 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. | ||
127 | func 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 | |||
138 | func 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 | |||
150 | func (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 | |||
166 | func (w *worker) stop() { | ||
167 | w.quit <- true | ||
168 | <-w.done | ||
169 | } | ||
170 | |||
171 | func (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 | |||
183 | func (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 | |||
203 | func (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 | |||
225 | func (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 | |||
16 | package view | ||
17 | |||
18 | import ( | ||
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 | |||
31 | type command interface { | ||
32 | handleCommand(w *worker) | ||
33 | } | ||
34 | |||
35 | // getViewByNameReq is the command to get a view given its name. | ||
36 | type getViewByNameReq struct { | ||
37 | name string | ||
38 | c chan *getViewByNameResp | ||
39 | } | ||
40 | |||
41 | type getViewByNameResp struct { | ||
42 | v *View | ||
43 | } | ||
44 | |||
45 | func (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. | ||
55 | type registerViewReq struct { | ||
56 | views []*View | ||
57 | err chan error | ||
58 | } | ||
59 | |||
60 | func (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. | ||
81 | type unregisterFromViewReq struct { | ||
82 | views []string | ||
83 | done chan struct{} | ||
84 | } | ||
85 | |||
86 | func (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. | ||
108 | type retrieveDataReq struct { | ||
109 | now time.Time | ||
110 | v string | ||
111 | c chan *retrieveDataResp | ||
112 | } | ||
113 | |||
114 | type retrieveDataResp struct { | ||
115 | rows []*Row | ||
116 | err error | ||
117 | } | ||
118 | |||
119 | func (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. | ||
144 | type recordReq struct { | ||
145 | tm *tag.Map | ||
146 | ms []stats.Measurement | ||
147 | attachments map[string]string | ||
148 | t time.Time | ||
149 | } | ||
150 | |||
151 | func (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. | ||
170 | type setReportingPeriodReq struct { | ||
171 | d time.Duration | ||
172 | c chan bool | ||
173 | } | ||
174 | |||
175 | func (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 | } | ||