vendor: github.com/prometheus/client_golang v1.12.1
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
985711c1f4
commit
ec47096efc
574 changed files with 101741 additions and 22828 deletions
69
vendor/go.opencensus.io/stats/doc.go
generated
vendored
Normal file
69
vendor/go.opencensus.io/stats/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
// 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 data point to be tracked and recorded.
|
||||
For example, latency, request Mb/s, and response Mb/s are measures
|
||||
to collect from a server.
|
||||
|
||||
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. Application authors can then
|
||||
create views and collect and break down measures by the tags they are
|
||||
interested in.
|
||||
|
||||
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. Measurements are created from 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 no views are registered for them.
|
||||
There is usually no need to conditionally enable and disable
|
||||
recording to reduce cost. Recording of measurements is cheap.
|
||||
|
||||
Libraries can always record measurements, and applications can later decide
|
||||
on which measurements they want to collect by registering views. This allows
|
||||
libraries to turn on the instrumentation by default.
|
||||
|
||||
Exemplars
|
||||
|
||||
For a given recorded measurement, the associated exemplar is a diagnostic map
|
||||
that gives more information about the measurement.
|
||||
|
||||
When aggregated using a Distribution aggregation, an exemplar is kept for each
|
||||
bucket in the Distribution. This allows you to easily find an example of a
|
||||
measurement that fell into each bucket.
|
||||
|
||||
For example, if you also use the OpenCensus trace package and you
|
||||
record a measurement with a context that contains a sampled trace span,
|
||||
then the trace span will be added to the exemplar associated with the measurement.
|
||||
|
||||
When exported to a supporting back end, you should be able to easily navigate
|
||||
to example traces that fell into each bucket in the Distribution.
|
||||
|
||||
*/
|
||||
package stats // import "go.opencensus.io/stats"
|
25
vendor/go.opencensus.io/stats/internal/record.go
generated
vendored
Normal file
25
vendor/go.opencensus.io/stats/internal/record.go
generated
vendored
Normal file
|
@ -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(tags *tag.Map, measurement interface{}, attachments map[string]interface{})
|
||||
|
||||
// SubscriptionReporter reports when a view subscribed with a measure.
|
||||
var SubscriptionReporter func(measure string)
|
109
vendor/go.opencensus.io/stats/measure.go
generated
vendored
Normal file
109
vendor/go.opencensus.io/stats/measure.go
generated
vendored
Normal file
|
@ -0,0 +1,109 @@
|
|||
// 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 single numeric value to be tracked and recorded.
|
||||
// For example, latency, request bytes, and response bytes could be measures
|
||||
// to collect from a server.
|
||||
//
|
||||
// Measures by themselves have no outside effects. In order to be exported,
|
||||
// the measure needs to be used in a View. If no Views are defined over a
|
||||
// measure, there is very little cost in recording it.
|
||||
type Measure interface {
|
||||
// Name returns the name of this measure.
|
||||
//
|
||||
// Measure names are globally unique (among all libraries linked into your program).
|
||||
// We recommend prefixing the measure name with a domain name relevant to your
|
||||
// project or application.
|
||||
//
|
||||
// Measure names are never sent over the wire or exported to backends.
|
||||
// They are only used to create Views.
|
||||
Name() string
|
||||
|
||||
// Description returns the human-readable description of this measure.
|
||||
Description() string
|
||||
|
||||
// Unit returns the units for the values this measure takes on.
|
||||
//
|
||||
// Units are encoded according to the case-sensitive abbreviations from the
|
||||
// Unified Code for Units of Measure: http://unitsofmeasure.org/ucum.html
|
||||
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
|
||||
desc *measureDescriptor
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
55
vendor/go.opencensus.io/stats/measure_float64.go
generated
vendored
Normal file
55
vendor/go.opencensus.io/stats/measure_float64.go
generated
vendored
Normal file
|
@ -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
|
||||
|
||||
// Float64Measure is a measure for float64 values.
|
||||
type Float64Measure struct {
|
||||
desc *measureDescriptor
|
||||
}
|
||||
|
||||
// M creates a new float64 measurement.
|
||||
// Use Record to record measurements.
|
||||
func (m *Float64Measure) M(v float64) Measurement {
|
||||
return Measurement{
|
||||
m: m,
|
||||
desc: m.desc,
|
||||
v: v,
|
||||
}
|
||||
}
|
||||
|
||||
// Float64 creates a new measure for float64 values.
|
||||
//
|
||||
// See the documentation for interface Measure for more guidance on the
|
||||
// parameters of this function.
|
||||
func Float64(name, description, unit string) *Float64Measure {
|
||||
mi := registerMeasureHandle(name, description, unit)
|
||||
return &Float64Measure{mi}
|
||||
}
|
||||
|
||||
// Name returns the name of the measure.
|
||||
func (m *Float64Measure) Name() string {
|
||||
return m.desc.name
|
||||
}
|
||||
|
||||
// Description returns the description of the measure.
|
||||
func (m *Float64Measure) Description() string {
|
||||
return m.desc.description
|
||||
}
|
||||
|
||||
// Unit returns the unit of the measure.
|
||||
func (m *Float64Measure) Unit() string {
|
||||
return m.desc.unit
|
||||
}
|
55
vendor/go.opencensus.io/stats/measure_int64.go
generated
vendored
Normal file
55
vendor/go.opencensus.io/stats/measure_int64.go
generated
vendored
Normal file
|
@ -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
|
||||
|
||||
// Int64Measure is a measure for int64 values.
|
||||
type Int64Measure struct {
|
||||
desc *measureDescriptor
|
||||
}
|
||||
|
||||
// M creates a new int64 measurement.
|
||||
// Use Record to record measurements.
|
||||
func (m *Int64Measure) M(v int64) Measurement {
|
||||
return Measurement{
|
||||
m: m,
|
||||
desc: m.desc,
|
||||
v: float64(v),
|
||||
}
|
||||
}
|
||||
|
||||
// Int64 creates a new measure for int64 values.
|
||||
//
|
||||
// See the documentation for interface Measure for more guidance on the
|
||||
// parameters of this function.
|
||||
func Int64(name, description, unit string) *Int64Measure {
|
||||
mi := registerMeasureHandle(name, description, unit)
|
||||
return &Int64Measure{mi}
|
||||
}
|
||||
|
||||
// Name returns the name of the measure.
|
||||
func (m *Int64Measure) Name() string {
|
||||
return m.desc.name
|
||||
}
|
||||
|
||||
// Description returns the description of the measure.
|
||||
func (m *Int64Measure) Description() string {
|
||||
return m.desc.description
|
||||
}
|
||||
|
||||
// Unit returns the unit of the measure.
|
||||
func (m *Int64Measure) Unit() string {
|
||||
return m.desc.unit
|
||||
}
|
137
vendor/go.opencensus.io/stats/record.go
generated
vendored
Normal file
137
vendor/go.opencensus.io/stats/record.go
generated
vendored
Normal file
|
@ -0,0 +1,137 @@
|
|||
// 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/metric/metricdata"
|
||||
"go.opencensus.io/stats/internal"
|
||||
"go.opencensus.io/tag"
|
||||
)
|
||||
|
||||
func init() {
|
||||
internal.SubscriptionReporter = func(measure string) {
|
||||
mu.Lock()
|
||||
measures[measure].subscribe()
|
||||
mu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// Recorder provides an interface for exporting measurement information from
|
||||
// the static Record method by using the WithRecorder option.
|
||||
type Recorder interface {
|
||||
// Record records a set of measurements associated with the given tags and attachments.
|
||||
// The second argument is a `[]Measurement`.
|
||||
Record(*tag.Map, interface{}, map[string]interface{})
|
||||
}
|
||||
|
||||
type recordOptions struct {
|
||||
attachments metricdata.Attachments
|
||||
mutators []tag.Mutator
|
||||
measurements []Measurement
|
||||
recorder Recorder
|
||||
}
|
||||
|
||||
// WithAttachments applies provided exemplar attachments.
|
||||
func WithAttachments(attachments metricdata.Attachments) Options {
|
||||
return func(ro *recordOptions) {
|
||||
ro.attachments = attachments
|
||||
}
|
||||
}
|
||||
|
||||
// WithTags applies provided tag mutators.
|
||||
func WithTags(mutators ...tag.Mutator) Options {
|
||||
return func(ro *recordOptions) {
|
||||
ro.mutators = mutators
|
||||
}
|
||||
}
|
||||
|
||||
// WithMeasurements applies provided measurements.
|
||||
func WithMeasurements(measurements ...Measurement) Options {
|
||||
return func(ro *recordOptions) {
|
||||
ro.measurements = measurements
|
||||
}
|
||||
}
|
||||
|
||||
// WithRecorder records the measurements to the specified `Recorder`, rather
|
||||
// than to the global metrics recorder.
|
||||
func WithRecorder(meter Recorder) Options {
|
||||
return func(ro *recordOptions) {
|
||||
ro.recorder = meter
|
||||
}
|
||||
}
|
||||
|
||||
// Options apply changes to recordOptions.
|
||||
type Options func(*recordOptions)
|
||||
|
||||
func createRecordOption(ros ...Options) *recordOptions {
|
||||
o := &recordOptions{}
|
||||
for _, ro := range ros {
|
||||
ro(o)
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
// Record records one or multiple measurements with the same context at once.
|
||||
// If there are any tags in the context, measurements will be tagged with them.
|
||||
func Record(ctx context.Context, ms ...Measurement) {
|
||||
RecordWithOptions(ctx, WithMeasurements(ms...))
|
||||
}
|
||||
|
||||
// RecordWithTags records one or multiple measurements at once.
|
||||
//
|
||||
// Measurements will be tagged with the tags in the context mutated by the mutators.
|
||||
// RecordWithTags is useful if you want to record with tag mutations but don't want
|
||||
// to propagate the mutations in the context.
|
||||
func RecordWithTags(ctx context.Context, mutators []tag.Mutator, ms ...Measurement) error {
|
||||
return RecordWithOptions(ctx, WithTags(mutators...), WithMeasurements(ms...))
|
||||
}
|
||||
|
||||
// RecordWithOptions records measurements from the given options (if any) against context
|
||||
// and tags and attachments in the options (if any).
|
||||
// If there are any tags in the context, measurements will be tagged with them.
|
||||
func RecordWithOptions(ctx context.Context, ros ...Options) error {
|
||||
o := createRecordOption(ros...)
|
||||
if len(o.measurements) == 0 {
|
||||
return nil
|
||||
}
|
||||
recorder := internal.DefaultRecorder
|
||||
if o.recorder != nil {
|
||||
recorder = o.recorder.Record
|
||||
}
|
||||
if recorder == nil {
|
||||
return nil
|
||||
}
|
||||
record := false
|
||||
for _, m := range o.measurements {
|
||||
if m.desc.subscribed() {
|
||||
record = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !record {
|
||||
return nil
|
||||
}
|
||||
if len(o.mutators) > 0 {
|
||||
var err error
|
||||
if ctx, err = tag.New(ctx, o.mutators...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
recorder(tag.FromContext(ctx), o.measurements, o.attachments)
|
||||
return nil
|
||||
}
|
26
vendor/go.opencensus.io/stats/units.go
generated
vendored
Normal file
26
vendor/go.opencensus.io/stats/units.go
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
// 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"
|
||||
UnitSeconds = "s"
|
||||
)
|
121
vendor/go.opencensus.io/stats/view/aggregation.go
generated
vendored
Normal file
121
vendor/go.opencensus.io/stats/view/aggregation.go
generated
vendored
Normal file
|
@ -0,0 +1,121 @@
|
|||
// 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.
|
||||
//
|
||||
// A 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 {
|
||||
agg := &Aggregation{
|
||||
Type: AggTypeDistribution,
|
||||
Buckets: bounds,
|
||||
}
|
||||
agg.newData = func() AggregationData {
|
||||
return newDistributionData(agg)
|
||||
}
|
||||
return agg
|
||||
}
|
||||
|
||||
// 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{}
|
||||
},
|
||||
}
|
||||
}
|
293
vendor/go.opencensus.io/stats/view/aggregation_data.go
generated
vendored
Normal file
293
vendor/go.opencensus.io/stats/view/aggregation_data.go
generated
vendored
Normal file
|
@ -0,0 +1,293 @@
|
|||
// 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"
|
||||
"time"
|
||||
|
||||
"go.opencensus.io/metric/metricdata"
|
||||
)
|
||||
|
||||
// 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, attachments map[string]interface{}, t time.Time)
|
||||
clone() AggregationData
|
||||
equal(other AggregationData) bool
|
||||
toPoint(t metricdata.Type, time time.Time) metricdata.Point
|
||||
}
|
||||
|
||||
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(_ float64, _ map[string]interface{}, _ time.Time) {
|
||||
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
|
||||
}
|
||||
|
||||
func (a *CountData) toPoint(metricType metricdata.Type, t time.Time) metricdata.Point {
|
||||
switch metricType {
|
||||
case metricdata.TypeCumulativeInt64:
|
||||
return metricdata.NewInt64Point(t, a.Value)
|
||||
default:
|
||||
panic("unsupported metricdata.Type")
|
||||
}
|
||||
}
|
||||
|
||||
// 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(v float64, _ map[string]interface{}, _ time.Time) {
|
||||
a.Value += v
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func (a *SumData) toPoint(metricType metricdata.Type, t time.Time) metricdata.Point {
|
||||
switch metricType {
|
||||
case metricdata.TypeCumulativeInt64:
|
||||
return metricdata.NewInt64Point(t, int64(a.Value))
|
||||
case metricdata.TypeCumulativeFloat64:
|
||||
return metricdata.NewFloat64Point(t, a.Value)
|
||||
default:
|
||||
panic("unsupported metricdata.Type")
|
||||
}
|
||||
}
|
||||
|
||||
// DistributionData is the aggregated data for the
|
||||
// Distribution aggregation.
|
||||
//
|
||||
// Most users won't directly access distribution data.
|
||||
//
|
||||
// For a distribution with N bounds, the associated DistributionData will have
|
||||
// N+1 buckets.
|
||||
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
|
||||
// ExemplarsPerBucket is slice the same length as CountPerBucket containing
|
||||
// an exemplar for the associated bucket, or nil.
|
||||
ExemplarsPerBucket []*metricdata.Exemplar
|
||||
bounds []float64 // histogram distribution of the values
|
||||
}
|
||||
|
||||
func newDistributionData(agg *Aggregation) *DistributionData {
|
||||
bucketCount := len(agg.Buckets) + 1
|
||||
return &DistributionData{
|
||||
CountPerBucket: make([]int64, bucketCount),
|
||||
ExemplarsPerBucket: make([]*metricdata.Exemplar, bucketCount),
|
||||
bounds: agg.Buckets,
|
||||
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 }
|
||||
|
||||
// TODO(songy23): support exemplar attachments.
|
||||
func (a *DistributionData) addSample(v float64, attachments map[string]interface{}, t time.Time) {
|
||||
if v < a.Min {
|
||||
a.Min = v
|
||||
}
|
||||
if v > a.Max {
|
||||
a.Max = v
|
||||
}
|
||||
a.Count++
|
||||
a.addToBucket(v, attachments, t)
|
||||
|
||||
if a.Count == 1 {
|
||||
a.Mean = v
|
||||
return
|
||||
}
|
||||
|
||||
oldMean := a.Mean
|
||||
a.Mean = a.Mean + (v-a.Mean)/float64(a.Count)
|
||||
a.SumOfSquaredDev = a.SumOfSquaredDev + (v-oldMean)*(v-a.Mean)
|
||||
}
|
||||
|
||||
func (a *DistributionData) addToBucket(v float64, attachments map[string]interface{}, t time.Time) {
|
||||
var count *int64
|
||||
var i int
|
||||
var b float64
|
||||
for i, b = range a.bounds {
|
||||
if v < b {
|
||||
count = &a.CountPerBucket[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
if count == nil { // Last bucket.
|
||||
i = len(a.bounds)
|
||||
count = &a.CountPerBucket[i]
|
||||
}
|
||||
*count++
|
||||
if exemplar := getExemplar(v, attachments, t); exemplar != nil {
|
||||
a.ExemplarsPerBucket[i] = exemplar
|
||||
}
|
||||
}
|
||||
|
||||
func getExemplar(v float64, attachments map[string]interface{}, t time.Time) *metricdata.Exemplar {
|
||||
if len(attachments) == 0 {
|
||||
return nil
|
||||
}
|
||||
return &metricdata.Exemplar{
|
||||
Value: v,
|
||||
Timestamp: t,
|
||||
Attachments: attachments,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *DistributionData) clone() AggregationData {
|
||||
c := *a
|
||||
c.CountPerBucket = append([]int64(nil), a.CountPerBucket...)
|
||||
c.ExemplarsPerBucket = append([]*metricdata.Exemplar(nil), a.ExemplarsPerBucket...)
|
||||
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
|
||||
}
|
||||
|
||||
func (a *DistributionData) toPoint(metricType metricdata.Type, t time.Time) metricdata.Point {
|
||||
switch metricType {
|
||||
case metricdata.TypeCumulativeDistribution:
|
||||
buckets := []metricdata.Bucket{}
|
||||
for i := 0; i < len(a.CountPerBucket); i++ {
|
||||
buckets = append(buckets, metricdata.Bucket{
|
||||
Count: a.CountPerBucket[i],
|
||||
Exemplar: a.ExemplarsPerBucket[i],
|
||||
})
|
||||
}
|
||||
bucketOptions := &metricdata.BucketOptions{Bounds: a.bounds}
|
||||
|
||||
val := &metricdata.Distribution{
|
||||
Count: a.Count,
|
||||
Sum: a.Sum(),
|
||||
SumOfSquaredDeviation: a.SumOfSquaredDev,
|
||||
BucketOptions: bucketOptions,
|
||||
Buckets: buckets,
|
||||
}
|
||||
return metricdata.NewDistributionPoint(t, val)
|
||||
|
||||
default:
|
||||
// TODO: [rghetia] when we have a use case for TypeGaugeDistribution.
|
||||
panic("unsupported metricdata.Type")
|
||||
}
|
||||
}
|
||||
|
||||
// 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, _ map[string]interface{}, _ time.Time) {
|
||||
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
|
||||
}
|
||||
|
||||
func (l *LastValueData) toPoint(metricType metricdata.Type, t time.Time) metricdata.Point {
|
||||
switch metricType {
|
||||
case metricdata.TypeGaugeInt64:
|
||||
return metricdata.NewInt64Point(t, int64(l.Value))
|
||||
case metricdata.TypeGaugeFloat64:
|
||||
return metricdata.NewFloat64Point(t, l.Value)
|
||||
default:
|
||||
panic("unsupported metricdata.Type")
|
||||
}
|
||||
}
|
86
vendor/go.opencensus.io/stats/view/collector.go
generated
vendored
Normal file
86
vendor/go.opencensus.io/stats/view/collector.go
generated
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
// 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"
|
||||
"time"
|
||||
|
||||
"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, attachments map[string]interface{}, t time.Time) {
|
||||
aggregator, ok := c.signatures[s]
|
||||
if !ok {
|
||||
aggregator = c.a.newData()
|
||||
c.signatures[s] = aggregator
|
||||
}
|
||||
aggregator.addSample(v, attachments, t)
|
||||
}
|
||||
|
||||
// collectRows returns a snapshot of the collected Row values.
|
||||
func (c *collector) collectedRows(keys []tag.Key) []*Row {
|
||||
rows := make([]*Row, 0, len(c.signatures))
|
||||
for sig, aggregator := range c.signatures {
|
||||
tags := decodeTags([]byte(sig), keys)
|
||||
row := &Row{Tags: tags, Data: aggregator.clone()}
|
||||
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
|
||||
}
|
47
vendor/go.opencensus.io/stats/view/doc.go
generated
vendored
Normal file
47
vendor/go.opencensus.io/stats/view/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
// 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.
|
||||
//
|
||||
// All recorded measurements can be grouped by a list of tags.
|
||||
//
|
||||
// OpenCensus provides several aggregation methods: Count, Distribution and Sum.
|
||||
//
|
||||
// Count only counts the number of measurement points recorded.
|
||||
// Distribution provides statistical summary of the aggregated data by counting
|
||||
// how many recorded measurements fall into each bucket.
|
||||
// Sum adds up the measurement values.
|
||||
// LastValue just keeps track of the most recently recorded measurement value.
|
||||
// All aggregations are cumulative.
|
||||
//
|
||||
// Views can be registered and unregistered at any time during program execution.
|
||||
//
|
||||
// Libraries can define views but it is recommended that in most cases registering
|
||||
// views be left up to applications.
|
||||
//
|
||||
// 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 back ends.
|
||||
package view // import "go.opencensus.io/stats/view"
|
||||
|
||||
// TODO(acetechnologist): Add a link to the language independent OpenCensus
|
||||
// spec when it is available.
|
45
vendor/go.opencensus.io/stats/view/export.go
generated
vendored
Normal file
45
vendor/go.opencensus.io/stats/view/export.go
generated
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
// 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
|
||||
|
||||
// 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.
|
||||
//
|
||||
// It is safe to assume that ExportView will not be called concurrently from
|
||||
// multiple goroutines.
|
||||
//
|
||||
// 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) {
|
||||
defaultWorker.RegisterExporter(e)
|
||||
}
|
||||
|
||||
// UnregisterExporter unregisters an exporter.
|
||||
func UnregisterExporter(e Exporter) {
|
||||
defaultWorker.UnregisterExporter(e)
|
||||
}
|
221
vendor/go.opencensus.io/stats/view/view.go
generated
vendored
Normal file
221
vendor/go.opencensus.io/stats/view/view.go
generated
vendored
Normal file
|
@ -0,0 +1,221 @@
|
|||
// 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"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"go.opencensus.io/metric/metricdata"
|
||||
"go.opencensus.io/stats"
|
||||
"go.opencensus.io/tag"
|
||||
)
|
||||
|
||||
// View allows users to aggregate the recorded stats.Measurements.
|
||||
// Views need to be passed to the Register function 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 to 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()
|
||||
}
|
||||
|
||||
// ErrNegativeBucketBounds error returned if histogram contains negative bounds.
|
||||
//
|
||||
// Deprecated: this should not be public.
|
||||
var ErrNegativeBucketBounds = errors.New("negative bucket bounds not supported")
|
||||
|
||||
// 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 register view %q: measure not set", v.Name)
|
||||
}
|
||||
if v.Aggregation == nil {
|
||||
return fmt.Errorf("cannot register 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()
|
||||
})
|
||||
sort.Float64s(v.Aggregation.Buckets)
|
||||
for _, b := range v.Aggregation.Buckets {
|
||||
if b < 0 {
|
||||
return ErrNegativeBucketBounds
|
||||
}
|
||||
}
|
||||
// drop 0 bucket silently.
|
||||
v.Aggregation.Buckets = dropZeroBounds(v.Aggregation.Buckets...)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func dropZeroBounds(bounds ...float64) []float64 {
|
||||
for i, bound := range bounds {
|
||||
if bound > 0 {
|
||||
return bounds[i:]
|
||||
}
|
||||
}
|
||||
return []float64{}
|
||||
}
|
||||
|
||||
// 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
|
||||
metricDescriptor *metricdata.Descriptor
|
||||
}
|
||||
|
||||
func newViewInternal(v *View) (*viewInternal, error) {
|
||||
return &viewInternal{
|
||||
view: v,
|
||||
collector: &collector{make(map[string]AggregationData), v.Aggregation},
|
||||
metricDescriptor: viewToMetricDescriptor(v),
|
||||
}, 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, attachments map[string]interface{}, t time.Time) {
|
||||
if !v.isSubscribed() {
|
||||
return
|
||||
}
|
||||
sig := string(encodeWithKeys(m, v.view.TagKeys))
|
||||
v.collector.addSample(sig, val, attachments, t)
|
||||
}
|
||||
|
||||
// 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 if 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)
|
||||
}
|
||||
|
||||
const maxNameLength = 255
|
||||
|
||||
// Returns true if the given string contains only printable characters.
|
||||
func isPrintable(str string) bool {
|
||||
for _, r := range str {
|
||||
if !(r >= ' ' && r <= '~') {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func checkViewName(name string) error {
|
||||
if len(name) > maxNameLength {
|
||||
return fmt.Errorf("view name cannot be larger than %v", maxNameLength)
|
||||
}
|
||||
if !isPrintable(name) {
|
||||
return fmt.Errorf("view name needs to be an ASCII string")
|
||||
}
|
||||
return nil
|
||||
}
|
152
vendor/go.opencensus.io/stats/view/view_to_metric.go
generated
vendored
Normal file
152
vendor/go.opencensus.io/stats/view/view_to_metric.go
generated
vendored
Normal file
|
@ -0,0 +1,152 @@
|
|||
// Copyright 2019, 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 (
|
||||
"time"
|
||||
|
||||
"go.opencensus.io/resource"
|
||||
|
||||
"go.opencensus.io/metric/metricdata"
|
||||
"go.opencensus.io/stats"
|
||||
)
|
||||
|
||||
func getUnit(unit string) metricdata.Unit {
|
||||
switch unit {
|
||||
case "1":
|
||||
return metricdata.UnitDimensionless
|
||||
case "ms":
|
||||
return metricdata.UnitMilliseconds
|
||||
case "By":
|
||||
return metricdata.UnitBytes
|
||||
}
|
||||
return metricdata.UnitDimensionless
|
||||
}
|
||||
|
||||
func getType(v *View) metricdata.Type {
|
||||
m := v.Measure
|
||||
agg := v.Aggregation
|
||||
|
||||
switch agg.Type {
|
||||
case AggTypeSum:
|
||||
switch m.(type) {
|
||||
case *stats.Int64Measure:
|
||||
return metricdata.TypeCumulativeInt64
|
||||
case *stats.Float64Measure:
|
||||
return metricdata.TypeCumulativeFloat64
|
||||
default:
|
||||
panic("unexpected measure type")
|
||||
}
|
||||
case AggTypeDistribution:
|
||||
return metricdata.TypeCumulativeDistribution
|
||||
case AggTypeLastValue:
|
||||
switch m.(type) {
|
||||
case *stats.Int64Measure:
|
||||
return metricdata.TypeGaugeInt64
|
||||
case *stats.Float64Measure:
|
||||
return metricdata.TypeGaugeFloat64
|
||||
default:
|
||||
panic("unexpected measure type")
|
||||
}
|
||||
case AggTypeCount:
|
||||
switch m.(type) {
|
||||
case *stats.Int64Measure:
|
||||
return metricdata.TypeCumulativeInt64
|
||||
case *stats.Float64Measure:
|
||||
return metricdata.TypeCumulativeInt64
|
||||
default:
|
||||
panic("unexpected measure type")
|
||||
}
|
||||
default:
|
||||
panic("unexpected aggregation type")
|
||||
}
|
||||
}
|
||||
|
||||
func getLabelKeys(v *View) []metricdata.LabelKey {
|
||||
labelKeys := []metricdata.LabelKey{}
|
||||
for _, k := range v.TagKeys {
|
||||
labelKeys = append(labelKeys, metricdata.LabelKey{Key: k.Name()})
|
||||
}
|
||||
return labelKeys
|
||||
}
|
||||
|
||||
func viewToMetricDescriptor(v *View) *metricdata.Descriptor {
|
||||
return &metricdata.Descriptor{
|
||||
Name: v.Name,
|
||||
Description: v.Description,
|
||||
Unit: convertUnit(v),
|
||||
Type: getType(v),
|
||||
LabelKeys: getLabelKeys(v),
|
||||
}
|
||||
}
|
||||
|
||||
func convertUnit(v *View) metricdata.Unit {
|
||||
switch v.Aggregation.Type {
|
||||
case AggTypeCount:
|
||||
return metricdata.UnitDimensionless
|
||||
default:
|
||||
return getUnit(v.Measure.Unit())
|
||||
}
|
||||
}
|
||||
|
||||
func toLabelValues(row *Row, expectedKeys []metricdata.LabelKey) []metricdata.LabelValue {
|
||||
labelValues := []metricdata.LabelValue{}
|
||||
tagMap := make(map[string]string)
|
||||
for _, tag := range row.Tags {
|
||||
tagMap[tag.Key.Name()] = tag.Value
|
||||
}
|
||||
|
||||
for _, key := range expectedKeys {
|
||||
if val, ok := tagMap[key.Key]; ok {
|
||||
labelValues = append(labelValues, metricdata.NewLabelValue(val))
|
||||
} else {
|
||||
labelValues = append(labelValues, metricdata.LabelValue{})
|
||||
}
|
||||
}
|
||||
return labelValues
|
||||
}
|
||||
|
||||
func rowToTimeseries(v *viewInternal, row *Row, now time.Time, startTime time.Time) *metricdata.TimeSeries {
|
||||
return &metricdata.TimeSeries{
|
||||
Points: []metricdata.Point{row.Data.toPoint(v.metricDescriptor.Type, now)},
|
||||
LabelValues: toLabelValues(row, v.metricDescriptor.LabelKeys),
|
||||
StartTime: startTime,
|
||||
}
|
||||
}
|
||||
|
||||
func viewToMetric(v *viewInternal, r *resource.Resource, now time.Time, startTime time.Time) *metricdata.Metric {
|
||||
if v.metricDescriptor.Type == metricdata.TypeGaugeInt64 ||
|
||||
v.metricDescriptor.Type == metricdata.TypeGaugeFloat64 {
|
||||
startTime = time.Time{}
|
||||
}
|
||||
|
||||
rows := v.collectedRows()
|
||||
if len(rows) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
ts := []*metricdata.TimeSeries{}
|
||||
for _, row := range rows {
|
||||
ts = append(ts, rowToTimeseries(v, row, now, startTime))
|
||||
}
|
||||
|
||||
m := &metricdata.Metric{
|
||||
Descriptor: *v.metricDescriptor,
|
||||
TimeSeries: ts,
|
||||
Resource: r,
|
||||
}
|
||||
return m
|
||||
}
|
413
vendor/go.opencensus.io/stats/view/worker.go
generated
vendored
Normal file
413
vendor/go.opencensus.io/stats/view/worker.go
generated
vendored
Normal file
|
@ -0,0 +1,413 @@
|
|||
// 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"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"go.opencensus.io/resource"
|
||||
|
||||
"go.opencensus.io/metric/metricdata"
|
||||
"go.opencensus.io/metric/metricproducer"
|
||||
"go.opencensus.io/stats"
|
||||
"go.opencensus.io/stats/internal"
|
||||
"go.opencensus.io/tag"
|
||||
)
|
||||
|
||||
func init() {
|
||||
defaultWorker = NewMeter().(*worker)
|
||||
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
|
||||
mu sync.RWMutex
|
||||
r *resource.Resource
|
||||
|
||||
exportersMu sync.RWMutex
|
||||
exporters map[Exporter]struct{}
|
||||
}
|
||||
|
||||
// Meter defines an interface which allows a single process to maintain
|
||||
// multiple sets of metrics exports (intended for the advanced case where a
|
||||
// single process wants to report metrics about multiple objects, such as
|
||||
// multiple databases or HTTP services).
|
||||
//
|
||||
// Note that this is an advanced use case, and the static functions in this
|
||||
// module should cover the common use cases.
|
||||
type Meter interface {
|
||||
stats.Recorder
|
||||
// Find returns a registered view associated with this name.
|
||||
// If no registered view is found, nil is returned.
|
||||
Find(name string) *View
|
||||
// Register begins collecting data for the given views.
|
||||
// Once a view is registered, it reports data to the registered exporters.
|
||||
Register(views ...*View) error
|
||||
// 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.
|
||||
Unregister(views ...*View)
|
||||
// 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.
|
||||
//
|
||||
// Note: each exporter makes different promises about what the lowest supported
|
||||
// duration is. For example, the Stackdriver exporter recommends a value no
|
||||
// lower than 1 minute. Consult each exporter per your needs.
|
||||
SetReportingPeriod(time.Duration)
|
||||
|
||||
// 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.
|
||||
RegisterExporter(Exporter)
|
||||
// UnregisterExporter unregisters an exporter.
|
||||
UnregisterExporter(Exporter)
|
||||
// SetResource may be used to set the Resource associated with this registry.
|
||||
// This is intended to be used in cases where a single process exports metrics
|
||||
// for multiple Resources, typically in a multi-tenant situation.
|
||||
SetResource(*resource.Resource)
|
||||
|
||||
// Start causes the Meter to start processing Record calls and aggregating
|
||||
// statistics as well as exporting data.
|
||||
Start()
|
||||
// Stop causes the Meter to stop processing calls and terminate data export.
|
||||
Stop()
|
||||
|
||||
// RetrieveData gets a snapshot of the data collected for the the view registered
|
||||
// with the given name. It is intended for testing only.
|
||||
RetrieveData(viewName string) ([]*Row, error)
|
||||
}
|
||||
|
||||
var _ Meter = (*worker)(nil)
|
||||
|
||||
var defaultWorker *worker
|
||||
|
||||
var defaultReportingDuration = 10 * time.Second
|
||||
|
||||
// Find returns a registered view associated with this name.
|
||||
// If no registered view is found, nil is returned.
|
||||
func Find(name string) (v *View) {
|
||||
return defaultWorker.Find(name)
|
||||
}
|
||||
|
||||
// Find returns a registered view associated with this name.
|
||||
// If no registered view is found, nil is returned.
|
||||
func (w *worker) Find(name string) (v *View) {
|
||||
req := &getViewByNameReq{
|
||||
name: name,
|
||||
c: make(chan *getViewByNameResp),
|
||||
}
|
||||
w.c <- req
|
||||
resp := <-req.c
|
||||
return resp.v
|
||||
}
|
||||
|
||||
// Register begins collecting data for the given views.
|
||||
// Once a view is registered, it reports data to the registered exporters.
|
||||
func Register(views ...*View) error {
|
||||
return defaultWorker.Register(views...)
|
||||
}
|
||||
|
||||
// Register begins collecting data for the given views.
|
||||
// Once a view is registered, it reports data to the registered exporters.
|
||||
func (w *worker) Register(views ...*View) error {
|
||||
req := ®isterViewReq{
|
||||
views: views,
|
||||
err: make(chan error),
|
||||
}
|
||||
w.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) {
|
||||
defaultWorker.Unregister(views...)
|
||||
}
|
||||
|
||||
// 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 (w *worker) 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{}),
|
||||
}
|
||||
w.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) {
|
||||
return defaultWorker.RetrieveData(viewName)
|
||||
}
|
||||
|
||||
// RetrieveData gets a snapshot of the data collected for the the view registered
|
||||
// with the given name. It is intended for testing only.
|
||||
func (w *worker) RetrieveData(viewName string) ([]*Row, error) {
|
||||
req := &retrieveDataReq{
|
||||
now: time.Now(),
|
||||
v: viewName,
|
||||
c: make(chan *retrieveDataResp),
|
||||
}
|
||||
w.c <- req
|
||||
resp := <-req.c
|
||||
return resp.rows, resp.err
|
||||
}
|
||||
|
||||
func record(tags *tag.Map, ms interface{}, attachments map[string]interface{}) {
|
||||
defaultWorker.Record(tags, ms, attachments)
|
||||
}
|
||||
|
||||
// Record records a set of measurements ms associated with the given tags and attachments.
|
||||
func (w *worker) Record(tags *tag.Map, ms interface{}, attachments map[string]interface{}) {
|
||||
req := &recordReq{
|
||||
tm: tags,
|
||||
ms: ms.([]stats.Measurement),
|
||||
attachments: attachments,
|
||||
t: time.Now(),
|
||||
}
|
||||
w.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.
|
||||
//
|
||||
// Note: each exporter makes different promises about what the lowest supported
|
||||
// duration is. For example, the Stackdriver exporter recommends a value no
|
||||
// lower than 1 minute. Consult each exporter per your needs.
|
||||
func SetReportingPeriod(d time.Duration) {
|
||||
defaultWorker.SetReportingPeriod(d)
|
||||
}
|
||||
|
||||
// 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.
|
||||
//
|
||||
// Note: each exporter makes different promises about what the lowest supported
|
||||
// duration is. For example, the Stackdriver exporter recommends a value no
|
||||
// lower than 1 minute. Consult each exporter per your needs.
|
||||
func (w *worker) 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),
|
||||
}
|
||||
w.c <- req
|
||||
<-req.c // don't return until the timer is set to the new duration.
|
||||
}
|
||||
|
||||
// NewMeter constructs a Meter instance. You should only need to use this if
|
||||
// you need to separate out Measurement recordings and View aggregations within
|
||||
// a single process.
|
||||
func NewMeter() Meter {
|
||||
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),
|
||||
|
||||
exporters: make(map[Exporter]struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// SetResource associates all data collected by this Meter with the specified
|
||||
// resource. This resource is reported when using metricexport.ReadAndExport;
|
||||
// it is not provided when used with ExportView/RegisterExporter, because that
|
||||
// interface does not provide a means for reporting the Resource.
|
||||
func (w *worker) SetResource(r *resource.Resource) {
|
||||
w.r = r
|
||||
}
|
||||
|
||||
func (w *worker) Start() {
|
||||
go w.start()
|
||||
}
|
||||
|
||||
func (w *worker) start() {
|
||||
prodMgr := metricproducer.GlobalManager()
|
||||
prodMgr.AddProducer(w)
|
||||
|
||||
for {
|
||||
select {
|
||||
case cmd := <-w.c:
|
||||
cmd.handleCommand(w)
|
||||
case <-w.timer.C:
|
||||
w.reportUsage()
|
||||
case <-w.quit:
|
||||
w.timer.Stop()
|
||||
close(w.c)
|
||||
w.done <- true
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *worker) Stop() {
|
||||
prodMgr := metricproducer.GlobalManager()
|
||||
prodMgr.DeleteProducer(w)
|
||||
|
||||
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) {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
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 register view %q; a different view with the same name is already registered", 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
|
||||
w.startTimes[vi] = time.Now()
|
||||
ref := w.getMeasureRef(vi.view.Measure.Name())
|
||||
ref.views[vi] = struct{}{}
|
||||
return vi, nil
|
||||
}
|
||||
|
||||
func (w *worker) unregisterView(v *viewInternal) {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
delete(w.views, v.view.Name)
|
||||
delete(w.startTimes, v)
|
||||
if measure := w.measures[v.view.Measure.Name()]; measure != nil {
|
||||
delete(measure.views, v)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *worker) reportView(v *viewInternal) {
|
||||
if !v.isSubscribed() {
|
||||
return
|
||||
}
|
||||
rows := v.collectedRows()
|
||||
viewData := &Data{
|
||||
View: v.view,
|
||||
Start: w.startTimes[v],
|
||||
End: time.Now(),
|
||||
Rows: rows,
|
||||
}
|
||||
w.exportersMu.Lock()
|
||||
defer w.exportersMu.Unlock()
|
||||
for e := range w.exporters {
|
||||
e.ExportView(viewData)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *worker) reportUsage() {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
for _, v := range w.views {
|
||||
w.reportView(v)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *worker) toMetric(v *viewInternal, now time.Time) *metricdata.Metric {
|
||||
if !v.isSubscribed() {
|
||||
return nil
|
||||
}
|
||||
|
||||
var startTime time.Time
|
||||
if v.metricDescriptor.Type == metricdata.TypeGaugeInt64 ||
|
||||
v.metricDescriptor.Type == metricdata.TypeGaugeFloat64 {
|
||||
startTime = time.Time{}
|
||||
} else {
|
||||
startTime = w.startTimes[v]
|
||||
}
|
||||
|
||||
return viewToMetric(v, w.r, now, startTime)
|
||||
}
|
||||
|
||||
// Read reads all view data and returns them as metrics.
|
||||
// It is typically invoked by metric reader to export stats in metric format.
|
||||
func (w *worker) Read() []*metricdata.Metric {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
now := time.Now()
|
||||
metrics := make([]*metricdata.Metric, 0, len(w.views))
|
||||
for _, v := range w.views {
|
||||
metric := w.toMetric(v, now)
|
||||
if metric != nil {
|
||||
metrics = append(metrics, metric)
|
||||
}
|
||||
}
|
||||
return metrics
|
||||
}
|
||||
|
||||
func (w *worker) RegisterExporter(e Exporter) {
|
||||
w.exportersMu.Lock()
|
||||
defer w.exportersMu.Unlock()
|
||||
|
||||
w.exporters[e] = struct{}{}
|
||||
}
|
||||
|
||||
func (w *worker) UnregisterExporter(e Exporter) {
|
||||
w.exportersMu.Lock()
|
||||
defer w.exportersMu.Unlock()
|
||||
|
||||
delete(w.exporters, e)
|
||||
}
|
186
vendor/go.opencensus.io/stats/view/worker_commands.go
generated
vendored
Normal file
186
vendor/go.opencensus.io/stats/view/worker_commands.go
generated
vendored
Normal file
|
@ -0,0 +1,186 @@
|
|||
// 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) {
|
||||
for _, v := range cmd.views {
|
||||
if err := v.canonicalize(); err != nil {
|
||||
cmd.err <- err
|
||||
return
|
||||
}
|
||||
}
|
||||
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 unregister 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
|
||||
}
|
||||
|
||||
// Report pending data for this view before removing it.
|
||||
w.reportView(vi)
|
||||
|
||||
vi.unsubscribe()
|
||||
if !vi.isSubscribed() {
|
||||
// this was the last subscription and view is not collecting anymore.
|
||||
// The collected data can be cleared.
|
||||
vi.clearRows()
|
||||
}
|
||||
w.unregisterView(vi)
|
||||
}
|
||||
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) {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
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
|
||||
attachments map[string]interface{}
|
||||
t time.Time
|
||||
}
|
||||
|
||||
func (cmd *recordReq) handleCommand(w *worker) {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
for _, m := range cmd.ms {
|
||||
if (m == stats.Measurement{}) { // not registered
|
||||
continue
|
||||
}
|
||||
ref := w.getMeasureRef(m.Measure().Name())
|
||||
for v := range ref.views {
|
||||
v.addSample(cmd.tm, m.Value(), cmd.attachments, cmd.t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setReportingPeriodReq is the command to modify the duration between
|
||||
// reporting the collected data to the registered 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
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue