aboutsummaryrefslogtreecommitdiff
path: root/vendor/go.opencensus.io/stats
diff options
context:
space:
mode:
authorNiall Sheridan <nsheridan@gmail.com>2018-06-20 22:39:07 +0100
committerNiall Sheridan <nsheridan@gmail.com>2018-06-20 22:39:07 +0100
commitde6d2c524430287c699aaa898c1325da6afea539 (patch)
treef78eb841208d667668a7bc92a9290d693cc7103b /vendor/go.opencensus.io/stats
parenteb99016e1629e690e55633de6fc63a14c53e7ea2 (diff)
Update dependencies
Diffstat (limited to 'vendor/go.opencensus.io/stats')
-rw-r--r--vendor/go.opencensus.io/stats/doc.go55
-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.go96
-rw-r--r--vendor/go.opencensus.io/stats/measure_float64.go52
-rw-r--r--vendor/go.opencensus.io/stats/measure_int64.go52
-rw-r--r--vendor/go.opencensus.io/stats/record.go52
-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.go207
-rw-r--r--vendor/go.opencensus.io/stats/view/collector.go84
-rw-r--r--vendor/go.opencensus.io/stats/view/doc.go46
-rw-r--r--vendor/go.opencensus.io/stats/view/export.go55
-rw-r--r--vendor/go.opencensus.io/stats/view/view.go183
-rw-r--r--vendor/go.opencensus.io/stats/view/worker.go233
-rw-r--r--vendor/go.opencensus.io/stats/view/worker_commands.go171
16 files changed, 1484 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..7a8a62c
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/doc.go
@@ -0,0 +1,55 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/*
+Package stats contains support for OpenCensus stats recording.
+
+OpenCensus allows users to create typed measures, record measurements,
+aggregate the collected data, and export the aggregated data.
+
+Measures
+
+A measure represents a type of metric to be tracked and recorded.
+For example, latency, request Mb/s, and response Mb/s are measures
+to collect from a server.
+
+Each measure needs to be registered before being used. Measure
+constructors such as Int64 and Float64 automatically
+register the measure by the given name. Each registered measure needs
+to be unique by name. Measures also have a description and a unit.
+
+Libraries can define and export measures for their end users to
+create views and collect instrumentation data.
+
+Recording measurements
+
+Measurement is a data point to be collected for a measure. For example,
+for a latency (ms) measure, 100 is a measurement that represents a 100ms
+latency event. Users collect data points on the existing measures with
+the current context. Tags from the current context are recorded with the
+measurements if they are any.
+
+Recorded measurements are dropped immediately if user is not aggregating
+them via views. Users don't necessarily need to conditionally enable/disable
+recording to reduce cost. Recording of measurements is cheap.
+
+Libraries can always record measurements, and end-users can later decide
+on which measurements they want to collect by registering views. This allows
+libraries to turn on the instrumentation by default.
+*/
+package stats // import "go.opencensus.io/stats"
+
+// TODO(acetechnologist): Add a link to the language independent OpenCensus
+// spec when it is available.
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..6341eb2
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/internal/record.go
@@ -0,0 +1,25 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package internal
+
+import (
+ "go.opencensus.io/tag"
+)
+
+// DefaultRecorder will be called for each Record call.
+var DefaultRecorder func(*tag.Map, interface{})
+
+// SubscriptionReporter reports when a view subscribed with a measure.
+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 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package internal // import "go.opencensus.io/stats/internal"
+
+const (
+ MaxNameLength = 255
+)
+
+func IsPrintable(str string) bool {
+ for _, r := range str {
+ if !(r >= ' ' && r <= '~') {
+ return false
+ }
+ }
+ return true
+}
diff --git a/vendor/go.opencensus.io/stats/measure.go b/vendor/go.opencensus.io/stats/measure.go
new file mode 100644
index 0000000..aa555c2
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/measure.go
@@ -0,0 +1,96 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package stats
+
+import (
+ "sync"
+ "sync/atomic"
+)
+
+// Measure represents a type of metric to be tracked and recorded.
+// For example, latency, request Mb/s, and response Mb/s are measures
+// to collect from a server.
+//
+// Each measure needs to be registered before being used.
+// Measure constructors such as Int64 and
+// Float64 automatically registers the measure
+// by the given name.
+// Each registered measure needs to be unique by name.
+// Measures also have a description and a unit.
+type Measure interface {
+ Name() string
+ Description() string
+ Unit() string
+}
+
+// measureDescriptor is the untyped descriptor associated with each measure.
+// Int64Measure and Float64Measure wrap measureDescriptor to provide typed
+// recording APIs.
+// Two Measures with the same name will have the same measureDescriptor.
+type measureDescriptor struct {
+ subs int32 // access atomically
+
+ name string
+ description string
+ unit string
+}
+
+func (m *measureDescriptor) subscribe() {
+ atomic.StoreInt32(&m.subs, 1)
+}
+
+func (m *measureDescriptor) subscribed() bool {
+ return atomic.LoadInt32(&m.subs) == 1
+}
+
+var (
+ mu sync.RWMutex
+ measures = make(map[string]*measureDescriptor)
+)
+
+func registerMeasureHandle(name, desc, unit string) *measureDescriptor {
+ mu.Lock()
+ defer mu.Unlock()
+
+ if stored, ok := measures[name]; ok {
+ return stored
+ }
+ m := &measureDescriptor{
+ name: name,
+ description: desc,
+ unit: unit,
+ }
+ measures[name] = m
+ return m
+}
+
+// Measurement is the numeric value measured when recording stats. Each measure
+// provides methods to create measurements of their kind. For example, Int64Measure
+// provides M to convert an int64 into a measurement.
+type Measurement struct {
+ v float64
+ m Measure
+}
+
+// Value returns the value of the Measurement as a float64.
+func (m Measurement) Value() float64 {
+ return m.v
+}
+
+// Measure returns the Measure from which this Measurement was created.
+func (m Measurement) Measure() Measure {
+ return m.m
+}
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..8de6b52
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/measure_float64.go
@@ -0,0 +1,52 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package stats
+
+// Float64Measure is a measure of type float64.
+type Float64Measure struct {
+ md *measureDescriptor
+}
+
+// Name returns the name of the measure.
+func (m *Float64Measure) Name() string {
+ return m.md.name
+}
+
+// Description returns the description of the measure.
+func (m *Float64Measure) Description() string {
+ return m.md.description
+}
+
+// Unit returns the unit of the measure.
+func (m *Float64Measure) Unit() string {
+ return m.md.unit
+}
+
+// M creates a new float64 measurement.
+// Use Record to record measurements.
+func (m *Float64Measure) M(v float64) Measurement {
+ if !m.md.subscribed() {
+ return Measurement{}
+ }
+ return Measurement{m: m, v: v}
+}
+
+// Float64 creates a new measure of type Float64Measure.
+// It never returns an error.
+func Float64(name, description, unit string) *Float64Measure {
+ mi := registerMeasureHandle(name, description, unit)
+ return &Float64Measure{mi}
+}
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..b6fd25f
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/measure_int64.go
@@ -0,0 +1,52 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package stats
+
+// Int64Measure is a measure of type int64.
+type Int64Measure struct {
+ md *measureDescriptor
+}
+
+// Name returns the name of the measure.
+func (m *Int64Measure) Name() string {
+ return m.md.name
+}
+
+// Description returns the description of the measure.
+func (m *Int64Measure) Description() string {
+ return m.md.description
+}
+
+// Unit returns the unit of the measure.
+func (m *Int64Measure) Unit() string {
+ return m.md.unit
+}
+
+// M creates a new int64 measurement.
+// Use Record to record measurements.
+func (m *Int64Measure) M(v int64) Measurement {
+ if !m.md.subscribed() {
+ return Measurement{}
+ }
+ return Measurement{m: m, v: float64(v)}
+}
+
+// Int64 creates a new measure of type Int64Measure.
+// It never returns an error.
+func Int64(name, description, unit string) *Int64Measure {
+ mi := registerMeasureHandle(name, description, unit)
+ return &Int64Measure{mi}
+}
diff --git a/vendor/go.opencensus.io/stats/record.go b/vendor/go.opencensus.io/stats/record.go
new file mode 100644
index 0000000..98865ff
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/record.go
@@ -0,0 +1,52 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package stats
+
+import (
+ "context"
+
+ "go.opencensus.io/stats/internal"
+ "go.opencensus.io/tag"
+)
+
+func init() {
+ internal.SubscriptionReporter = func(measure string) {
+ mu.Lock()
+ measures[measure].subscribe()
+ mu.Unlock()
+ }
+}
+
+// Record records one or multiple measurements with the same tags at once.
+// If there are any tags in the context, measurements will be tagged with them.
+func Record(ctx context.Context, ms ...Measurement) {
+ if len(ms) == 0 {
+ return
+ }
+ var record bool
+ for _, m := range ms {
+ if (m != Measurement{}) {
+ record = true
+ break
+ }
+ }
+ if !record {
+ return
+ }
+ if internal.DefaultRecorder != nil {
+ internal.DefaultRecorder(tag.FromContext(ctx), ms)
+ }
+}
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 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package stats
+
+// Units are encoded according to the case-sensitive abbreviations from the
+// Unified Code for Units of Measure: http://unitsofmeasure.org/ucum.html
+const (
+ UnitNone = "1" // Deprecated: Use UnitDimensionless.
+ UnitDimensionless = "1"
+ UnitBytes = "By"
+ UnitMilliseconds = "ms"
+)
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 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package view
+
+// AggType represents the type of aggregation function used on a View.
+type AggType int
+
+// All available aggregation types.
+const (
+ AggTypeNone AggType = iota // no aggregation; reserved for future use.
+ AggTypeCount // the count aggregation, see Count.
+ AggTypeSum // the sum aggregation, see Sum.
+ AggTypeDistribution // the distribution aggregation, see Distribution.
+ AggTypeLastValue // the last value aggregation, see LastValue.
+)
+
+func (t AggType) String() string {
+ return aggTypeName[t]
+}
+
+var aggTypeName = map[AggType]string{
+ AggTypeNone: "None",
+ AggTypeCount: "Count",
+ AggTypeSum: "Sum",
+ AggTypeDistribution: "Distribution",
+ AggTypeLastValue: "LastValue",
+}
+
+// Aggregation represents a data aggregation method. Use one of the functions:
+// Count, Sum, or Distribution to construct an Aggregation.
+type Aggregation struct {
+ Type AggType // Type is the AggType of this Aggregation.
+ Buckets []float64 // Buckets are the bucket endpoints if this Aggregation represents a distribution, see Distribution.
+
+ newData func() AggregationData
+}
+
+var (
+ aggCount = &Aggregation{
+ Type: AggTypeCount,
+ newData: func() AggregationData {
+ return &CountData{}
+ },
+ }
+ aggSum = &Aggregation{
+ Type: AggTypeSum,
+ newData: func() AggregationData {
+ return &SumData{}
+ },
+ }
+)
+
+// Count indicates that data collected and aggregated
+// with this method will be turned into a count value.
+// For example, total number of accepted requests can be
+// aggregated by using Count.
+func Count() *Aggregation {
+ return aggCount
+}
+
+// Sum indicates that data collected and aggregated
+// with this method will be summed up.
+// For example, accumulated request bytes can be aggregated by using
+// Sum.
+func Sum() *Aggregation {
+ return aggSum
+}
+
+// Distribution indicates that the desired aggregation is
+// a histogram distribution.
+//
+// An distribution aggregation may contain a histogram of the values in the
+// population. The bucket boundaries for that histogram are described
+// by the bounds. This defines len(bounds)+1 buckets.
+//
+// If len(bounds) >= 2 then the boundaries for bucket index i are:
+//
+// [-infinity, bounds[i]) for i = 0
+// [bounds[i-1], bounds[i]) for 0 < i < length
+// [bounds[i-1], +infinity) for i = length
+//
+// If len(bounds) is 0 then there is no histogram associated with the
+// distribution. There will be a single bucket with boundaries
+// (-infinity, +infinity).
+//
+// If len(bounds) is 1 then there is no finite buckets, and that single
+// element is the common boundary of the overflow and underflow buckets.
+func Distribution(bounds ...float64) *Aggregation {
+ return &Aggregation{
+ Type: AggTypeDistribution,
+ Buckets: bounds,
+ newData: func() AggregationData {
+ return newDistributionData(bounds)
+ },
+ }
+}
+
+// LastValue only reports the last value recorded using this
+// aggregation. All other measurements will be dropped.
+func LastValue() *Aggregation {
+ return &Aggregation{
+ Type: AggTypeLastValue,
+ newData: func() AggregationData {
+ return &LastValueData{}
+ },
+ }
+}
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..88c500b
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/aggregation_data.go
@@ -0,0 +1,207 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package view
+
+import (
+ "math"
+)
+
+// AggregationData represents an aggregated value from a collection.
+// They are reported on the view data during exporting.
+// Mosts users won't directly access aggregration data.
+type AggregationData interface {
+ isAggregationData() bool
+ addSample(v float64)
+ clone() AggregationData
+ equal(other AggregationData) bool
+}
+
+const epsilon = 1e-9
+
+// CountData is the aggregated data for the Count aggregation.
+// A count aggregation processes data and counts the recordings.
+//
+// Most users won't directly access count data.
+type CountData struct {
+ Value int64
+}
+
+func (a *CountData) isAggregationData() bool { return true }
+
+func (a *CountData) addSample(v float64) {
+ a.Value = a.Value + 1
+}
+
+func (a *CountData) clone() AggregationData {
+ return &CountData{Value: a.Value}
+}
+
+func (a *CountData) equal(other AggregationData) bool {
+ a2, ok := other.(*CountData)
+ if !ok {
+ return false
+ }
+
+ return a.Value == a2.Value
+}
+
+// SumData is the aggregated data for the Sum aggregation.
+// A sum aggregation processes data and sums up the recordings.
+//
+// Most users won't directly access sum data.
+type SumData struct {
+ Value float64
+}
+
+func (a *SumData) isAggregationData() bool { return true }
+
+func (a *SumData) addSample(f float64) {
+ a.Value += f
+}
+
+func (a *SumData) clone() AggregationData {
+ return &SumData{Value: a.Value}
+}
+
+func (a *SumData) equal(other AggregationData) bool {
+ a2, ok := other.(*SumData)
+ if !ok {
+ return false
+ }
+ return math.Pow(a.Value-a2.Value, 2) < epsilon
+}
+
+// DistributionData is the aggregated data for the
+// Distribution aggregation.
+//
+// Most users won't directly access distribution data.
+type DistributionData struct {
+ Count int64 // number of data points aggregated
+ Min float64 // minimum value in the distribution
+ Max float64 // max value in the distribution
+ Mean float64 // mean of the distribution
+ SumOfSquaredDev float64 // sum of the squared deviation from the mean
+ CountPerBucket []int64 // number of occurrences per bucket
+ bounds []float64 // histogram distribution of the values
+}
+
+func newDistributionData(bounds []float64) *DistributionData {
+ return &DistributionData{
+ CountPerBucket: make([]int64, len(bounds)+1),
+ bounds: bounds,
+ Min: math.MaxFloat64,
+ Max: math.SmallestNonzeroFloat64,
+ }
+}
+
+// Sum returns the sum of all samples collected.
+func (a *DistributionData) Sum() float64 { return a.Mean * float64(a.Count) }
+
+func (a *DistributionData) variance() float64 {
+ if a.Count <= 1 {
+ return 0
+ }
+ return a.SumOfSquaredDev / float64(a.Count-1)
+}
+
+func (a *DistributionData) isAggregationData() bool { return true }
+
+func (a *DistributionData) addSample(f float64) {
+ if f < a.Min {
+ a.Min = f
+ }
+ if f > a.Max {
+ a.Max = f
+ }
+ a.Count++
+ a.incrementBucketCount(f)
+
+ if a.Count == 1 {
+ a.Mean = f
+ return
+ }
+
+ oldMean := a.Mean
+ a.Mean = a.Mean + (f-a.Mean)/float64(a.Count)
+ a.SumOfSquaredDev = a.SumOfSquaredDev + (f-oldMean)*(f-a.Mean)
+}
+
+func (a *DistributionData) incrementBucketCount(f float64) {
+ if len(a.bounds) == 0 {
+ a.CountPerBucket[0]++
+ return
+ }
+
+ for i, b := range a.bounds {
+ if f < b {
+ a.CountPerBucket[i]++
+ return
+ }
+ }
+ a.CountPerBucket[len(a.bounds)]++
+}
+
+func (a *DistributionData) clone() AggregationData {
+ counts := make([]int64, len(a.CountPerBucket))
+ copy(counts, a.CountPerBucket)
+ c := *a
+ c.CountPerBucket = counts
+ return &c
+}
+
+func (a *DistributionData) equal(other AggregationData) bool {
+ a2, ok := other.(*DistributionData)
+ if !ok {
+ return false
+ }
+ if a2 == nil {
+ return false
+ }
+ if len(a.CountPerBucket) != len(a2.CountPerBucket) {
+ return false
+ }
+ for i := range a.CountPerBucket {
+ if a.CountPerBucket[i] != a2.CountPerBucket[i] {
+ return false
+ }
+ }
+ 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
+}
+
+// LastValueData returns the last value recorded for LastValue aggregation.
+type LastValueData struct {
+ Value float64
+}
+
+func (l *LastValueData) isAggregationData() bool {
+ return true
+}
+
+func (l *LastValueData) addSample(v float64) {
+ l.Value = v
+}
+
+func (l *LastValueData) clone() AggregationData {
+ return &LastValueData{l.Value}
+}
+
+func (l *LastValueData) equal(other AggregationData) bool {
+ a2, ok := other.(*LastValueData)
+ if !ok {
+ return false
+ }
+ return l.Value == a2.Value
+}
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..863a5b6
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/collector.go
@@ -0,0 +1,84 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package view
+
+import (
+ "sort"
+
+ "go.opencensus.io/internal/tagencoding"
+ "go.opencensus.io/tag"
+)
+
+type collector struct {
+ // signatures holds the aggregations values for each unique tag signature
+ // (values for all keys) to its aggregator.
+ signatures map[string]AggregationData
+ // Aggregation is the description of the aggregation to perform for this
+ // view.
+ a *Aggregation
+}
+
+func (c *collector) addSample(s string, v float64) {
+ aggregator, ok := c.signatures[s]
+ if !ok {
+ aggregator = c.a.newData()
+ c.signatures[s] = aggregator
+ }
+ aggregator.addSample(v)
+}
+
+func (c *collector) collectedRows(keys []tag.Key) []*Row {
+ var rows []*Row
+ for sig, aggregator := range c.signatures {
+ tags := decodeTags([]byte(sig), keys)
+ row := &Row{tags, aggregator}
+ rows = append(rows, row)
+ }
+ return rows
+}
+
+func (c *collector) clearRows() {
+ c.signatures = make(map[string]AggregationData)
+}
+
+// encodeWithKeys encodes the map by using values
+// only associated with the keys provided.
+func encodeWithKeys(m *tag.Map, keys []tag.Key) []byte {
+ vb := &tagencoding.Values{
+ Buffer: make([]byte, len(keys)),
+ }
+ for _, k := range keys {
+ v, _ := m.Value(k)
+ vb.WriteValue([]byte(v))
+ }
+ return vb.Bytes()
+}
+
+// decodeTags decodes tags from the buffer and
+// orders them by the keys.
+func decodeTags(buf []byte, keys []tag.Key) []tag.Tag {
+ vb := &tagencoding.Values{Buffer: buf}
+ var tags []tag.Tag
+ for _, k := range keys {
+ v := vb.ReadValue()
+ if v != nil {
+ tags = append(tags, tag.Tag{Key: k, Value: string(v)})
+ }
+ }
+ vb.ReadIndex = 0
+ sort.Slice(tags, func(i, j int) bool { return tags[i].Key.Name() < tags[j].Key.Name() })
+ return tags
+}
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..856fb4e
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/doc.go
@@ -0,0 +1,46 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/*
+Package view contains support for collecting and exposing aggregates over stats.
+
+In order to collect measurements, views need to be defined and registered.
+A view allows recorded measurements to be filtered and aggregated over a time window.
+
+All recorded measurements can be filtered by a list of tags.
+
+OpenCensus provides several aggregation methods: count, distribution and sum.
+Count aggregation only counts the number of measurement points. Distribution
+aggregation provides statistical summary of the aggregated data. Sum distribution
+sums up the measurement points. Aggregations are cumulative.
+
+Users can dynamically create and delete views.
+
+Libraries can export their own views and claim the view names
+by registering them themselves.
+
+Exporting
+
+Collected and aggregated data can be exported to a metric collection
+backend by registering its exporter.
+
+Multiple exporters can be registered to upload the data to various
+different backends. Users need to unregister the exporters once they
+no longer are needed.
+*/
+package view // import "go.opencensus.io/stats/view"
+
+// TODO(acetechnologist): Add a link to the language independent OpenCensus
+// 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..ffd0d1a
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/export.go
@@ -0,0 +1,55 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package view
+
+import "sync"
+
+var (
+ exportersMu sync.RWMutex // guards exporters
+ exporters = make(map[Exporter]struct{})
+)
+
+// Exporter exports the collected records as view data.
+//
+// The ExportView method should return quickly; if an
+// Exporter takes a significant amount of time to
+// process a Data, that work should be done on another goroutine.
+//
+// The Data should not be modified.
+type Exporter interface {
+ ExportView(viewData *Data)
+}
+
+// RegisterExporter registers an exporter.
+// Collected data will be reported via all the
+// registered exporters. Once you no longer
+// want data to be exported, invoke UnregisterExporter
+// with the previously registered exporter.
+//
+// Binaries can register exporters, libraries shouldn't register exporters.
+func RegisterExporter(e Exporter) {
+ exportersMu.Lock()
+ defer exportersMu.Unlock()
+
+ exporters[e] = struct{}{}
+}
+
+// UnregisterExporter unregisters an exporter.
+func UnregisterExporter(e Exporter) {
+ exportersMu.Lock()
+ defer exportersMu.Unlock()
+
+ delete(exporters, e)
+}
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..87bf5d4
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/view.go
@@ -0,0 +1,183 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package view
+
+import (
+ "bytes"
+ "fmt"
+ "reflect"
+ "sort"
+ "sync/atomic"
+ "time"
+
+ "go.opencensus.io/stats"
+ "go.opencensus.io/stats/internal"
+ "go.opencensus.io/tag"
+)
+
+// View allows users to aggregate the recorded stats.Measurements.
+// Views need to be passed to the Subscribe function to be before data will be
+// collected and sent to Exporters.
+type View struct {
+ Name string // Name of View. Must be unique. If unset, will default to the name of the Measure.
+ Description string // Description is a human-readable description for this view.
+
+ // TagKeys are the tag keys describing the grouping of this view.
+ // A single Row will be produced for each combination of associated tag values.
+ TagKeys []tag.Key
+
+ // Measure is a stats.Measure to aggregate in this view.
+ Measure stats.Measure
+
+ // Aggregation is the aggregation function tp apply to the set of Measurements.
+ Aggregation *Aggregation
+}
+
+// WithName returns a copy of the View with a new name. This is useful for
+// renaming views to cope with limitations placed on metric names by various
+// backends.
+func (v *View) WithName(name string) *View {
+ vNew := *v
+ vNew.Name = name
+ return &vNew
+}
+
+// same compares two views and returns true if they represent the same aggregation.
+func (v *View) same(other *View) bool {
+ if v == other {
+ return true
+ }
+ if v == nil {
+ return false
+ }
+ return reflect.DeepEqual(v.Aggregation, other.Aggregation) &&
+ v.Measure.Name() == other.Measure.Name()
+}
+
+// canonicalize canonicalizes v by setting explicit
+// defaults for Name and Description and sorting the TagKeys
+func (v *View) canonicalize() error {
+ if v.Measure == nil {
+ return fmt.Errorf("cannot subscribe view %q: measure not set", v.Name)
+ }
+ if v.Aggregation == nil {
+ return fmt.Errorf("cannot subscribe view %q: aggregation not set", v.Name)
+ }
+ if v.Name == "" {
+ v.Name = v.Measure.Name()
+ }
+ if v.Description == "" {
+ v.Description = v.Measure.Description()
+ }
+ if err := checkViewName(v.Name); err != nil {
+ return err
+ }
+ sort.Slice(v.TagKeys, func(i, j int) bool {
+ return v.TagKeys[i].Name() < v.TagKeys[j].Name()
+ })
+ return nil
+}
+
+// viewInternal is the internal representation of a View.
+type viewInternal struct {
+ view *View // view is the canonicalized View definition associated with this view.
+ subscribed uint32 // 1 if someone is subscribed and data need to be exported, use atomic to access
+ collector *collector
+}
+
+func newViewInternal(v *View) (*viewInternal, error) {
+ return &viewInternal{
+ view: v,
+ collector: &collector{make(map[string]AggregationData), v.Aggregation},
+ }, nil
+}
+
+func (v *viewInternal) subscribe() {
+ atomic.StoreUint32(&v.subscribed, 1)
+}
+
+func (v *viewInternal) unsubscribe() {
+ atomic.StoreUint32(&v.subscribed, 0)
+}
+
+// isSubscribed returns true if the view is exporting
+// data by subscription.
+func (v *viewInternal) isSubscribed() bool {
+ return atomic.LoadUint32(&v.subscribed) == 1
+}
+
+func (v *viewInternal) clearRows() {
+ v.collector.clearRows()
+}
+
+func (v *viewInternal) collectedRows() []*Row {
+ return v.collector.collectedRows(v.view.TagKeys)
+}
+
+func (v *viewInternal) addSample(m *tag.Map, val float64) {
+ if !v.isSubscribed() {
+ return
+ }
+ sig := string(encodeWithKeys(m, v.view.TagKeys))
+ v.collector.addSample(sig, val)
+}
+
+// A Data is a set of rows about usage of the single measure associated
+// with the given view. Each row is specific to a unique set of tags.
+type Data struct {
+ View *View
+ Start, End time.Time
+ Rows []*Row
+}
+
+// Row is the collected value for a specific set of key value pairs a.k.a tags.
+type Row struct {
+ Tags []tag.Tag
+ Data AggregationData
+}
+
+func (r *Row) String() string {
+ var buffer bytes.Buffer
+ buffer.WriteString("{ ")
+ buffer.WriteString("{ ")
+ for _, t := range r.Tags {
+ buffer.WriteString(fmt.Sprintf("{%v %v}", t.Key.Name(), t.Value))
+ }
+ buffer.WriteString(" }")
+ buffer.WriteString(fmt.Sprintf("%v", r.Data))
+ buffer.WriteString(" }")
+ return buffer.String()
+}
+
+// Equal returns true if both rows are equal. Tags are expected to be ordered
+// by the key name. Even both rows have the same tags but the tags appear in
+// different orders it will return false.
+func (r *Row) Equal(other *Row) bool {
+ if r == other {
+ return true
+ }
+ return reflect.DeepEqual(r.Tags, other.Tags) && r.Data.equal(other.Data)
+}
+
+func checkViewName(name string) error {
+ if len(name) > internal.MaxNameLength {
+ return fmt.Errorf("view name cannot be larger than %v", internal.MaxNameLength)
+ }
+ if !internal.IsPrintable(name) {
+ return fmt.Errorf("view name needs to be an ASCII string")
+ }
+ return nil
+}
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..ba9d7fc
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/worker.go
@@ -0,0 +1,233 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package view
+
+import (
+ "fmt"
+ "time"
+
+ "go.opencensus.io/stats"
+ "go.opencensus.io/stats/internal"
+ "go.opencensus.io/tag"
+)
+
+func init() {
+ defaultWorker = newWorker()
+ go defaultWorker.start()
+ internal.DefaultRecorder = record
+}
+
+type measureRef struct {
+ measure string
+ views map[*viewInternal]struct{}
+}
+
+type worker struct {
+ measures map[string]*measureRef
+ views map[string]*viewInternal
+ startTimes map[*viewInternal]time.Time
+
+ timer *time.Ticker
+ c chan command
+ quit, done chan bool
+}
+
+var defaultWorker *worker
+
+var defaultReportingDuration = 10 * time.Second
+
+// Find returns a subscribed view associated with this name.
+// If no subscribed view is found, nil is returned.
+func Find(name string) (v *View) {
+ req := &getViewByNameReq{
+ name: name,
+ c: make(chan *getViewByNameResp),
+ }
+ defaultWorker.c <- req
+ resp := <-req.c
+ return resp.v
+}
+
+// Register begins collecting data for the given views.
+// Once a view is subscribed, it reports data to the registered exporters.
+func Register(views ...*View) error {
+ for _, v := range views {
+ if err := v.canonicalize(); err != nil {
+ return err
+ }
+ }
+ req := &registerViewReq{
+ views: views,
+ err: make(chan error),
+ }
+ defaultWorker.c <- req
+ return <-req.err
+}
+
+// Unregister the given views. Data will not longer be exported for these views
+// after Unregister returns.
+// It is not necessary to unregister from views you expect to collect for the
+// duration of your program execution.
+func Unregister(views ...*View) {
+ names := make([]string, len(views))
+ for i := range views {
+ names[i] = views[i].Name
+ }
+ req := &unregisterFromViewReq{
+ views: names,
+ done: make(chan struct{}),
+ }
+ defaultWorker.c <- req
+ <-req.done
+}
+
+// RetrieveData gets a snapshot of the data collected for the the view registered
+// with the given name. It is intended for testing only.
+func RetrieveData(viewName string) ([]*Row, error) {
+ req := &retrieveDataReq{
+ now: time.Now(),
+ v: viewName,
+ c: make(chan *retrieveDataResp),
+ }
+ defaultWorker.c <- req
+ resp := <-req.c
+ return resp.rows, resp.err
+}
+
+func record(tags *tag.Map, ms interface{}) {
+ req := &recordReq{
+ tm: tags,
+ ms: ms.([]stats.Measurement),
+ }
+ defaultWorker.c <- req
+}
+
+// SetReportingPeriod sets the interval between reporting aggregated views in
+// the program. If duration is less than or
+// equal to zero, it enables the default behavior.
+func SetReportingPeriod(d time.Duration) {
+ // TODO(acetechnologist): ensure that the duration d is more than a certain
+ // value. e.g. 1s
+ req := &setReportingPeriodReq{
+ d: d,
+ c: make(chan bool),
+ }
+ defaultWorker.c <- req
+ <-req.c // don't return until the timer is set to the new duration.
+}
+
+func newWorker() *worker {
+ return &worker{
+ measures: make(map[string]*measureRef),
+ views: make(map[string]*viewInternal),
+ startTimes: make(map[*viewInternal]time.Time),
+ timer: time.NewTicker(defaultReportingDuration),
+ c: make(chan command, 1024),
+ quit: make(chan bool),
+ done: make(chan bool),
+ }
+}
+
+func (w *worker) start() {
+ for {
+ select {
+ case cmd := <-w.c:
+ cmd.handleCommand(w)
+ case <-w.timer.C:
+ w.reportUsage(time.Now())
+ case <-w.quit:
+ w.timer.Stop()
+ close(w.c)
+ w.done <- true
+ return
+ }
+ }
+}
+
+func (w *worker) stop() {
+ w.quit <- true
+ <-w.done
+}
+
+func (w *worker) getMeasureRef(name string) *measureRef {
+ if mr, ok := w.measures[name]; ok {
+ return mr
+ }
+ mr := &measureRef{
+ measure: name,
+ views: make(map[*viewInternal]struct{}),
+ }
+ w.measures[name] = mr
+ return mr
+}
+
+func (w *worker) tryRegisterView(v *View) (*viewInternal, error) {
+ vi, err := newViewInternal(v)
+ if err != nil {
+ return nil, err
+ }
+ if x, ok := w.views[vi.view.Name]; ok {
+ if !x.view.same(vi.view) {
+ return nil, fmt.Errorf("cannot subscribe view %q; a different view with the same name is already subscribed", v.Name)
+ }
+
+ // the view is already registered so there is nothing to do and the
+ // command is considered successful.
+ return x, nil
+ }
+ w.views[vi.view.Name] = vi
+ ref := w.getMeasureRef(vi.view.Measure.Name())
+ ref.views[vi] = struct{}{}
+ return vi, nil
+}
+
+func (w *worker) reportUsage(now time.Time) {
+ for _, v := range w.views {
+ if !v.isSubscribed() {
+ continue
+ }
+ rows := v.collectedRows()
+ _, ok := w.startTimes[v]
+ if !ok {
+ w.startTimes[v] = now
+ }
+ // Make sure collector is never going
+ // to mutate the exported data.
+ rows = deepCopyRowData(rows)
+ viewData := &Data{
+ View: v.view,
+ Start: w.startTimes[v],
+ End: time.Now(),
+ Rows: rows,
+ }
+ exportersMu.Lock()
+ for e := range exporters {
+ e.ExportView(viewData)
+ }
+ exportersMu.Unlock()
+ }
+}
+
+func deepCopyRowData(rows []*Row) []*Row {
+ newRows := make([]*Row, 0, len(rows))
+ for _, r := range rows {
+ newRows = append(newRows, &Row{
+ Data: r.Data.clone(),
+ Tags: r.Tags,
+ })
+ }
+ return newRows
+}
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..ef79ec3
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/worker_commands.go
@@ -0,0 +1,171 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package view
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+ "time"
+
+ "go.opencensus.io/stats"
+ "go.opencensus.io/stats/internal"
+ "go.opencensus.io/tag"
+)
+
+type command interface {
+ handleCommand(w *worker)
+}
+
+// getViewByNameReq is the command to get a view given its name.
+type getViewByNameReq struct {
+ name string
+ c chan *getViewByNameResp
+}
+
+type getViewByNameResp struct {
+ v *View
+}
+
+func (cmd *getViewByNameReq) handleCommand(w *worker) {
+ v := w.views[cmd.name]
+ if v == nil {
+ cmd.c <- &getViewByNameResp{nil}
+ return
+ }
+ cmd.c <- &getViewByNameResp{v.view}
+}
+
+// registerViewReq is the command to register a view.
+type registerViewReq struct {
+ views []*View
+ err chan error
+}
+
+func (cmd *registerViewReq) handleCommand(w *worker) {
+ var errstr []string
+ for _, view := range cmd.views {
+ vi, err := w.tryRegisterView(view)
+ if err != nil {
+ errstr = append(errstr, fmt.Sprintf("%s: %v", view.Name, err))
+ continue
+ }
+ internal.SubscriptionReporter(view.Measure.Name())
+ vi.subscribe()
+ }
+ if len(errstr) > 0 {
+ cmd.err <- errors.New(strings.Join(errstr, "\n"))
+ } else {
+ cmd.err <- nil
+ }
+}
+
+// unregisterFromViewReq is the command to unsubscribe to a view. Has no
+// impact on the data collection for client that are pulling data from the
+// library.
+type unregisterFromViewReq struct {
+ views []string
+ done chan struct{}
+}
+
+func (cmd *unregisterFromViewReq) handleCommand(w *worker) {
+ for _, name := range cmd.views {
+ vi, ok := w.views[name]
+ if !ok {
+ continue
+ }
+
+ vi.unsubscribe()
+ if !vi.isSubscribed() {
+ // this was the last subscription and view is not collecting anymore.
+ // The collected data can be cleared.
+ vi.clearRows()
+ }
+ delete(w.views, name)
+ }
+ cmd.done <- struct{}{}
+}
+
+// retrieveDataReq is the command to retrieve data for a view.
+type retrieveDataReq struct {
+ now time.Time
+ v string
+ c chan *retrieveDataResp
+}
+
+type retrieveDataResp struct {
+ rows []*Row
+ err error
+}
+
+func (cmd *retrieveDataReq) handleCommand(w *worker) {
+ vi, ok := w.views[cmd.v]
+ if !ok {
+ cmd.c <- &retrieveDataResp{
+ nil,
+ fmt.Errorf("cannot retrieve data; view %q is not registered", cmd.v),
+ }
+ return
+ }
+
+ if !vi.isSubscribed() {
+ cmd.c <- &retrieveDataResp{
+ nil,
+ fmt.Errorf("cannot retrieve data; view %q has no subscriptions or collection is not forcibly started", cmd.v),
+ }
+ return
+ }
+ cmd.c <- &retrieveDataResp{
+ vi.collectedRows(),
+ nil,
+ }
+}
+
+// recordReq is the command to record data related to multiple measures
+// at once.
+type recordReq struct {
+ tm *tag.Map
+ ms []stats.Measurement
+}
+
+func (cmd *recordReq) handleCommand(w *worker) {
+ for _, m := range cmd.ms {
+ if (m == stats.Measurement{}) { // not subscribed
+ continue
+ }
+ ref := w.getMeasureRef(m.Measure().Name())
+ for v := range ref.views {
+ v.addSample(cmd.tm, m.Value())
+ }
+ }
+}
+
+// setReportingPeriodReq is the command to modify the duration between
+// reporting the collected data to the subscribed clients.
+type setReportingPeriodReq struct {
+ d time.Duration
+ c chan bool
+}
+
+func (cmd *setReportingPeriodReq) handleCommand(w *worker) {
+ w.timer.Stop()
+ if cmd.d <= 0 {
+ w.timer = time.NewTicker(defaultReportingDuration)
+ } else {
+ w.timer = time.NewTicker(cmd.d)
+ }
+ cmd.c <- true
+}