1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2024-12-12 10:04:29 +02:00
opentelemetry-go/sdk/metric/meter_test.go
Tyler Yahn 36904e4463
Deprecate the syncint64/syncfloat64/asyncint64/asyncfloat64 packages (#3575)
* Dep async/sync pkgs for new inst in instrument pkg

* Replace use of deprecated instruments

* Add changelog entry

* Update changelog entry PR number
2023-01-10 15:06:24 -08:00

1075 lines
30 KiB
Go

// Copyright The 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.
package metric
import (
"context"
"sync"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/instrument"
"go.opentelemetry.io/otel/sdk/instrumentation"
"go.opentelemetry.io/otel/sdk/metric/aggregation"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
"go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest"
"go.opentelemetry.io/otel/sdk/resource"
)
// A meter should be able to make instruments concurrently.
func TestMeterInstrumentConcurrency(t *testing.T) {
wg := &sync.WaitGroup{}
wg.Add(12)
m := NewMeterProvider().Meter("inst-concurrency")
go func() {
_, _ = m.Float64ObservableCounter("AFCounter")
wg.Done()
}()
go func() {
_, _ = m.Float64ObservableUpDownCounter("AFUpDownCounter")
wg.Done()
}()
go func() {
_, _ = m.Float64ObservableGauge("AFGauge")
wg.Done()
}()
go func() {
_, _ = m.Int64ObservableCounter("AICounter")
wg.Done()
}()
go func() {
_, _ = m.Int64ObservableUpDownCounter("AIUpDownCounter")
wg.Done()
}()
go func() {
_, _ = m.Int64ObservableGauge("AIGauge")
wg.Done()
}()
go func() {
_, _ = m.Float64Counter("SFCounter")
wg.Done()
}()
go func() {
_, _ = m.Float64UpDownCounter("SFUpDownCounter")
wg.Done()
}()
go func() {
_, _ = m.Float64Histogram("SFHistogram")
wg.Done()
}()
go func() {
_, _ = m.Int64Counter("SICounter")
wg.Done()
}()
go func() {
_, _ = m.Int64UpDownCounter("SIUpDownCounter")
wg.Done()
}()
go func() {
_, _ = m.Int64Histogram("SIHistogram")
wg.Done()
}()
wg.Wait()
}
var emptyCallback metric.Callback = func(ctx context.Context) error { return nil }
// A Meter Should be able register Callbacks Concurrently.
func TestMeterCallbackCreationConcurrency(t *testing.T) {
wg := &sync.WaitGroup{}
wg.Add(2)
m := NewMeterProvider().Meter("callback-concurrency")
go func() {
_, _ = m.RegisterCallback([]instrument.Asynchronous{}, emptyCallback)
wg.Done()
}()
go func() {
_, _ = m.RegisterCallback([]instrument.Asynchronous{}, emptyCallback)
wg.Done()
}()
wg.Wait()
}
func TestNoopCallbackUnregisterConcurrency(t *testing.T) {
m := NewMeterProvider().Meter("noop-unregister-concurrency")
reg, err := m.RegisterCallback(nil, emptyCallback)
require.NoError(t, err)
wg := &sync.WaitGroup{}
wg.Add(2)
go func() {
_ = reg.Unregister()
wg.Done()
}()
go func() {
_ = reg.Unregister()
wg.Done()
}()
wg.Wait()
}
func TestCallbackUnregisterConcurrency(t *testing.T) {
reader := NewManualReader()
provider := NewMeterProvider(WithReader(reader))
meter := provider.Meter("unregister-concurrency")
actr, err := meter.Float64ObservableCounter("counter")
require.NoError(t, err)
ag, err := meter.Int64ObservableGauge("gauge")
require.NoError(t, err)
i := []instrument.Asynchronous{actr}
regCtr, err := meter.RegisterCallback(i, emptyCallback)
require.NoError(t, err)
i = []instrument.Asynchronous{ag}
regG, err := meter.RegisterCallback(i, emptyCallback)
require.NoError(t, err)
wg := &sync.WaitGroup{}
wg.Add(2)
go func() {
_ = regCtr.Unregister()
_ = regG.Unregister()
wg.Done()
}()
go func() {
_ = regCtr.Unregister()
_ = regG.Unregister()
wg.Done()
}()
wg.Wait()
}
// Instruments should produce correct ResourceMetrics.
func TestMeterCreatesInstruments(t *testing.T) {
attrs := []attribute.KeyValue{attribute.String("name", "alice")}
seven := 7.0
testCases := []struct {
name string
fn func(*testing.T, metric.Meter)
want metricdata.Metrics
}{
{
name: "ObservableInt64Count",
fn: func(t *testing.T, m metric.Meter) {
cback := func(ctx context.Context, o instrument.Int64Observer) error {
o.Observe(ctx, 4, attrs...)
return nil
}
ctr, err := m.Int64ObservableCounter("aint", instrument.WithInt64Callback(cback))
assert.NoError(t, err)
_, err = m.RegisterCallback([]instrument.Asynchronous{ctr}, func(ctx context.Context) error {
ctr.Observe(ctx, 3)
return nil
})
assert.NoError(t, err)
// Observed outside of a callback, it should be ignored.
ctr.Observe(context.Background(), 19)
},
want: metricdata.Metrics{
Name: "aint",
Data: metricdata.Sum[int64]{
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: true,
DataPoints: []metricdata.DataPoint[int64]{
{Attributes: attribute.NewSet(attrs...), Value: 4},
{Value: 3},
},
},
},
},
{
name: "ObservableInt64UpDownCount",
fn: func(t *testing.T, m metric.Meter) {
cback := func(ctx context.Context, o instrument.Int64Observer) error {
o.Observe(ctx, 4, attrs...)
return nil
}
ctr, err := m.Int64ObservableUpDownCounter("aint", instrument.WithInt64Callback(cback))
assert.NoError(t, err)
_, err = m.RegisterCallback([]instrument.Asynchronous{ctr}, func(ctx context.Context) error {
ctr.Observe(ctx, 11)
return nil
})
assert.NoError(t, err)
// Observed outside of a callback, it should be ignored.
ctr.Observe(context.Background(), 19)
},
want: metricdata.Metrics{
Name: "aint",
Data: metricdata.Sum[int64]{
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: false,
DataPoints: []metricdata.DataPoint[int64]{
{Attributes: attribute.NewSet(attrs...), Value: 4},
{Value: 11},
},
},
},
},
{
name: "ObservableInt64Gauge",
fn: func(t *testing.T, m metric.Meter) {
cback := func(ctx context.Context, o instrument.Int64Observer) error {
o.Observe(ctx, 4, attrs...)
return nil
}
gauge, err := m.Int64ObservableGauge("agauge", instrument.WithInt64Callback(cback))
assert.NoError(t, err)
_, err = m.RegisterCallback([]instrument.Asynchronous{gauge}, func(ctx context.Context) error {
gauge.Observe(ctx, 11)
return nil
})
assert.NoError(t, err)
// Observed outside of a callback, it should be ignored.
gauge.Observe(context.Background(), 19)
},
want: metricdata.Metrics{
Name: "agauge",
Data: metricdata.Gauge[int64]{
DataPoints: []metricdata.DataPoint[int64]{
{Attributes: attribute.NewSet(attrs...), Value: 4},
{Value: 11},
},
},
},
},
{
name: "ObservableFloat64Count",
fn: func(t *testing.T, m metric.Meter) {
cback := func(ctx context.Context, o instrument.Float64Observer) error {
o.Observe(ctx, 4, attrs...)
return nil
}
ctr, err := m.Float64ObservableCounter("afloat", instrument.WithFloat64Callback(cback))
assert.NoError(t, err)
_, err = m.RegisterCallback([]instrument.Asynchronous{ctr}, func(ctx context.Context) error {
ctr.Observe(ctx, 3)
return nil
})
assert.NoError(t, err)
// Observed outside of a callback, it should be ignored.
ctr.Observe(context.Background(), 19)
},
want: metricdata.Metrics{
Name: "afloat",
Data: metricdata.Sum[float64]{
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: true,
DataPoints: []metricdata.DataPoint[float64]{
{Attributes: attribute.NewSet(attrs...), Value: 4},
{Value: 3},
},
},
},
},
{
name: "ObservableFloat64UpDownCount",
fn: func(t *testing.T, m metric.Meter) {
cback := func(ctx context.Context, o instrument.Float64Observer) error {
o.Observe(ctx, 4, attrs...)
return nil
}
ctr, err := m.Float64ObservableUpDownCounter("afloat", instrument.WithFloat64Callback(cback))
assert.NoError(t, err)
_, err = m.RegisterCallback([]instrument.Asynchronous{ctr}, func(ctx context.Context) error {
ctr.Observe(ctx, 11)
return nil
})
assert.NoError(t, err)
// Observed outside of a callback, it should be ignored.
ctr.Observe(context.Background(), 19)
},
want: metricdata.Metrics{
Name: "afloat",
Data: metricdata.Sum[float64]{
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: false,
DataPoints: []metricdata.DataPoint[float64]{
{Attributes: attribute.NewSet(attrs...), Value: 4},
{Value: 11},
},
},
},
},
{
name: "ObservableFloat64Gauge",
fn: func(t *testing.T, m metric.Meter) {
cback := func(ctx context.Context, o instrument.Float64Observer) error {
o.Observe(ctx, 4, attrs...)
return nil
}
gauge, err := m.Float64ObservableGauge("agauge", instrument.WithFloat64Callback(cback))
assert.NoError(t, err)
_, err = m.RegisterCallback([]instrument.Asynchronous{gauge}, func(ctx context.Context) error {
gauge.Observe(ctx, 11)
return nil
})
assert.NoError(t, err)
// Observed outside of a callback, it should be ignored.
gauge.Observe(context.Background(), 19)
},
want: metricdata.Metrics{
Name: "agauge",
Data: metricdata.Gauge[float64]{
DataPoints: []metricdata.DataPoint[float64]{
{Attributes: attribute.NewSet(attrs...), Value: 4},
{Value: 11},
},
},
},
},
{
name: "SyncInt64Count",
fn: func(t *testing.T, m metric.Meter) {
ctr, err := m.Int64Counter("sint")
assert.NoError(t, err)
ctr.Add(context.Background(), 3)
},
want: metricdata.Metrics{
Name: "sint",
Data: metricdata.Sum[int64]{
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: true,
DataPoints: []metricdata.DataPoint[int64]{
{Value: 3},
},
},
},
},
{
name: "SyncInt64UpDownCount",
fn: func(t *testing.T, m metric.Meter) {
ctr, err := m.Int64UpDownCounter("sint")
assert.NoError(t, err)
ctr.Add(context.Background(), 11)
},
want: metricdata.Metrics{
Name: "sint",
Data: metricdata.Sum[int64]{
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: false,
DataPoints: []metricdata.DataPoint[int64]{
{Value: 11},
},
},
},
},
{
name: "SyncInt64Histogram",
fn: func(t *testing.T, m metric.Meter) {
gauge, err := m.Int64Histogram("histogram")
assert.NoError(t, err)
gauge.Record(context.Background(), 7)
},
want: metricdata.Metrics{
Name: "histogram",
Data: metricdata.Histogram{
Temporality: metricdata.CumulativeTemporality,
DataPoints: []metricdata.HistogramDataPoint{
{
Attributes: attribute.Set{},
Count: 1,
Bounds: []float64{0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000},
BucketCounts: []uint64{0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Min: &seven,
Max: &seven,
Sum: 7.0,
},
},
},
},
},
{
name: "SyncFloat64Count",
fn: func(t *testing.T, m metric.Meter) {
ctr, err := m.Float64Counter("sfloat")
assert.NoError(t, err)
ctr.Add(context.Background(), 3)
},
want: metricdata.Metrics{
Name: "sfloat",
Data: metricdata.Sum[float64]{
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: true,
DataPoints: []metricdata.DataPoint[float64]{
{Value: 3},
},
},
},
},
{
name: "SyncFloat64UpDownCount",
fn: func(t *testing.T, m metric.Meter) {
ctr, err := m.Float64UpDownCounter("sfloat")
assert.NoError(t, err)
ctr.Add(context.Background(), 11)
},
want: metricdata.Metrics{
Name: "sfloat",
Data: metricdata.Sum[float64]{
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: false,
DataPoints: []metricdata.DataPoint[float64]{
{Value: 11},
},
},
},
},
{
name: "SyncFloat64Histogram",
fn: func(t *testing.T, m metric.Meter) {
gauge, err := m.Float64Histogram("histogram")
assert.NoError(t, err)
gauge.Record(context.Background(), 7)
},
want: metricdata.Metrics{
Name: "histogram",
Data: metricdata.Histogram{
Temporality: metricdata.CumulativeTemporality,
DataPoints: []metricdata.HistogramDataPoint{
{
Attributes: attribute.Set{},
Count: 1,
Bounds: []float64{0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000},
BucketCounts: []uint64{0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Min: &seven,
Max: &seven,
Sum: 7.0,
},
},
},
},
},
}
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
rdr := NewManualReader()
m := NewMeterProvider(WithReader(rdr)).Meter("testInstruments")
tt.fn(t, m)
rm, err := rdr.Collect(context.Background())
assert.NoError(t, err)
require.Len(t, rm.ScopeMetrics, 1)
sm := rm.ScopeMetrics[0]
require.Len(t, sm.Metrics, 1)
got := sm.Metrics[0]
metricdatatest.AssertEqual(t, tt.want, got, metricdatatest.IgnoreTimestamp())
})
}
}
func TestMetersProvideScope(t *testing.T) {
rdr := NewManualReader()
mp := NewMeterProvider(WithReader(rdr))
m1 := mp.Meter("scope1")
ctr1, err := m1.Float64ObservableCounter("ctr1")
assert.NoError(t, err)
_, err = m1.RegisterCallback([]instrument.Asynchronous{ctr1}, func(ctx context.Context) error {
ctr1.Observe(ctx, 5)
return nil
})
assert.NoError(t, err)
m2 := mp.Meter("scope2")
ctr2, err := m2.Int64ObservableCounter("ctr2")
assert.NoError(t, err)
_, err = m1.RegisterCallback([]instrument.Asynchronous{ctr2}, func(ctx context.Context) error {
ctr2.Observe(ctx, 7)
return nil
})
assert.NoError(t, err)
want := metricdata.ResourceMetrics{
Resource: resource.Default(),
ScopeMetrics: []metricdata.ScopeMetrics{
{
Scope: instrumentation.Scope{
Name: "scope1",
},
Metrics: []metricdata.Metrics{
{
Name: "ctr1",
Data: metricdata.Sum[float64]{
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: true,
DataPoints: []metricdata.DataPoint[float64]{
{
Value: 5,
},
},
},
},
},
},
{
Scope: instrumentation.Scope{
Name: "scope2",
},
Metrics: []metricdata.Metrics{
{
Name: "ctr2",
Data: metricdata.Sum[int64]{
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: true,
DataPoints: []metricdata.DataPoint[int64]{
{
Value: 7,
},
},
},
},
},
},
},
}
got, err := rdr.Collect(context.Background())
assert.NoError(t, err)
metricdatatest.AssertEqual(t, want, got, metricdatatest.IgnoreTimestamp())
}
func TestUnregisterUnregisters(t *testing.T) {
r := NewManualReader()
mp := NewMeterProvider(WithReader(r))
m := mp.Meter("TestUnregisterUnregisters")
int64Counter, err := m.Int64ObservableCounter("int64.counter")
require.NoError(t, err)
int64UpDownCounter, err := m.Int64ObservableUpDownCounter("int64.up_down_counter")
require.NoError(t, err)
int64Gauge, err := m.Int64ObservableGauge("int64.gauge")
require.NoError(t, err)
floag64Counter, err := m.Float64ObservableCounter("floag64.counter")
require.NoError(t, err)
floag64UpDownCounter, err := m.Float64ObservableUpDownCounter("floag64.up_down_counter")
require.NoError(t, err)
floag64Gauge, err := m.Float64ObservableGauge("floag64.gauge")
require.NoError(t, err)
var called bool
reg, err := m.RegisterCallback([]instrument.Asynchronous{
int64Counter,
int64UpDownCounter,
int64Gauge,
floag64Counter,
floag64UpDownCounter,
floag64Gauge,
}, func(context.Context) error {
called = true
return nil
})
require.NoError(t, err)
ctx := context.Background()
_, err = r.Collect(ctx)
require.NoError(t, err)
assert.True(t, called, "callback not called for registered callback")
called = false
require.NoError(t, reg.Unregister(), "unregister")
_, err = r.Collect(ctx)
require.NoError(t, err)
assert.False(t, called, "callback called for unregistered callback")
}
func TestRegisterCallbackDropAggregations(t *testing.T) {
aggFn := func(InstrumentKind) aggregation.Aggregation {
return aggregation.Drop{}
}
r := NewManualReader(WithAggregationSelector(aggFn))
mp := NewMeterProvider(WithReader(r))
m := mp.Meter("testRegisterCallbackDropAggregations")
int64Counter, err := m.Int64ObservableCounter("int64.counter")
require.NoError(t, err)
int64UpDownCounter, err := m.Int64ObservableUpDownCounter("int64.up_down_counter")
require.NoError(t, err)
int64Gauge, err := m.Int64ObservableGauge("int64.gauge")
require.NoError(t, err)
floag64Counter, err := m.Float64ObservableCounter("floag64.counter")
require.NoError(t, err)
floag64UpDownCounter, err := m.Float64ObservableUpDownCounter("floag64.up_down_counter")
require.NoError(t, err)
floag64Gauge, err := m.Float64ObservableGauge("floag64.gauge")
require.NoError(t, err)
var called bool
_, err = m.RegisterCallback([]instrument.Asynchronous{
int64Counter,
int64UpDownCounter,
int64Gauge,
floag64Counter,
floag64UpDownCounter,
floag64Gauge,
}, func(context.Context) error {
called = true
return nil
})
require.NoError(t, err)
data, err := r.Collect(context.Background())
require.NoError(t, err)
assert.False(t, called, "callback called for all drop instruments")
assert.Len(t, data.ScopeMetrics, 0, "metrics exported for drop instruments")
}
func TestAttributeFilter(t *testing.T) {
one := 1.0
two := 2.0
testcases := []struct {
name string
register func(t *testing.T, mtr metric.Meter) error
wantMetric metricdata.Metrics
}{
{
name: "ObservableFloat64Counter",
register: func(t *testing.T, mtr metric.Meter) error {
ctr, err := mtr.Float64ObservableCounter("afcounter")
if err != nil {
return err
}
_, err = mtr.RegisterCallback([]instrument.Asynchronous{ctr}, func(ctx context.Context) error {
ctr.Observe(ctx, 1.0, attribute.String("foo", "bar"), attribute.Int("version", 1))
ctr.Observe(ctx, 2.0, attribute.String("foo", "bar"), attribute.Int("version", 2))
return nil
})
return err
},
wantMetric: metricdata.Metrics{
Name: "afcounter",
Data: metricdata.Sum[float64]{
DataPoints: []metricdata.DataPoint[float64]{
{
Attributes: attribute.NewSet(attribute.String("foo", "bar")),
Value: 2.0, // TODO (#3439): This should be 3.0.
},
},
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: true,
},
},
},
{
name: "ObservableFloat64UpDownCounter",
register: func(t *testing.T, mtr metric.Meter) error {
ctr, err := mtr.Float64ObservableUpDownCounter("afupdowncounter")
if err != nil {
return err
}
_, err = mtr.RegisterCallback([]instrument.Asynchronous{ctr}, func(ctx context.Context) error {
ctr.Observe(ctx, 1.0, attribute.String("foo", "bar"), attribute.Int("version", 1))
ctr.Observe(ctx, 2.0, attribute.String("foo", "bar"), attribute.Int("version", 2))
return nil
})
return err
},
wantMetric: metricdata.Metrics{
Name: "afupdowncounter",
Data: metricdata.Sum[float64]{
DataPoints: []metricdata.DataPoint[float64]{
{
Attributes: attribute.NewSet(attribute.String("foo", "bar")),
Value: 2.0, // TODO (#3439): This should be 3.0.
},
},
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: false,
},
},
},
{
name: "ObservableFloat64Gauge",
register: func(t *testing.T, mtr metric.Meter) error {
ctr, err := mtr.Float64ObservableGauge("afgauge")
if err != nil {
return err
}
_, err = mtr.RegisterCallback([]instrument.Asynchronous{ctr}, func(ctx context.Context) error {
ctr.Observe(ctx, 1.0, attribute.String("foo", "bar"), attribute.Int("version", 1))
ctr.Observe(ctx, 2.0, attribute.String("foo", "bar"), attribute.Int("version", 2))
return nil
})
return err
},
wantMetric: metricdata.Metrics{
Name: "afgauge",
Data: metricdata.Gauge[float64]{
DataPoints: []metricdata.DataPoint[float64]{
{
Attributes: attribute.NewSet(attribute.String("foo", "bar")),
Value: 2.0,
},
},
},
},
},
{
name: "ObservableInt64Counter",
register: func(t *testing.T, mtr metric.Meter) error {
ctr, err := mtr.Int64ObservableCounter("aicounter")
if err != nil {
return err
}
_, err = mtr.RegisterCallback([]instrument.Asynchronous{ctr}, func(ctx context.Context) error {
ctr.Observe(ctx, 10, attribute.String("foo", "bar"), attribute.Int("version", 1))
ctr.Observe(ctx, 20, attribute.String("foo", "bar"), attribute.Int("version", 2))
return nil
})
return err
},
wantMetric: metricdata.Metrics{
Name: "aicounter",
Data: metricdata.Sum[int64]{
DataPoints: []metricdata.DataPoint[int64]{
{
Attributes: attribute.NewSet(attribute.String("foo", "bar")),
Value: 20, // TODO (#3439): This should be 30.
},
},
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: true,
},
},
},
{
name: "ObservableInt64UpDownCounter",
register: func(t *testing.T, mtr metric.Meter) error {
ctr, err := mtr.Int64ObservableUpDownCounter("aiupdowncounter")
if err != nil {
return err
}
_, err = mtr.RegisterCallback([]instrument.Asynchronous{ctr}, func(ctx context.Context) error {
ctr.Observe(ctx, 10, attribute.String("foo", "bar"), attribute.Int("version", 1))
ctr.Observe(ctx, 20, attribute.String("foo", "bar"), attribute.Int("version", 2))
return nil
})
return err
},
wantMetric: metricdata.Metrics{
Name: "aiupdowncounter",
Data: metricdata.Sum[int64]{
DataPoints: []metricdata.DataPoint[int64]{
{
Attributes: attribute.NewSet(attribute.String("foo", "bar")),
Value: 20, // TODO (#3439): This should be 30.
},
},
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: false,
},
},
},
{
name: "ObservableInt64Gauge",
register: func(t *testing.T, mtr metric.Meter) error {
ctr, err := mtr.Int64ObservableGauge("aigauge")
if err != nil {
return err
}
_, err = mtr.RegisterCallback([]instrument.Asynchronous{ctr}, func(ctx context.Context) error {
ctr.Observe(ctx, 10, attribute.String("foo", "bar"), attribute.Int("version", 1))
ctr.Observe(ctx, 20, attribute.String("foo", "bar"), attribute.Int("version", 2))
return nil
})
return err
},
wantMetric: metricdata.Metrics{
Name: "aigauge",
Data: metricdata.Gauge[int64]{
DataPoints: []metricdata.DataPoint[int64]{
{
Attributes: attribute.NewSet(attribute.String("foo", "bar")),
Value: 20,
},
},
},
},
},
{
name: "SyncFloat64Counter",
register: func(t *testing.T, mtr metric.Meter) error {
ctr, err := mtr.Float64Counter("sfcounter")
if err != nil {
return err
}
ctr.Add(context.Background(), 1.0, attribute.String("foo", "bar"), attribute.Int("version", 1))
ctr.Add(context.Background(), 2.0, attribute.String("foo", "bar"), attribute.Int("version", 2))
return nil
},
wantMetric: metricdata.Metrics{
Name: "sfcounter",
Data: metricdata.Sum[float64]{
DataPoints: []metricdata.DataPoint[float64]{
{
Attributes: attribute.NewSet(attribute.String("foo", "bar")),
Value: 3.0,
},
},
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: true,
},
},
},
{
name: "SyncFloat64UpDownCounter",
register: func(t *testing.T, mtr metric.Meter) error {
ctr, err := mtr.Float64UpDownCounter("sfupdowncounter")
if err != nil {
return err
}
ctr.Add(context.Background(), 1.0, attribute.String("foo", "bar"), attribute.Int("version", 1))
ctr.Add(context.Background(), 2.0, attribute.String("foo", "bar"), attribute.Int("version", 2))
return nil
},
wantMetric: metricdata.Metrics{
Name: "sfupdowncounter",
Data: metricdata.Sum[float64]{
DataPoints: []metricdata.DataPoint[float64]{
{
Attributes: attribute.NewSet(attribute.String("foo", "bar")),
Value: 3.0,
},
},
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: false,
},
},
},
{
name: "SyncFloat64Histogram",
register: func(t *testing.T, mtr metric.Meter) error {
ctr, err := mtr.Float64Histogram("sfhistogram")
if err != nil {
return err
}
ctr.Record(context.Background(), 1.0, attribute.String("foo", "bar"), attribute.Int("version", 1))
ctr.Record(context.Background(), 2.0, attribute.String("foo", "bar"), attribute.Int("version", 2))
return nil
},
wantMetric: metricdata.Metrics{
Name: "sfhistogram",
Data: metricdata.Histogram{
DataPoints: []metricdata.HistogramDataPoint{
{
Attributes: attribute.NewSet(attribute.String("foo", "bar")),
Bounds: []float64{0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000},
BucketCounts: []uint64{0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Count: 2,
Min: &one,
Max: &two,
Sum: 3.0,
},
},
Temporality: metricdata.CumulativeTemporality,
},
},
},
{
name: "SyncInt64Counter",
register: func(t *testing.T, mtr metric.Meter) error {
ctr, err := mtr.Int64Counter("sicounter")
if err != nil {
return err
}
ctr.Add(context.Background(), 10, attribute.String("foo", "bar"), attribute.Int("version", 1))
ctr.Add(context.Background(), 20, attribute.String("foo", "bar"), attribute.Int("version", 2))
return nil
},
wantMetric: metricdata.Metrics{
Name: "sicounter",
Data: metricdata.Sum[int64]{
DataPoints: []metricdata.DataPoint[int64]{
{
Attributes: attribute.NewSet(attribute.String("foo", "bar")),
Value: 30,
},
},
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: true,
},
},
},
{
name: "SyncInt64UpDownCounter",
register: func(t *testing.T, mtr metric.Meter) error {
ctr, err := mtr.Int64UpDownCounter("siupdowncounter")
if err != nil {
return err
}
ctr.Add(context.Background(), 10, attribute.String("foo", "bar"), attribute.Int("version", 1))
ctr.Add(context.Background(), 20, attribute.String("foo", "bar"), attribute.Int("version", 2))
return nil
},
wantMetric: metricdata.Metrics{
Name: "siupdowncounter",
Data: metricdata.Sum[int64]{
DataPoints: []metricdata.DataPoint[int64]{
{
Attributes: attribute.NewSet(attribute.String("foo", "bar")),
Value: 30,
},
},
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: false,
},
},
},
{
name: "SyncInt64Histogram",
register: func(t *testing.T, mtr metric.Meter) error {
ctr, err := mtr.Int64Histogram("sihistogram")
if err != nil {
return err
}
ctr.Record(context.Background(), 1, attribute.String("foo", "bar"), attribute.Int("version", 1))
ctr.Record(context.Background(), 2, attribute.String("foo", "bar"), attribute.Int("version", 2))
return nil
},
wantMetric: metricdata.Metrics{
Name: "sihistogram",
Data: metricdata.Histogram{
DataPoints: []metricdata.HistogramDataPoint{
{
Attributes: attribute.NewSet(attribute.String("foo", "bar")),
Bounds: []float64{0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000},
BucketCounts: []uint64{0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Count: 2,
Min: &one,
Max: &two,
Sum: 3.0,
},
},
Temporality: metricdata.CumulativeTemporality,
},
},
},
}
for _, tt := range testcases {
t.Run(tt.name, func(t *testing.T) {
rdr := NewManualReader()
mtr := NewMeterProvider(
WithReader(rdr),
WithView(NewView(
Instrument{Name: "*"},
Stream{AttributeFilter: func(kv attribute.KeyValue) bool {
return kv.Key == attribute.Key("foo")
}},
)),
).Meter("TestAttributeFilter")
require.NoError(t, tt.register(t, mtr))
m, err := rdr.Collect(context.Background())
assert.NoError(t, err)
require.Len(t, m.ScopeMetrics, 1)
require.Len(t, m.ScopeMetrics[0].Metrics, 1)
metricdatatest.AssertEqual(t, tt.wantMetric, m.ScopeMetrics[0].Metrics[0], metricdatatest.IgnoreTimestamp())
})
}
}
var (
aiCounter instrument.Int64ObservableCounter
aiUpDownCounter instrument.Int64ObservableUpDownCounter
aiGauge instrument.Int64ObservableGauge
afCounter instrument.Float64ObservableCounter
afUpDownCounter instrument.Float64ObservableUpDownCounter
afGauge instrument.Float64ObservableGauge
siCounter instrument.Int64Counter
siUpDownCounter instrument.Int64UpDownCounter
siHistogram instrument.Int64Histogram
sfCounter instrument.Float64Counter
sfUpDownCounter instrument.Float64UpDownCounter
sfHistogram instrument.Float64Histogram
)
func BenchmarkInstrumentCreation(b *testing.B) {
provider := NewMeterProvider(WithReader(NewManualReader()))
meter := provider.Meter("BenchmarkInstrumentCreation")
b.ReportAllocs()
b.ResetTimer()
for n := 0; n < b.N; n++ {
aiCounter, _ = meter.Int64ObservableCounter("observable.int64.counter")
aiUpDownCounter, _ = meter.Int64ObservableUpDownCounter("observable.int64.up.down.counter")
aiGauge, _ = meter.Int64ObservableGauge("observable.int64.gauge")
afCounter, _ = meter.Float64ObservableCounter("observable.float64.counter")
afUpDownCounter, _ = meter.Float64ObservableUpDownCounter("observable.float64.up.down.counter")
afGauge, _ = meter.Float64ObservableGauge("observable.float64.gauge")
siCounter, _ = meter.Int64Counter("sync.int64.counter")
siUpDownCounter, _ = meter.Int64UpDownCounter("sync.int64.up.down.counter")
siHistogram, _ = meter.Int64Histogram("sync.int64.histogram")
sfCounter, _ = meter.Float64Counter("sync.float64.counter")
sfUpDownCounter, _ = meter.Float64UpDownCounter("sync.float64.up.down.counter")
sfHistogram, _ = meter.Float64Histogram("sync.float64.histogram")
}
}