2019-10-29 22:27:22 +02:00
|
|
|
// Copyright 2019, OpenTelemetry 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.
|
|
|
|
|
2020-01-16 20:05:12 +02:00
|
|
|
package metric
|
2019-11-15 23:01:20 +02:00
|
|
|
|
2019-10-29 22:27:22 +02:00
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
2019-11-01 20:40:29 +02:00
|
|
|
"go.opentelemetry.io/otel/api/core"
|
2020-03-19 21:02:46 +02:00
|
|
|
"go.opentelemetry.io/otel/api/metric"
|
2019-10-29 22:27:22 +02:00
|
|
|
)
|
|
|
|
|
2019-11-15 23:01:20 +02:00
|
|
|
// Batcher is responsible for deciding which kind of aggregation to
|
|
|
|
// use (via AggregationSelector), gathering exported results from the
|
|
|
|
// SDK during collection, and deciding over which dimensions to group
|
|
|
|
// the exported data.
|
|
|
|
//
|
|
|
|
// The SDK supports binding only one of these interfaces, as it has
|
|
|
|
// the sole responsibility of determining which Aggregator to use for
|
|
|
|
// each record.
|
|
|
|
//
|
|
|
|
// The embedded AggregationSelector interface is called (concurrently)
|
|
|
|
// in instrumentation context to select the appropriate Aggregator for
|
|
|
|
// an instrument.
|
|
|
|
//
|
|
|
|
// The `Process` method is called during collection in a
|
|
|
|
// single-threaded context from the SDK, after the aggregator is
|
|
|
|
// checkpointed, allowing the batcher to build the set of metrics
|
|
|
|
// currently being exported.
|
2019-11-05 23:08:55 +02:00
|
|
|
//
|
2019-11-15 23:01:20 +02:00
|
|
|
// The `CheckpointSet` method is called during collection in a
|
|
|
|
// single-threaded context from the Exporter, giving the exporter
|
|
|
|
// access to a producer for iterating over the complete checkpoint.
|
2019-11-05 23:08:55 +02:00
|
|
|
type Batcher interface {
|
2019-11-15 23:01:20 +02:00
|
|
|
// AggregationSelector is responsible for selecting the
|
|
|
|
// concrete type of Aggregator used for a metric in the SDK.
|
|
|
|
//
|
|
|
|
// This may be a static decision based on fields of the
|
|
|
|
// Descriptor, or it could use an external configuration
|
|
|
|
// source to customize the treatment of each metric
|
|
|
|
// instrument.
|
|
|
|
//
|
|
|
|
// The result from AggregatorSelector.AggregatorFor should be
|
|
|
|
// the same type for a given Descriptor or else nil. The same
|
|
|
|
// type should be returned for a given descriptor, because
|
|
|
|
// Aggregators only know how to Merge with their own type. If
|
|
|
|
// the result is nil, the metric instrument will be disabled.
|
|
|
|
//
|
|
|
|
// Note that the SDK only calls AggregatorFor when new records
|
|
|
|
// require an Aggregator. This does not provide a way to
|
|
|
|
// disable metrics with active records.
|
|
|
|
AggregationSelector
|
|
|
|
|
|
|
|
// Process is called by the SDK once per internal record,
|
|
|
|
// passing the export Record (a Descriptor, the corresponding
|
|
|
|
// Labels, and the checkpointed Aggregator). The Batcher
|
|
|
|
// should be prepared to process duplicate (Descriptor,
|
|
|
|
// Labels) pairs during this pass due to race conditions, but
|
|
|
|
// this will usually be the ordinary course of events, as
|
|
|
|
// Aggregators are typically merged according the output set
|
|
|
|
// of labels.
|
2019-11-05 23:08:55 +02:00
|
|
|
//
|
2019-11-15 23:01:20 +02:00
|
|
|
// The Context argument originates from the controller that
|
|
|
|
// orchestrates collection.
|
|
|
|
Process(ctx context.Context, record Record) error
|
2019-11-05 23:08:55 +02:00
|
|
|
|
2019-11-15 23:01:20 +02:00
|
|
|
// CheckpointSet is the interface used by the controller to
|
|
|
|
// access the fully aggregated checkpoint after collection.
|
|
|
|
//
|
|
|
|
// The returned CheckpointSet is passed to the Exporter.
|
|
|
|
CheckpointSet() CheckpointSet
|
|
|
|
|
|
|
|
// FinishedCollection informs the Batcher that a complete
|
|
|
|
// collection round was completed. Stateless batchers might
|
|
|
|
// reset state in this method, for example.
|
|
|
|
FinishedCollection()
|
2019-11-05 23:08:55 +02:00
|
|
|
}
|
|
|
|
|
2019-11-15 23:01:20 +02:00
|
|
|
// AggregationSelector supports selecting the kind of Aggregator to
|
|
|
|
// use at runtime for a specific metric instrument.
|
|
|
|
type AggregationSelector interface {
|
|
|
|
// AggregatorFor returns the kind of aggregator suited to the
|
|
|
|
// requested export. Returning `nil` indicates to ignore this
|
|
|
|
// metric instrument. This must return a consistent type to
|
|
|
|
// avoid confusion in later stages of the metrics export
|
|
|
|
// process, i.e., when Merging multiple aggregators for a
|
|
|
|
// specific instrument.
|
|
|
|
//
|
|
|
|
// Note: This is context-free because the aggregator should
|
|
|
|
// not relate to the incoming context. This call should not
|
|
|
|
// block.
|
2020-03-19 21:02:46 +02:00
|
|
|
AggregatorFor(*metric.Descriptor) Aggregator
|
2019-11-15 23:01:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Aggregator implements a specific aggregation behavior, e.g., a
|
2020-03-11 01:00:37 +02:00
|
|
|
// behavior to track a sequence of updates to a counter, a measure, or
|
|
|
|
// an observer instrument. For the most part, counter semantics are
|
|
|
|
// fixed and the provided implementation should be used. Measure and
|
|
|
|
// observer metrics offer a wide range of potential tradeoffs and
|
|
|
|
// several implementations are provided.
|
2019-11-15 23:01:20 +02:00
|
|
|
//
|
|
|
|
// Aggregators are meant to compute the change (i.e., delta) in state
|
2020-03-11 01:00:37 +02:00
|
|
|
// from one checkpoint to the next, with the exception of LastValue
|
|
|
|
// aggregators. LastValue aggregators are required to maintain the last
|
|
|
|
// value across checkpoints.
|
2019-11-15 23:01:20 +02:00
|
|
|
//
|
|
|
|
// Note that any Aggregator may be attached to any instrument--this is
|
|
|
|
// the result of the OpenTelemetry API/SDK separation. It is possible
|
2020-03-11 01:00:37 +02:00
|
|
|
// to attach a counter aggregator to a Measure instrument (to compute
|
|
|
|
// a simple sum) or a LastValue aggregator to a measure instrument (to
|
2019-11-15 23:01:20 +02:00
|
|
|
// compute the last value).
|
2019-11-05 23:08:55 +02:00
|
|
|
type Aggregator interface {
|
2019-10-29 22:27:22 +02:00
|
|
|
// Update receives a new measured value and incorporates it
|
2019-11-15 23:01:20 +02:00
|
|
|
// into the aggregation. Update() calls may arrive
|
|
|
|
// concurrently as the SDK does not provide synchronization.
|
|
|
|
//
|
|
|
|
// Descriptor.NumberKind() should be consulted to determine
|
|
|
|
// whether the provided number is an int64 or float64.
|
|
|
|
//
|
|
|
|
// The Context argument comes from user-level code and could be
|
|
|
|
// inspected for distributed or span context.
|
2020-03-19 21:02:46 +02:00
|
|
|
Update(context.Context, core.Number, *metric.Descriptor) error
|
2019-11-15 23:01:20 +02:00
|
|
|
|
|
|
|
// Checkpoint is called during collection to finish one period
|
|
|
|
// of aggregation by atomically saving the current value.
|
|
|
|
// Checkpoint() is called concurrently with Update().
|
|
|
|
// Checkpoint should reset the current state to the empty
|
|
|
|
// state, in order to begin computing a new delta for the next
|
|
|
|
// collection period.
|
|
|
|
//
|
|
|
|
// After the checkpoint is taken, the current value may be
|
|
|
|
// accessed using by converting to one a suitable interface
|
|
|
|
// types in the `aggregator` sub-package.
|
|
|
|
//
|
|
|
|
// The Context argument originates from the controller that
|
|
|
|
// orchestrates collection.
|
2020-03-19 21:02:46 +02:00
|
|
|
Checkpoint(context.Context, *metric.Descriptor)
|
2019-11-15 23:01:20 +02:00
|
|
|
|
|
|
|
// Merge combines the checkpointed state from the argument
|
|
|
|
// aggregator into this aggregator's checkpointed state.
|
|
|
|
// Merge() is called in a single-threaded context, no locking
|
|
|
|
// is required.
|
2020-03-19 21:02:46 +02:00
|
|
|
Merge(Aggregator, *metric.Descriptor) error
|
2019-11-15 23:01:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Exporter handles presentation of the checkpoint of aggregate
|
|
|
|
// metrics. This is the final stage of a metrics export pipeline,
|
|
|
|
// where metric data are formatted for a specific system.
|
|
|
|
type Exporter interface {
|
|
|
|
// Export is called immediately after completing a collection
|
|
|
|
// pass in the SDK.
|
|
|
|
//
|
|
|
|
// The Context comes from the controller that initiated
|
|
|
|
// collection.
|
|
|
|
//
|
|
|
|
// The CheckpointSet interface refers to the Batcher that just
|
|
|
|
// completed collection.
|
|
|
|
Export(context.Context, CheckpointSet) error
|
|
|
|
}
|
|
|
|
|
|
|
|
// LabelEncoder enables an optimization for export pipelines that use
|
|
|
|
// text to encode their label sets.
|
|
|
|
//
|
|
|
|
// This interface allows configuring the encoder used in the SDK
|
|
|
|
// and/or the Batcher so that by the time the exporter is called, the
|
|
|
|
// same encoding may be used.
|
|
|
|
//
|
|
|
|
// If none is provided, a default will be used.
|
|
|
|
type LabelEncoder interface {
|
|
|
|
// Encode is called (concurrently) in instrumentation context.
|
|
|
|
// It should return a unique representation of the labels
|
|
|
|
// suitable for the SDK to use as a map key.
|
|
|
|
//
|
|
|
|
// The exported Labels object retains a reference to its
|
|
|
|
// LabelEncoder to determine which encoding was used.
|
|
|
|
//
|
|
|
|
// The expectation is that Exporters with a pre-determined to
|
|
|
|
// syntax for serialized label sets should implement
|
|
|
|
// LabelEncoder, thus avoiding duplicate computation in the
|
|
|
|
// export path.
|
|
|
|
Encode([]core.KeyValue) string
|
|
|
|
}
|
2019-10-29 22:27:22 +02:00
|
|
|
|
2019-11-15 23:01:20 +02:00
|
|
|
// CheckpointSet allows a controller to access a complete checkpoint of
|
|
|
|
// aggregated metrics from the Batcher. This is passed to the
|
|
|
|
// Exporter which may then use ForEach to iterate over the collection
|
|
|
|
// of aggregated metrics.
|
|
|
|
type CheckpointSet interface {
|
|
|
|
// ForEach iterates over aggregated checkpoints for all
|
|
|
|
// metrics that were updated during the last collection
|
2020-03-17 01:28:33 +02:00
|
|
|
// period. Each aggregated checkpoint returned by the
|
|
|
|
// function parameter may return an error.
|
|
|
|
// ForEach tolerates ErrNoData silently, as this is
|
|
|
|
// expected from the Meter implementation. Any other kind
|
|
|
|
// of error will immediately halt ForEach and return
|
|
|
|
// the error to the caller.
|
|
|
|
ForEach(func(Record) error) error
|
2019-11-15 23:01:20 +02:00
|
|
|
}
|
2019-10-31 07:15:27 +02:00
|
|
|
|
2019-11-15 23:01:20 +02:00
|
|
|
// Record contains the exported data for a single metric instrument
|
|
|
|
// and label set.
|
|
|
|
type Record struct {
|
2020-03-19 21:02:46 +02:00
|
|
|
descriptor *metric.Descriptor
|
2019-11-15 23:01:20 +02:00
|
|
|
labels Labels
|
|
|
|
aggregator Aggregator
|
2019-10-29 22:27:22 +02:00
|
|
|
}
|
|
|
|
|
2019-11-15 23:01:20 +02:00
|
|
|
// Labels stores complete information about a computed label set,
|
|
|
|
// including the labels in an appropriate order (as defined by the
|
|
|
|
// Batcher). If the batcher does not re-order labels, they are
|
|
|
|
// presented in sorted order by the SDK.
|
|
|
|
type Labels struct {
|
|
|
|
ordered []core.KeyValue
|
|
|
|
encoded string
|
|
|
|
encoder LabelEncoder
|
|
|
|
}
|
2019-10-29 22:27:22 +02:00
|
|
|
|
2019-11-15 23:01:20 +02:00
|
|
|
// NewLabels builds a Labels object, consisting of an ordered set of
|
|
|
|
// labels, a unique encoded representation, and the encoder that
|
|
|
|
// produced it.
|
|
|
|
func NewLabels(ordered []core.KeyValue, encoded string, encoder LabelEncoder) Labels {
|
|
|
|
return Labels{
|
|
|
|
ordered: ordered,
|
|
|
|
encoded: encoded,
|
|
|
|
encoder: encoder,
|
|
|
|
}
|
2019-10-29 22:27:22 +02:00
|
|
|
}
|
|
|
|
|
2019-11-15 23:01:20 +02:00
|
|
|
// Ordered returns the labels in a specified order, according to the
|
|
|
|
// Batcher.
|
|
|
|
func (l Labels) Ordered() []core.KeyValue {
|
|
|
|
return l.ordered
|
|
|
|
}
|
|
|
|
|
|
|
|
// Encoded is a pre-encoded form of the ordered labels.
|
|
|
|
func (l Labels) Encoded() string {
|
|
|
|
return l.encoded
|
|
|
|
}
|
|
|
|
|
|
|
|
// Encoder is the encoder that computed the Encoded() representation.
|
|
|
|
func (l Labels) Encoder() LabelEncoder {
|
|
|
|
return l.encoder
|
|
|
|
}
|
|
|
|
|
|
|
|
// Len returns the number of labels.
|
|
|
|
func (l Labels) Len() int {
|
|
|
|
return len(l.ordered)
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewRecord allows Batcher implementations to construct export
|
|
|
|
// records. The Descriptor, Labels, and Aggregator represent
|
|
|
|
// aggregate metric events received over a single collection period.
|
2020-03-19 21:02:46 +02:00
|
|
|
func NewRecord(descriptor *metric.Descriptor, labels Labels, aggregator Aggregator) Record {
|
2019-11-15 23:01:20 +02:00
|
|
|
return Record{
|
|
|
|
descriptor: descriptor,
|
|
|
|
labels: labels,
|
|
|
|
aggregator: aggregator,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Aggregator returns the checkpointed aggregator. It is safe to
|
|
|
|
// access the checkpointed state without locking.
|
|
|
|
func (r Record) Aggregator() Aggregator {
|
|
|
|
return r.aggregator
|
|
|
|
}
|
|
|
|
|
|
|
|
// Descriptor describes the metric instrument being exported.
|
2020-03-19 21:02:46 +02:00
|
|
|
func (r Record) Descriptor() *metric.Descriptor {
|
2019-11-15 23:01:20 +02:00
|
|
|
return r.descriptor
|
|
|
|
}
|
|
|
|
|
|
|
|
// Labels describes the labels associated with the instrument and the
|
|
|
|
// aggregated data.
|
|
|
|
func (r Record) Labels() Labels {
|
|
|
|
return r.labels
|
|
|
|
}
|