2020-03-23 22:41:10 -07:00
|
|
|
// Copyright The OpenTelemetry Authors
|
2019-10-29 13:27:22 -07:00
|
|
|
//
|
|
|
|
// 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-03-10 16:00:37 -07:00
|
|
|
package lastvalue // import "go.opentelemetry.io/otel/sdk/metric/aggregator/lastvalue"
|
2019-10-29 13:27:22 -07:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"sync/atomic"
|
|
|
|
"time"
|
|
|
|
"unsafe"
|
|
|
|
|
2020-11-12 16:28:32 +01:00
|
|
|
"go.opentelemetry.io/otel/metric"
|
2020-11-11 16:24:12 +01:00
|
|
|
"go.opentelemetry.io/otel/metric/number"
|
2019-11-05 13:08:55 -08:00
|
|
|
export "go.opentelemetry.io/otel/sdk/export/metric"
|
2020-06-09 22:53:30 -07:00
|
|
|
"go.opentelemetry.io/otel/sdk/export/metric/aggregation"
|
|
|
|
"go.opentelemetry.io/otel/sdk/metric/aggregator"
|
2019-10-29 13:27:22 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
type (
|
|
|
|
|
2020-03-10 16:00:37 -07:00
|
|
|
// Aggregator aggregates lastValue events.
|
2019-10-29 13:27:22 -07:00
|
|
|
Aggregator struct {
|
2020-06-13 00:55:01 -07:00
|
|
|
// value is an atomic pointer to *lastValueData. It is never nil.
|
|
|
|
value unsafe.Pointer
|
2019-10-29 13:27:22 -07:00
|
|
|
}
|
|
|
|
|
2020-03-10 16:00:37 -07:00
|
|
|
// lastValueData stores the current value of a lastValue along with
|
2019-10-29 13:27:22 -07:00
|
|
|
// a sequence number to determine the winner of a race.
|
2020-03-10 16:00:37 -07:00
|
|
|
lastValueData struct {
|
2019-10-29 13:27:22 -07:00
|
|
|
// value is the int64- or float64-encoded Set() data
|
2020-01-06 10:08:40 -08:00
|
|
|
//
|
|
|
|
// value needs to be aligned for 64-bit atomic operations.
|
2020-11-11 16:24:12 +01:00
|
|
|
value number.Number
|
2019-10-29 13:27:22 -07:00
|
|
|
|
|
|
|
// timestamp indicates when this record was submitted.
|
|
|
|
// this can be used to pick a winner when multiple
|
2020-03-10 16:00:37 -07:00
|
|
|
// records contain lastValue data for the same labels due
|
2019-10-29 13:27:22 -07:00
|
|
|
// to races.
|
|
|
|
timestamp time.Time
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2019-11-05 13:08:55 -08:00
|
|
|
var _ export.Aggregator = &Aggregator{}
|
2020-06-09 22:53:30 -07:00
|
|
|
var _ aggregation.LastValue = &Aggregator{}
|
2019-10-29 13:27:22 -07:00
|
|
|
|
2020-03-10 16:00:37 -07:00
|
|
|
// An unset lastValue has zero timestamp and zero value.
|
|
|
|
var unsetLastValue = &lastValueData{}
|
2019-10-29 13:27:22 -07:00
|
|
|
|
2020-03-10 16:00:37 -07:00
|
|
|
// New returns a new lastValue aggregator. This aggregator retains the
|
2019-10-29 13:27:22 -07:00
|
|
|
// last value and timestamp that were recorded.
|
2020-06-13 00:55:01 -07:00
|
|
|
func New(cnt int) []Aggregator {
|
|
|
|
aggs := make([]Aggregator, cnt)
|
|
|
|
for i := range aggs {
|
|
|
|
aggs[i] = Aggregator{
|
|
|
|
value: unsafe.Pointer(unsetLastValue),
|
|
|
|
}
|
2019-10-29 13:27:22 -07:00
|
|
|
}
|
2020-06-13 00:55:01 -07:00
|
|
|
return aggs
|
2019-10-29 13:27:22 -07:00
|
|
|
}
|
|
|
|
|
2020-06-18 10:16:33 -07:00
|
|
|
// Aggregation returns an interface for reading the state of this aggregator.
|
|
|
|
func (g *Aggregator) Aggregation() aggregation.Aggregation {
|
|
|
|
return g
|
|
|
|
}
|
|
|
|
|
2020-06-10 00:32:14 -07:00
|
|
|
// Kind returns aggregation.LastValueKind.
|
|
|
|
func (g *Aggregator) Kind() aggregation.Kind {
|
|
|
|
return aggregation.LastValueKind
|
|
|
|
}
|
|
|
|
|
2020-03-10 16:00:37 -07:00
|
|
|
// LastValue returns the last-recorded lastValue value and the
|
2020-06-09 22:53:30 -07:00
|
|
|
// corresponding timestamp. The error value aggregation.ErrNoData
|
2019-11-15 13:01:20 -08:00
|
|
|
// will be returned if (due to a race condition) the checkpoint was
|
|
|
|
// computed before the first value was set.
|
2020-11-11 16:24:12 +01:00
|
|
|
func (g *Aggregator) LastValue() (number.Number, time.Time, error) {
|
2020-06-13 00:55:01 -07:00
|
|
|
gd := (*lastValueData)(g.value)
|
2020-03-10 16:00:37 -07:00
|
|
|
if gd == unsetLastValue {
|
2020-06-13 00:55:01 -07:00
|
|
|
return 0, time.Time{}, aggregation.ErrNoData
|
2019-11-15 13:01:20 -08:00
|
|
|
}
|
|
|
|
return gd.value.AsNumber(), gd.timestamp, nil
|
2019-10-29 13:27:22 -07:00
|
|
|
}
|
|
|
|
|
2020-06-23 10:41:11 -07:00
|
|
|
// SynchronizedMove atomically saves the current value.
|
2020-11-12 16:28:32 +01:00
|
|
|
func (g *Aggregator) SynchronizedMove(oa export.Aggregator, _ *metric.Descriptor) error {
|
2020-06-13 00:55:01 -07:00
|
|
|
o, _ := oa.(*Aggregator)
|
|
|
|
if o == nil {
|
|
|
|
return aggregator.NewInconsistentAggregatorError(g, oa)
|
|
|
|
}
|
|
|
|
o.value = atomic.SwapPointer(&g.value, unsafe.Pointer(unsetLastValue))
|
|
|
|
return nil
|
2019-10-29 13:27:22 -07:00
|
|
|
}
|
|
|
|
|
2019-11-15 13:01:20 -08:00
|
|
|
// Update atomically sets the current "last" value.
|
2020-11-12 16:28:32 +01:00
|
|
|
func (g *Aggregator) Update(_ context.Context, number number.Number, desc *metric.Descriptor) error {
|
2020-03-10 16:00:37 -07:00
|
|
|
ngd := &lastValueData{
|
2019-10-29 13:27:22 -07:00
|
|
|
value: number,
|
|
|
|
timestamp: time.Now(),
|
|
|
|
}
|
2020-06-13 00:55:01 -07:00
|
|
|
atomic.StorePointer(&g.value, unsafe.Pointer(ngd))
|
2020-03-10 16:00:37 -07:00
|
|
|
return nil
|
2019-10-29 13:27:22 -07:00
|
|
|
}
|
|
|
|
|
2020-03-10 16:00:37 -07:00
|
|
|
// Merge combines state from two aggregators. The most-recently set
|
|
|
|
// value is chosen.
|
2020-11-12 16:28:32 +01:00
|
|
|
func (g *Aggregator) Merge(oa export.Aggregator, desc *metric.Descriptor) error {
|
2019-10-30 22:15:27 -07:00
|
|
|
o, _ := oa.(*Aggregator)
|
|
|
|
if o == nil {
|
2020-06-13 00:55:01 -07:00
|
|
|
return aggregator.NewInconsistentAggregatorError(g, oa)
|
2019-10-30 22:15:27 -07:00
|
|
|
}
|
|
|
|
|
2020-06-13 00:55:01 -07:00
|
|
|
ggd := (*lastValueData)(atomic.LoadPointer(&g.value))
|
|
|
|
ogd := (*lastValueData)(atomic.LoadPointer(&o.value))
|
2019-10-30 22:15:27 -07:00
|
|
|
|
|
|
|
if ggd.timestamp.After(ogd.timestamp) {
|
2019-11-15 13:01:20 -08:00
|
|
|
return nil
|
2019-10-30 22:15:27 -07:00
|
|
|
}
|
|
|
|
|
2020-06-13 00:55:01 -07:00
|
|
|
g.value = unsafe.Pointer(ogd)
|
2019-11-15 13:01:20 -08:00
|
|
|
return nil
|
2019-10-30 22:15:27 -07:00
|
|
|
}
|