mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2024-12-16 10:19:23 +02:00
be8fb0b4e2
* initial metrics work * rename cumulative to counter * rename bidirectional to nonmonotonic * rename unidirectional to monotonic * rename nonnegative to signed this changes the default semantics a bit - before the change measure could record negative values by default, now it can't. The specification draft currently specifies both NonNegative and Signed, but I think it's a mistake. * rename instrument to descriptor * license * rework measurement values * make measurement value a tagged union * simplify to one kind of metrics * add observers * change some interfaces to match the spec * keep integral measurement separate from floating ones * remove duplicated measurement type * add checking for options * reorder some fields and functions * rename a function to avoid confusion between the Handle type and the Measure type * drop disabled field from descriptor * add back typed API for metrics * make metric options type safe * merge alternatives into a single bool * make value kind name less stuttery * fix observation callback prototype * drop context parameter from NewHandle * drop useless parameter names * make descriptor an opaque struct * use a store helper * handle comment fixes * reword Alternate comment * drop the "any value" metrics * make measurement value simpler * document value stuff * add tests for values * docs * do not panic if there is no span ID in the event
340 lines
9.7 KiB
Go
340 lines
9.7 KiB
Go
// 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.
|
|
|
|
//go:generate stringer -type=Kind,ValueKind
|
|
|
|
package metric
|
|
|
|
import (
|
|
"context"
|
|
|
|
"go.opentelemetry.io/api/core"
|
|
"go.opentelemetry.io/api/unit"
|
|
)
|
|
|
|
// Kind categorizes different kinds of metric.
|
|
type Kind int
|
|
|
|
const (
|
|
// Invalid describes an invalid metric.
|
|
Invalid Kind = iota
|
|
// CounterKind describes a metric that supports Add().
|
|
CounterKind
|
|
// GaugeKind describes a metric that supports Set().
|
|
GaugeKind
|
|
// MeasureKind describes a metric that supports Record().
|
|
MeasureKind
|
|
// ObserverKind describes a metric that reports measurement on
|
|
// demand.
|
|
ObserverKind
|
|
)
|
|
|
|
// Handle is the implementation-level interface to Set/Add/Record
|
|
// individual metrics.
|
|
type Handle interface {
|
|
// RecordOne allows the SDK to observe a single metric event
|
|
RecordOne(ctx context.Context, value MeasurementValue)
|
|
}
|
|
|
|
// TODO this belongs outside the metrics API, in some sense, but that
|
|
// might create a dependency. Putting this here means we can't re-use
|
|
// a LabelSet between metrics and tracing, even when they are the same
|
|
// SDK.
|
|
|
|
// LabelSet represents a []core.KeyValue for use as pre-defined labels
|
|
// in the metrics API.
|
|
type LabelSet interface {
|
|
Meter() Meter
|
|
}
|
|
|
|
// ObservationCallback defines a type of the callback the observer
|
|
// will use to report the measurement
|
|
type ObservationCallback func(LabelSet, MeasurementValue)
|
|
|
|
// ObserverCallback defines a type of the callback SDK will call for
|
|
// the registered observers.
|
|
type ObserverCallback func(Meter, Observer, ObservationCallback)
|
|
|
|
// Meter is an interface to the metrics portion of the OpenTelemetry SDK.
|
|
type Meter interface {
|
|
// DefineLabels returns a reference to a set of labels that
|
|
// cannot be read by the application.
|
|
DefineLabels(context.Context, ...core.KeyValue) LabelSet
|
|
|
|
// RecordBatch atomically records a batch of measurements.
|
|
RecordBatch(context.Context, LabelSet, ...Measurement)
|
|
|
|
// NewHandle creates a Handle that contains the passed
|
|
// key-value pairs. This should not be used directly - prefer
|
|
// using GetHandle function of a metric.
|
|
NewHandle(*Descriptor, LabelSet) Handle
|
|
// DeleteHandle destroys the Handle and does a cleanup of the
|
|
// underlying resources.
|
|
DeleteHandle(Handle)
|
|
|
|
// RegisterObserver registers the observer with callback
|
|
// returning a measurement. When and how often the callback
|
|
// will be called is defined by SDK. This should not be used
|
|
// directly - prefer either RegisterInt64Observer or
|
|
// RegisterFloat64Observer, depending on the type of the
|
|
// observer to be registered.
|
|
RegisterObserver(Observer, ObserverCallback)
|
|
// UnregisterObserver removes the observer from registered
|
|
// observers. This should not be used directly - prefer either
|
|
// UnregisterInt64Observer or UnregisterFloat64Observer,
|
|
// depending on the type of the observer to be registered.
|
|
UnregisterObserver(Observer)
|
|
}
|
|
|
|
// DescriptorID is a unique identifier of a metric.
|
|
type DescriptorID uint64
|
|
|
|
// ValueKind describes the data type of the measurement value the
|
|
// metric generates.
|
|
type ValueKind int8
|
|
|
|
const (
|
|
// Int64ValueKind means that the metric generates values of
|
|
// type int64.
|
|
Int64ValueKind ValueKind = iota
|
|
// Float64ValueKind means that the metric generates values of
|
|
// type float64.
|
|
Float64ValueKind
|
|
)
|
|
|
|
// Descriptor represents a named metric with recommended
|
|
// local-aggregation keys.
|
|
type Descriptor struct {
|
|
name string
|
|
kind Kind
|
|
keys []core.Key
|
|
id DescriptorID
|
|
description string
|
|
unit unit.Unit
|
|
valueKind ValueKind
|
|
alternate bool
|
|
}
|
|
|
|
// Name is a required field describing this metric descriptor, should
|
|
// have length > 0.
|
|
func (d *Descriptor) Name() string {
|
|
return d.name
|
|
}
|
|
|
|
// Kind is the metric kind of this descriptor.
|
|
func (d *Descriptor) Kind() Kind {
|
|
return d.kind
|
|
}
|
|
|
|
// Keys are recommended keys determined in the handles obtained for
|
|
// this metric.
|
|
func (d *Descriptor) Keys() []core.Key {
|
|
return d.keys
|
|
}
|
|
|
|
// ID is uniquely assigned to support per-SDK registration.
|
|
func (d *Descriptor) ID() DescriptorID {
|
|
return d.id
|
|
}
|
|
|
|
// Description is an optional field describing this metric descriptor.
|
|
func (d *Descriptor) Description() string {
|
|
return d.description
|
|
}
|
|
|
|
// Unit is an optional field describing this metric descriptor.
|
|
func (d *Descriptor) Unit() unit.Unit {
|
|
return d.unit
|
|
}
|
|
|
|
// ValueKind describes the type of values the metric produces.
|
|
func (d *Descriptor) ValueKind() ValueKind {
|
|
return d.valueKind
|
|
}
|
|
|
|
// Alternate defines the property of metric value dependent on a
|
|
// metric type.
|
|
//
|
|
// - for Counter, true implies that the metric is an up-down Counter
|
|
//
|
|
// - for Gauge/Observer, true implies that the metric is a
|
|
// non-descending Gauge/Observer
|
|
//
|
|
// - for Measure, true implies that the metric supports positive and
|
|
// negative values
|
|
func (d *Descriptor) Alternate() bool {
|
|
return d.alternate
|
|
}
|
|
|
|
// Measurement is used for reporting a batch of metric values.
|
|
type Measurement struct {
|
|
Descriptor *Descriptor
|
|
Value MeasurementValue
|
|
}
|
|
|
|
// Option supports specifying the various metric options.
|
|
type Option func(*Descriptor)
|
|
|
|
// OptionApplier is an interface for applying metric options that are
|
|
// valid for all the kinds of metrics.
|
|
type OptionApplier interface {
|
|
CounterOptionApplier
|
|
GaugeOptionApplier
|
|
MeasureOptionApplier
|
|
// ApplyOption is used to make some changes in the Descriptor.
|
|
ApplyOption(*Descriptor)
|
|
}
|
|
|
|
type optionWrapper struct {
|
|
F Option
|
|
}
|
|
|
|
var _ OptionApplier = optionWrapper{}
|
|
|
|
func (o optionWrapper) ApplyCounterOption(d *Descriptor) {
|
|
o.ApplyOption(d)
|
|
}
|
|
|
|
func (o optionWrapper) ApplyGaugeOption(d *Descriptor) {
|
|
o.ApplyOption(d)
|
|
}
|
|
|
|
func (o optionWrapper) ApplyMeasureOption(d *Descriptor) {
|
|
o.ApplyOption(d)
|
|
}
|
|
|
|
func (o optionWrapper) ApplyOption(d *Descriptor) {
|
|
o.F(d)
|
|
}
|
|
|
|
// WithDescription applies provided description.
|
|
func WithDescription(desc string) OptionApplier {
|
|
return optionWrapper{
|
|
F: func(d *Descriptor) {
|
|
d.description = desc
|
|
},
|
|
}
|
|
}
|
|
|
|
// WithUnit applies provided unit.
|
|
func WithUnit(unit unit.Unit) OptionApplier {
|
|
return optionWrapper{
|
|
F: func(d *Descriptor) {
|
|
d.unit = unit
|
|
},
|
|
}
|
|
}
|
|
|
|
// WithKeys applies required label keys. Multiple `WithKeys` options
|
|
// accumulate.
|
|
func WithKeys(keys ...core.Key) OptionApplier {
|
|
return optionWrapper{
|
|
F: func(d *Descriptor) {
|
|
d.keys = append(d.keys, keys...)
|
|
},
|
|
}
|
|
}
|
|
|
|
// WithNonMonotonic sets whether a counter is permitted to go up AND
|
|
// down.
|
|
func WithNonMonotonic(nm bool) CounterOptionApplier {
|
|
return counterOptionWrapper{
|
|
F: func(d *Descriptor) {
|
|
d.alternate = nm
|
|
},
|
|
}
|
|
}
|
|
|
|
// WithMonotonic sets whether a gauge is not permitted to go down.
|
|
func WithMonotonic(m bool) GaugeOptionApplier {
|
|
return gaugeOptionWrapper{
|
|
F: func(d *Descriptor) {
|
|
d.alternate = m
|
|
},
|
|
}
|
|
}
|
|
|
|
// WithSigned sets whether a measure is permitted to be negative.
|
|
func WithSigned(s bool) MeasureOptionApplier {
|
|
return measureOptionWrapper{
|
|
F: func(d *Descriptor) {
|
|
d.alternate = s
|
|
},
|
|
}
|
|
}
|
|
|
|
// Defined returns true when the descriptor has been registered.
|
|
func (d Descriptor) Defined() bool {
|
|
return len(d.name) != 0
|
|
}
|
|
|
|
// RecordBatch reports to the global Meter.
|
|
func RecordBatch(ctx context.Context, labels LabelSet, batch ...Measurement) {
|
|
GlobalMeter().RecordBatch(ctx, labels, batch...)
|
|
}
|
|
|
|
// Int64ObservationCallback defines a type of the callback the
|
|
// observer will use to report the int64 measurement.
|
|
type Int64ObservationCallback func(LabelSet, int64)
|
|
|
|
// Int64ObserverCallback defines a type of the callback SDK will call
|
|
// for the registered int64 observers.
|
|
type Int64ObserverCallback func(Meter, Int64Observer, Int64ObservationCallback)
|
|
|
|
// RegisterInt64Observer is a convenience wrapper around
|
|
// Meter.RegisterObserver that provides a type-safe callback for
|
|
// Int64Observer.
|
|
func RegisterInt64Observer(meter Meter, observer Int64Observer, callback Int64ObserverCallback) {
|
|
cb := func(m Meter, o Observer, ocb ObservationCallback) {
|
|
iocb := func(l LabelSet, i int64) {
|
|
ocb(l, NewInt64MeasurementValue(i))
|
|
}
|
|
callback(m, Int64Observer{o}, iocb)
|
|
}
|
|
meter.RegisterObserver(observer.Observer, cb)
|
|
}
|
|
|
|
// UnregisterInt64Observer is a convenience wrapper around
|
|
// Meter.UnregisterObserver for Int64Observer.
|
|
func UnregisterInt64Observer(meter Meter, observer Int64Observer) {
|
|
meter.UnregisterObserver(observer.Observer)
|
|
}
|
|
|
|
// Float64ObservationCallback defines a type of the callback the
|
|
// observer will use to report the float64 measurement.
|
|
type Float64ObservationCallback func(LabelSet, float64)
|
|
|
|
// Float64ObserverCallback defines a type of the callback SDK will
|
|
// call for the registered float64 observers.
|
|
type Float64ObserverCallback func(Meter, Float64Observer, Float64ObservationCallback)
|
|
|
|
// RegisterFloat64Observer is a convenience wrapper around
|
|
// Meter.RegisterObserver that provides a type-safe callback for
|
|
// Float64Observer.
|
|
func RegisterFloat64Observer(meter Meter, observer Float64Observer, callback Float64ObserverCallback) {
|
|
cb := func(m Meter, o Observer, ocb ObservationCallback) {
|
|
focb := func(l LabelSet, f float64) {
|
|
ocb(l, NewFloat64MeasurementValue(f))
|
|
}
|
|
callback(m, Float64Observer{o}, focb)
|
|
}
|
|
meter.RegisterObserver(observer.Observer, cb)
|
|
}
|
|
|
|
// UnregisterFloat64Observer is a convenience wrapper around
|
|
// Meter.UnregisterObserver for Float64Observer.
|
|
func UnregisterFloat64Observer(meter Meter, observer Float64Observer) {
|
|
meter.UnregisterObserver(observer.Observer)
|
|
}
|