1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-11-27 22:49:15 +02:00

Add the synchronous gauge to the metric API and SDK (#5304)

Resolve #5225 

The specification has [added a synchronous gauge
instrument](https://github.com/open-telemetry/opentelemetry-specification/pull/3540).
That instrument has now been
[stabilized](https://github.com/open-telemetry/opentelemetry-specification/pull/4019),
and that stabilization is included in the [next
release](https://github.com/open-telemetry/opentelemetry-specification/pull/4034).

This adds the new synchronous gauge instrument to the metric API and all
implementation we publish.

This change will be a breaking change for any SDK developer. The
`embedded` package is updated to ensure our compatibility guarantees are
meet.

---------

Co-authored-by: David Ashpole <dashpole@google.com>
This commit is contained in:
Tyler Yahn
2024-05-16 09:56:40 -07:00
committed by GitHub
parent 166b3473dd
commit dafe137bbe
24 changed files with 416 additions and 12 deletions

View File

@@ -14,6 +14,9 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Add `RecordFactory` in `go.opentelemetry.io/otel/sdk/log/logtest` to facilitate testing the exporter and processor implementations. (#5258)
- Add example for `go.opentelemetry.io/otel/exporters/stdout/stdoutlog`. (#5242)
- The count of dropped records from the `BatchProcessor` in `go.opentelemetry.io/otel/sdk/log` is logged. (#5276)
- Add the synchronous gauge instrument to `go.opentelemetry.io/otel/metric`. (#5304)
- An `int64` or `float64` synchronous gauge instrument can now be created from a `Meter`.
- All implementations of the API (`go.opentelemetry.io/otel/metric/noop`, `go.opentelemetry.io/otel/sdk/metric`) are updated to support this instrument.
- Add logs to `go.opentelemetry.io/otel/example/dice`. (#5349)
### Changed

View File

@@ -281,6 +281,32 @@ func (i *sfHistogram) Record(ctx context.Context, x float64, opts ...metric.Reco
}
}
type sfGauge struct {
embedded.Float64Gauge
name string
opts []metric.Float64GaugeOption
delegate atomic.Value // metric.Float64Gauge
}
var _ metric.Float64Gauge = (*sfGauge)(nil)
func (i *sfGauge) setDelegate(m metric.Meter) {
ctr, err := m.Float64Gauge(i.name, i.opts...)
if err != nil {
GetErrorHandler().Handle(err)
return
}
i.delegate.Store(ctr)
}
func (i *sfGauge) Record(ctx context.Context, x float64, opts ...metric.RecordOption) {
if ctr := i.delegate.Load(); ctr != nil {
ctr.(metric.Float64Gauge).Record(ctx, x, opts...)
}
}
type siCounter struct {
embedded.Int64Counter
@@ -358,3 +384,29 @@ func (i *siHistogram) Record(ctx context.Context, x int64, opts ...metric.Record
ctr.(metric.Int64Histogram).Record(ctx, x, opts...)
}
}
type siGauge struct {
embedded.Int64Gauge
name string
opts []metric.Int64GaugeOption
delegate atomic.Value // metric.Int64Gauge
}
var _ metric.Int64Gauge = (*siGauge)(nil)
func (i *siGauge) setDelegate(m metric.Meter) {
ctr, err := m.Int64Gauge(i.name, i.opts...)
if err != nil {
GetErrorHandler().Handle(err)
return
}
i.delegate.Store(ctr)
}
func (i *siGauge) Record(ctx context.Context, x int64, opts ...metric.RecordOption) {
if ctr := i.delegate.Load(); ctr != nil {
ctr.(metric.Int64Gauge).Record(ctx, x, opts...)
}
}

View File

@@ -117,6 +117,12 @@ func TestSyncInstrumentSetDelegateConcurrentSafe(t *testing.T) {
f := func(v float64) { delegate.Record(context.Background(), v) }
testFloat64ConcurrentSafe(f, delegate.setDelegate)
})
t.Run("Gauge", func(t *testing.T) {
delegate := &sfGauge{}
f := func(v float64) { delegate.Record(context.Background(), v) }
testFloat64ConcurrentSafe(f, delegate.setDelegate)
})
})
// Int64 Instruments
@@ -139,6 +145,12 @@ func TestSyncInstrumentSetDelegateConcurrentSafe(t *testing.T) {
f := func(v int64) { delegate.Record(context.Background(), v) }
testInt64ConcurrentSafe(f, delegate.setDelegate)
})
t.Run("Gauge", func(t *testing.T) {
delegate := &siGauge{}
f := func(v int64) { delegate.Record(context.Background(), v) }
testInt64ConcurrentSafe(f, delegate.setDelegate)
})
})
}
@@ -149,6 +161,7 @@ type testCountingFloatInstrument struct {
embedded.Float64Counter
embedded.Float64UpDownCounter
embedded.Float64Histogram
embedded.Float64Gauge
embedded.Float64ObservableCounter
embedded.Float64ObservableUpDownCounter
embedded.Float64ObservableGauge
@@ -173,6 +186,7 @@ type testCountingIntInstrument struct {
embedded.Int64Counter
embedded.Int64UpDownCounter
embedded.Int64Histogram
embedded.Int64Gauge
embedded.Int64ObservableCounter
embedded.Int64ObservableUpDownCounter
embedded.Int64ObservableGauge

View File

@@ -164,6 +164,17 @@ func (m *meter) Int64Histogram(name string, options ...metric.Int64HistogramOpti
return i, nil
}
func (m *meter) Int64Gauge(name string, options ...metric.Int64GaugeOption) (metric.Int64Gauge, error) {
if del, ok := m.delegate.Load().(metric.Meter); ok {
return del.Int64Gauge(name, options...)
}
m.mtx.Lock()
defer m.mtx.Unlock()
i := &siGauge{name: name, opts: options}
m.instruments = append(m.instruments, i)
return i, nil
}
func (m *meter) Int64ObservableCounter(name string, options ...metric.Int64ObservableCounterOption) (metric.Int64ObservableCounter, error) {
if del, ok := m.delegate.Load().(metric.Meter); ok {
return del.Int64ObservableCounter(name, options...)
@@ -230,6 +241,17 @@ func (m *meter) Float64Histogram(name string, options ...metric.Float64Histogram
return i, nil
}
func (m *meter) Float64Gauge(name string, options ...metric.Float64GaugeOption) (metric.Float64Gauge, error) {
if del, ok := m.delegate.Load().(metric.Meter); ok {
return del.Float64Gauge(name, options...)
}
m.mtx.Lock()
defer m.mtx.Unlock()
i := &sfGauge{name: name, opts: options}
m.instruments = append(m.instruments, i)
return i, nil
}
func (m *meter) Float64ObservableCounter(name string, options ...metric.Float64ObservableCounterOption) (metric.Float64ObservableCounter, error) {
if del, ok := m.delegate.Load().(metric.Meter); ok {
return del.Float64ObservableCounter(name, options...)

View File

@@ -61,9 +61,11 @@ func TestMeterConcurrentSafe(t *testing.T) {
_, _ = mtr.Float64Counter(name)
_, _ = mtr.Float64UpDownCounter(name)
_, _ = mtr.Float64Histogram(name)
_, _ = mtr.Float64Gauge(name)
_, _ = mtr.Int64Counter(name)
_, _ = mtr.Int64UpDownCounter(name)
_, _ = mtr.Int64Histogram(name)
_, _ = mtr.Int64Gauge(name)
_, _ = mtr.RegisterCallback(zeroCallback)
if !once {
wg.Done()
@@ -142,6 +144,8 @@ func testSetupAllInstrumentTypes(t *testing.T, m metric.Meter) (metric.Float64Co
assert.NoError(t, err)
_, err = m.Float64Histogram("test_Sync_Histogram")
assert.NoError(t, err)
_, err = m.Float64Gauge("test_Sync_Gauge")
assert.NoError(t, err)
_, err = m.Int64Counter("test_Sync_Counter")
assert.NoError(t, err)
@@ -149,6 +153,8 @@ func testSetupAllInstrumentTypes(t *testing.T, m metric.Meter) (metric.Float64Co
assert.NoError(t, err)
_, err = m.Int64Histogram("test_Sync_Histogram")
assert.NoError(t, err)
_, err = m.Int64Gauge("test_Sync_Gauge")
assert.NoError(t, err)
return sfcounter, afcounter
}

View File

@@ -36,10 +36,12 @@ type testMeter struct {
sfCount int
sfUDCount int
sfHist int
sfGauge int
siCount int
siUDCount int
siHist int
siGauge int
callbacks []metric.Callback
}
@@ -59,6 +61,11 @@ func (m *testMeter) Int64Histogram(name string, options ...metric.Int64Histogram
return &testCountingIntInstrument{}, nil
}
func (m *testMeter) Int64Gauge(name string, options ...metric.Int64GaugeOption) (metric.Int64Gauge, error) {
m.siGauge++
return &testCountingIntInstrument{}, nil
}
func (m *testMeter) Int64ObservableCounter(name string, options ...metric.Int64ObservableCounterOption) (metric.Int64ObservableCounter, error) {
m.aiCount++
return &testCountingIntInstrument{}, nil
@@ -89,6 +96,11 @@ func (m *testMeter) Float64Histogram(name string, options ...metric.Float64Histo
return &testCountingFloatInstrument{}, nil
}
func (m *testMeter) Float64Gauge(name string, options ...metric.Float64GaugeOption) (metric.Float64Gauge, error) {
m.sfGauge++
return &testCountingFloatInstrument{}, nil
}
func (m *testMeter) Float64ObservableCounter(name string, options ...metric.Float64ObservableCounterOption) (metric.Float64ObservableCounter, error) {
m.afCount++
return &testCountingFloatInstrument{}, nil

View File

@@ -102,6 +102,16 @@ type Float64Counter interface{ float64Counter() }
// the API package).
type Float64Histogram interface{ float64Histogram() }
// Float64Gauge is embedded in [go.opentelemetry.io/otel/metric.Float64Gauge].
//
// Embed this interface in your implementation of the
// [go.opentelemetry.io/otel/metric.Float64Gauge] if you want users to
// experience a compilation error, signaling they need to update to your latest
// implementation, when the [go.opentelemetry.io/otel/metric.Float64Gauge]
// interface is extended (which is something that can happen without a major
// version bump of the API package).
type Float64Gauge interface{ float64Gauge() }
// Float64ObservableCounter is embedded in
// [go.opentelemetry.io/otel/metric.Float64ObservableCounter].
//
@@ -174,6 +184,16 @@ type Int64Counter interface{ int64Counter() }
// the API package).
type Int64Histogram interface{ int64Histogram() }
// Int64Gauge is embedded in [go.opentelemetry.io/otel/metric.Int64Gauge].
//
// Embed this interface in your implementation of the
// [go.opentelemetry.io/otel/metric.Int64Gauge] if you want users to experience
// a compilation error, signaling they need to update to your latest
// implementation, when the [go.opentelemetry.io/otel/metric.Int64Gauge]
// interface is extended (which is something that can happen without a major
// version bump of the API package).
type Int64Gauge interface{ int64Gauge() }
// Int64ObservableCounter is embedded in
// [go.opentelemetry.io/otel/metric.Int64ObservableCounter].
//

View File

@@ -16,6 +16,7 @@ type InstrumentOption interface {
Int64CounterOption
Int64UpDownCounterOption
Int64HistogramOption
Int64GaugeOption
Int64ObservableCounterOption
Int64ObservableUpDownCounterOption
Int64ObservableGaugeOption
@@ -23,6 +24,7 @@ type InstrumentOption interface {
Float64CounterOption
Float64UpDownCounterOption
Float64HistogramOption
Float64GaugeOption
Float64ObservableCounterOption
Float64ObservableUpDownCounterOption
Float64ObservableGaugeOption
@@ -51,6 +53,11 @@ func (o descOpt) applyFloat64Histogram(c Float64HistogramConfig) Float64Histogra
return c
}
func (o descOpt) applyFloat64Gauge(c Float64GaugeConfig) Float64GaugeConfig {
c.description = string(o)
return c
}
func (o descOpt) applyFloat64ObservableCounter(c Float64ObservableCounterConfig) Float64ObservableCounterConfig {
c.description = string(o)
return c
@@ -81,6 +88,11 @@ func (o descOpt) applyInt64Histogram(c Int64HistogramConfig) Int64HistogramConfi
return c
}
func (o descOpt) applyInt64Gauge(c Int64GaugeConfig) Int64GaugeConfig {
c.description = string(o)
return c
}
func (o descOpt) applyInt64ObservableCounter(c Int64ObservableCounterConfig) Int64ObservableCounterConfig {
c.description = string(o)
return c
@@ -116,6 +128,11 @@ func (o unitOpt) applyFloat64Histogram(c Float64HistogramConfig) Float64Histogra
return c
}
func (o unitOpt) applyFloat64Gauge(c Float64GaugeConfig) Float64GaugeConfig {
c.unit = string(o)
return c
}
func (o unitOpt) applyFloat64ObservableCounter(c Float64ObservableCounterConfig) Float64ObservableCounterConfig {
c.unit = string(o)
return c
@@ -146,6 +163,11 @@ func (o unitOpt) applyInt64Histogram(c Int64HistogramConfig) Int64HistogramConfi
return c
}
func (o unitOpt) applyInt64Gauge(c Int64GaugeConfig) Int64GaugeConfig {
c.unit = string(o)
return c
}
func (o unitOpt) applyInt64ObservableCounter(c Int64ObservableCounterConfig) Int64ObservableCounterConfig {
c.unit = string(o)
return c

View File

@@ -58,6 +58,10 @@ type Meter interface {
// synchronously record the distribution of int64 measurements during a
// computational operation.
Int64Histogram(name string, options ...Int64HistogramOption) (Int64Histogram, error)
// Int64Gauge returns a new Int64Gauge instrument identified by name and
// configured with options. The instrument is used to synchronously record
// instantaneous int64 measurements during a computational operation.
Int64Gauge(name string, options ...Int64GaugeOption) (Int64Gauge, error)
// Int64ObservableCounter returns a new Int64ObservableCounter identified
// by name and configured with options. The instrument is used to
// asynchronously record increasing int64 measurements once per a
@@ -104,6 +108,10 @@ type Meter interface {
// synchronously record the distribution of float64 measurements during a
// computational operation.
Float64Histogram(name string, options ...Float64HistogramOption) (Float64Histogram, error)
// Float64Gauge returns a new Float64Gauge instrument identified by name and
// configured with options. The instrument is used to synchronously record
// instantaneous float64 measurements during a computational operation.
Float64Gauge(name string, options ...Float64GaugeOption) (Float64Gauge, error)
// Float64ObservableCounter returns a new Float64ObservableCounter
// instrument identified by name and configured with options. The
// instrument is used to asynchronously record increasing float64

View File

@@ -32,6 +32,8 @@ var (
_ metric.Float64UpDownCounter = Float64UpDownCounter{}
_ metric.Int64Histogram = Int64Histogram{}
_ metric.Float64Histogram = Float64Histogram{}
_ metric.Int64Gauge = Int64Gauge{}
_ metric.Float64Gauge = Float64Gauge{}
_ metric.Int64ObservableCounter = Int64ObservableCounter{}
_ metric.Float64ObservableCounter = Float64ObservableCounter{}
_ metric.Int64ObservableGauge = Int64ObservableGauge{}
@@ -76,6 +78,12 @@ func (Meter) Int64Histogram(string, ...metric.Int64HistogramOption) (metric.Int6
return Int64Histogram{}, nil
}
// Int64Gauge returns a Gauge used to record int64 measurements that
// produces no telemetry.
func (Meter) Int64Gauge(string, ...metric.Int64GaugeOption) (metric.Int64Gauge, error) {
return Int64Gauge{}, nil
}
// Int64ObservableCounter returns an ObservableCounter used to record int64
// measurements that produces no telemetry.
func (Meter) Int64ObservableCounter(string, ...metric.Int64ObservableCounterOption) (metric.Int64ObservableCounter, error) {
@@ -112,6 +120,12 @@ func (Meter) Float64Histogram(string, ...metric.Float64HistogramOption) (metric.
return Float64Histogram{}, nil
}
// Float64Gauge returns a Gauge used to record float64 measurements that
// produces no telemetry.
func (Meter) Float64Gauge(string, ...metric.Float64GaugeOption) (metric.Float64Gauge, error) {
return Float64Gauge{}, nil
}
// Float64ObservableCounter returns an ObservableCounter used to record int64
// measurements that produces no telemetry.
func (Meter) Float64ObservableCounter(string, ...metric.Float64ObservableCounterOption) (metric.Float64ObservableCounter, error) {
@@ -197,6 +211,20 @@ type Float64Histogram struct{ embedded.Float64Histogram }
// Record performs no operation.
func (Float64Histogram) Record(context.Context, float64, ...metric.RecordOption) {}
// Int64Gauge is an OpenTelemetry Gauge used to record instantaneous int64
// measurements. It produces no telemetry.
type Int64Gauge struct{ embedded.Int64Gauge }
// Record performs no operation.
func (Int64Gauge) Record(context.Context, int64, ...metric.RecordOption) {}
// Float64Gauge is an OpenTelemetry Gauge used to record instantaneous float64
// measurements. It produces no telemetry.
type Float64Gauge struct{ embedded.Float64Gauge }
// Record performs no operation.
func (Float64Gauge) Record(context.Context, float64, ...metric.RecordOption) {}
// Int64ObservableCounter is an OpenTelemetry ObservableCounter used to record
// int64 measurements. It produces no telemetry.
type Int64ObservableCounter struct {

View File

@@ -55,6 +55,14 @@ func TestImplementationNoPanics(t *testing.T) {
reflect.ValueOf(Float64Histogram{}),
reflect.TypeOf((*metric.Float64Histogram)(nil)).Elem(),
))
t.Run("Int64Gauge", assertAllExportedMethodNoPanic(
reflect.ValueOf(Int64Gauge{}),
reflect.TypeOf((*metric.Int64Gauge)(nil)).Elem(),
))
t.Run("Float64Gauge", assertAllExportedMethodNoPanic(
reflect.ValueOf(Float64Gauge{}),
reflect.TypeOf((*metric.Float64Gauge)(nil)).Elem(),
))
t.Run("Int64ObservableCounter", assertAllExportedMethodNoPanic(
reflect.ValueOf(Int64ObservableCounter{}),
reflect.TypeOf((*metric.Int64ObservableCounter)(nil)).Elem(),

View File

@@ -172,3 +172,55 @@ func (c Float64HistogramConfig) ExplicitBucketBoundaries() []float64 {
type Float64HistogramOption interface {
applyFloat64Histogram(Float64HistogramConfig) Float64HistogramConfig
}
// Float64Gauge is an instrument that records instantaneous float64 values.
//
// Warning: Methods may be added to this interface in minor releases. See
// package documentation on API implementation for information on how to set
// default behavior for unimplemented methods.
type Float64Gauge interface {
// Users of the interface can ignore this. This embedded type is only used
// by implementations of this interface. See the "API Implementations"
// section of the package documentation for more information.
embedded.Float64Gauge
// Record records the instantaneous value.
//
// Use the WithAttributeSet (or, if performance is not a concern,
// the WithAttributes) option to include measurement attributes.
Record(ctx context.Context, value float64, options ...RecordOption)
}
// Float64GaugeConfig contains options for synchronous gauge instruments that
// record float64 values.
type Float64GaugeConfig struct {
description string
unit string
}
// NewFloat64GaugeConfig returns a new [Float64GaugeConfig] with all opts
// applied.
func NewFloat64GaugeConfig(opts ...Float64GaugeOption) Float64GaugeConfig {
var config Float64GaugeConfig
for _, o := range opts {
config = o.applyFloat64Gauge(config)
}
return config
}
// Description returns the configured description.
func (c Float64GaugeConfig) Description() string {
return c.description
}
// Unit returns the configured unit.
func (c Float64GaugeConfig) Unit() string {
return c.unit
}
// Float64GaugeOption applies options to a [Float64GaugeConfig]. See
// [InstrumentOption] for other options that can be used as a
// Float64GaugeOption.
type Float64GaugeOption interface {
applyFloat64Gauge(Float64GaugeConfig) Float64GaugeConfig
}

View File

@@ -34,6 +34,10 @@ func TestFloat64Configuration(t *testing.T) {
t.Run("Float64Histogram", run(
NewFloat64HistogramConfig(WithDescription(desc), WithUnit(uBytes)),
))
t.Run("Float64Gauge", run(
NewFloat64GaugeConfig(WithDescription(desc), WithUnit(uBytes)),
))
}
type float64Config interface {

View File

@@ -172,3 +172,55 @@ func (c Int64HistogramConfig) ExplicitBucketBoundaries() []float64 {
type Int64HistogramOption interface {
applyInt64Histogram(Int64HistogramConfig) Int64HistogramConfig
}
// Int64Gauge is an instrument that records instantaneous int64 values.
//
// Warning: Methods may be added to this interface in minor releases. See
// package documentation on API implementation for information on how to set
// default behavior for unimplemented methods.
type Int64Gauge interface {
// Users of the interface can ignore this. This embedded type is only used
// by implementations of this interface. See the "API Implementations"
// section of the package documentation for more information.
embedded.Int64Gauge
// Record records the instantaneous value.
//
// Use the WithAttributeSet (or, if performance is not a concern,
// the WithAttributes) option to include measurement attributes.
Record(ctx context.Context, value int64, options ...RecordOption)
}
// Int64GaugeConfig contains options for synchronous gauge instruments that
// record int64 values.
type Int64GaugeConfig struct {
description string
unit string
}
// NewInt64GaugeConfig returns a new [Int64GaugeConfig] with all opts
// applied.
func NewInt64GaugeConfig(opts ...Int64GaugeOption) Int64GaugeConfig {
var config Int64GaugeConfig
for _, o := range opts {
config = o.applyInt64Gauge(config)
}
return config
}
// Description returns the configured description.
func (c Int64GaugeConfig) Description() string {
return c.description
}
// Unit returns the configured unit.
func (c Int64GaugeConfig) Unit() string {
return c.unit
}
// Int64GaugeOption applies options to a [Int64GaugeConfig]. See
// [InstrumentOption] for other options that can be used as a
// Int64GaugeOption.
type Int64GaugeOption interface {
applyInt64Gauge(Int64GaugeConfig) Int64GaugeConfig
}

View File

@@ -34,6 +34,10 @@ func TestInt64Configuration(t *testing.T) {
t.Run("Int64Histogram", run(
NewInt64HistogramConfig(WithDescription(desc), WithUnit(uBytes)),
))
t.Run("Int64Gauge", run(
NewInt64GaugeConfig(WithDescription(desc), WithUnit(uBytes)),
))
}
type int64Config interface {

View File

@@ -42,6 +42,10 @@ const (
// distribution of values synchronously with the code path they are
// measuring.
InstrumentKindHistogram
// InstrumentKindGauge identifies a group of instruments that record
// instantaneous values synchronously with the code path they are
// measuring.
InstrumentKindGauge
// InstrumentKindObservableCounter identifies a group of instruments that
// record increasing values in an asynchronous callback.
InstrumentKindObservableCounter
@@ -175,12 +179,14 @@ type int64Inst struct {
embedded.Int64Counter
embedded.Int64UpDownCounter
embedded.Int64Histogram
embedded.Int64Gauge
}
var (
_ metric.Int64Counter = (*int64Inst)(nil)
_ metric.Int64UpDownCounter = (*int64Inst)(nil)
_ metric.Int64Histogram = (*int64Inst)(nil)
_ metric.Int64Gauge = (*int64Inst)(nil)
)
func (i *int64Inst) Add(ctx context.Context, val int64, opts ...metric.AddOption) {
@@ -205,12 +211,14 @@ type float64Inst struct {
embedded.Float64Counter
embedded.Float64UpDownCounter
embedded.Float64Histogram
embedded.Float64Gauge
}
var (
_ metric.Float64Counter = (*float64Inst)(nil)
_ metric.Float64UpDownCounter = (*float64Inst)(nil)
_ metric.Float64Histogram = (*float64Inst)(nil)
_ metric.Float64Gauge = (*float64Inst)(nil)
)
func (i *float64Inst) Add(ctx context.Context, val float64, opts ...metric.AddOption) {

View File

@@ -25,7 +25,12 @@ func BenchmarkInstrument(b *testing.B) {
build := aggregate.Builder[int64]{}
var meas []aggregate.Measure[int64]
in, _ := build.PrecomputedLastValue()
build.Temporality = metricdata.CumulativeTemporality
in, _ := build.LastValue()
meas = append(meas, in)
build.Temporality = metricdata.DeltaTemporality
in, _ = build.LastValue()
meas = append(meas, in)
build.Temporality = metricdata.CumulativeTemporality

View File

@@ -12,14 +12,15 @@ func _() {
_ = x[InstrumentKindCounter-1]
_ = x[InstrumentKindUpDownCounter-2]
_ = x[InstrumentKindHistogram-3]
_ = x[InstrumentKindObservableCounter-4]
_ = x[InstrumentKindObservableUpDownCounter-5]
_ = x[InstrumentKindObservableGauge-6]
_ = x[InstrumentKindGauge-4]
_ = x[InstrumentKindObservableCounter-5]
_ = x[InstrumentKindObservableUpDownCounter-6]
_ = x[InstrumentKindObservableGauge-7]
}
const _InstrumentKind_name = "instrumentKindUndefinedCounterUpDownCounterHistogramObservableCounterObservableUpDownCounterObservableGauge"
const _InstrumentKind_name = "instrumentKindUndefinedCounterUpDownCounterHistogramGaugeObservableCounterObservableUpDownCounterObservableGauge"
var _InstrumentKind_index = [...]uint8{0, 23, 30, 43, 52, 69, 92, 107}
var _InstrumentKind_index = [...]uint8{0, 23, 30, 43, 52, 57, 74, 97, 112}
func (i InstrumentKind) String() string {
if i >= InstrumentKind(len(_InstrumentKind_index)-1) {

View File

@@ -108,6 +108,21 @@ func (m *meter) Int64Histogram(name string, options ...metric.Int64HistogramOpti
return i, validateInstrumentName(name)
}
// Int64Gauge returns a new instrument identified by name and configured
// with options. The instrument is used to synchronously record the
// distribution of int64 measurements during a computational operation.
func (m *meter) Int64Gauge(name string, options ...metric.Int64GaugeOption) (metric.Int64Gauge, error) {
cfg := metric.NewInt64GaugeConfig(options...)
const kind = InstrumentKindGauge
p := int64InstProvider{m}
i, err := p.lookup(kind, name, cfg.Description(), cfg.Unit())
if err != nil {
return i, err
}
return i, validateInstrumentName(name)
}
// int64ObservableInstrument returns a new observable identified by the Instrument.
// It registers callbacks for each reader's pipeline.
func (m *meter) int64ObservableInstrument(id Instrument, callbacks []metric.Int64Callback) (int64Observable, error) {
@@ -242,6 +257,21 @@ func (m *meter) Float64Histogram(name string, options ...metric.Float64Histogram
return i, validateInstrumentName(name)
}
// Float64Gauge returns a new instrument identified by name and configured
// with options. The instrument is used to synchronously record the
// distribution of float64 measurements during a computational operation.
func (m *meter) Float64Gauge(name string, options ...metric.Float64GaugeOption) (metric.Float64Gauge, error) {
cfg := metric.NewFloat64GaugeConfig(options...)
const kind = InstrumentKindGauge
p := float64InstProvider{m}
i, err := p.lookup(kind, name, cfg.Description(), cfg.Unit())
if err != nil {
return i, err
}
return i, validateInstrumentName(name)
}
// float64ObservableInstrument returns a new observable identified by the Instrument.
// It registers callbacks for each reader's pipeline.
func (m *meter) float64ObservableInstrument(id Instrument, callbacks []metric.Float64Callback) (float64Observable, error) {

View File

@@ -447,10 +447,12 @@ func (i *inserter[N]) aggregateFunc(b aggregate.Builder[N], agg Aggregation, kin
case AggregationDrop:
// Return nil in and out to signify the drop aggregator.
case AggregationLastValue:
if kind == InstrumentKindObservableGauge {
switch kind {
case InstrumentKindGauge:
meas, comp = b.LastValue()
case InstrumentKindObservableGauge:
meas, comp = b.PrecomputedLastValue()
}
// TODO (#5304): Support synchronous gauges.
case AggregationSum:
switch kind {
case InstrumentKindObservableCounter:
@@ -467,7 +469,7 @@ func (i *inserter[N]) aggregateFunc(b aggregate.Builder[N], agg Aggregation, kin
case AggregationExplicitBucketHistogram:
var noSum bool
switch kind {
case InstrumentKindUpDownCounter, InstrumentKindObservableUpDownCounter, InstrumentKindObservableGauge:
case InstrumentKindUpDownCounter, InstrumentKindObservableUpDownCounter, InstrumentKindObservableGauge, InstrumentKindGauge:
// The sum should not be collected for any instrument that can make
// negative measurements:
// https://github.com/open-telemetry/opentelemetry-specification/blob/v1.21.0/specification/metrics/sdk.md#histogram-aggregations
@@ -477,7 +479,7 @@ func (i *inserter[N]) aggregateFunc(b aggregate.Builder[N], agg Aggregation, kin
case AggregationBase2ExponentialHistogram:
var noSum bool
switch kind {
case InstrumentKindUpDownCounter, InstrumentKindObservableUpDownCounter, InstrumentKindObservableGauge:
case InstrumentKindUpDownCounter, InstrumentKindObservableUpDownCounter, InstrumentKindObservableGauge, InstrumentKindGauge:
// The sum should not be collected for any instrument that can make
// negative measurements:
// https://github.com/open-telemetry/opentelemetry-specification/blob/v1.21.0/specification/metrics/sdk.md#histogram-aggregations
@@ -500,6 +502,7 @@ func (i *inserter[N]) aggregateFunc(b aggregate.Builder[N], agg Aggregation, kin
// | Counter | ✓ | | ✓ | ✓ | ✓ |
// | UpDownCounter | ✓ | | ✓ | ✓ | ✓ |
// | Histogram | ✓ | | ✓ | ✓ | ✓ |
// | Gauge | ✓ | ✓ | | ✓ | ✓ |
// | Observable Counter | ✓ | | ✓ | ✓ | ✓ |
// | Observable UpDownCounter | ✓ | | ✓ | ✓ | ✓ |
// | Observable Gauge | ✓ | ✓ | | ✓ | ✓ |.
@@ -512,6 +515,7 @@ func isAggregatorCompatible(kind InstrumentKind, agg Aggregation) error {
case InstrumentKindCounter,
InstrumentKindUpDownCounter,
InstrumentKindHistogram,
InstrumentKindGauge,
InstrumentKindObservableCounter,
InstrumentKindObservableUpDownCounter,
InstrumentKindObservableGauge:
@@ -529,7 +533,8 @@ func isAggregatorCompatible(kind InstrumentKind, agg Aggregation) error {
return errIncompatibleAggregation
}
case AggregationLastValue:
if kind == InstrumentKindObservableGauge {
switch kind {
case InstrumentKindObservableGauge, InstrumentKindGauge:
return nil
}
// TODO: review need for aggregation check after

View File

@@ -149,6 +149,7 @@ func testCreateAggregators[N int64 | float64](t *testing.T) {
{Name: "foo", Kind: InstrumentKindCounter},
{Name: "foo", Kind: InstrumentKindUpDownCounter},
{Name: "foo", Kind: InstrumentKindHistogram},
{Name: "foo", Kind: InstrumentKindGauge},
{Name: "foo", Kind: InstrumentKindObservableCounter},
{Name: "foo", Kind: InstrumentKindObservableUpDownCounter},
{Name: "foo", Kind: InstrumentKindObservableGauge},
@@ -184,6 +185,12 @@ func testCreateAggregators[N int64 | float64](t *testing.T) {
inst: instruments[InstrumentKindHistogram],
validate: assertHist[N](metricdata.DeltaTemporality),
},
{
name: "Default/Delta/Gauge",
reader: NewManualReader(WithTemporalitySelector(deltaTemporalitySelector)),
inst: instruments[InstrumentKindGauge],
validate: assertLastValue[N],
},
{
name: "Default/Delta/PrecomputedSum/Monotonic",
reader: NewManualReader(WithTemporalitySelector(deltaTemporalitySelector)),
@@ -220,6 +227,12 @@ func testCreateAggregators[N int64 | float64](t *testing.T) {
inst: instruments[InstrumentKindHistogram],
validate: assertHist[N](metricdata.CumulativeTemporality),
},
{
name: "Default/Cumulative/Gauge",
reader: NewManualReader(),
inst: instruments[InstrumentKindGauge],
validate: assertLastValue[N],
},
{
name: "Default/Cumulative/PrecomputedSum/Monotonic",
reader: NewManualReader(),
@@ -307,6 +320,12 @@ func testCreateAggregators[N int64 | float64](t *testing.T) {
inst: instruments[InstrumentKindHistogram],
validate: assertHist[N](metricdata.CumulativeTemporality),
},
{
name: "Reader/Default/Cumulative/Gauge",
reader: NewManualReader(WithAggregationSelector(func(ik InstrumentKind) Aggregation { return AggregationDefault{} })),
inst: instruments[InstrumentKindGauge],
validate: assertLastValue[N],
},
{
name: "Reader/Default/Cumulative/PrecomputedSum/Monotonic",
reader: NewManualReader(WithAggregationSelector(func(ik InstrumentKind) Aggregation { return AggregationDefault{} })),
@@ -699,6 +718,32 @@ func TestIsAggregatorCompatible(t *testing.T) {
kind: InstrumentKindHistogram,
agg: AggregationBase2ExponentialHistogram{},
},
{
name: "SyncGauge and Drop",
kind: InstrumentKindGauge,
agg: AggregationDrop{},
},
{
name: "SyncGauge and LastValue",
kind: InstrumentKindGauge,
agg: AggregationLastValue{},
},
{
name: "SyncGauge and Sum",
kind: InstrumentKindGauge,
agg: AggregationSum{},
want: errIncompatibleAggregation,
},
{
name: "SyncGauge and ExplicitBucketHistogram",
kind: InstrumentKindGauge,
agg: AggregationExplicitBucketHistogram{},
},
{
name: "SyncGauge and ExponentialHistogram",
kind: InstrumentKindGauge,
agg: AggregationBase2ExponentialHistogram{},
},
{
name: "ObservableCounter and Drop",
kind: InstrumentKindObservableCounter,

View File

@@ -148,7 +148,7 @@ func DefaultAggregationSelector(ik InstrumentKind) Aggregation {
switch ik {
case InstrumentKindCounter, InstrumentKindUpDownCounter, InstrumentKindObservableCounter, InstrumentKindObservableUpDownCounter:
return AggregationSum{}
case InstrumentKindObservableGauge:
case InstrumentKindObservableGauge, InstrumentKindGauge:
return AggregationLastValue{}
case InstrumentKindHistogram:
return AggregationExplicitBucketHistogram{

View File

@@ -300,6 +300,7 @@ func TestDefaultAggregationSelector(t *testing.T) {
InstrumentKindCounter,
InstrumentKindUpDownCounter,
InstrumentKindHistogram,
InstrumentKindGauge,
InstrumentKindObservableCounter,
InstrumentKindObservableUpDownCounter,
InstrumentKindObservableGauge,
@@ -317,6 +318,7 @@ func TestDefaultTemporalitySelector(t *testing.T) {
InstrumentKindCounter,
InstrumentKindUpDownCounter,
InstrumentKindHistogram,
InstrumentKindGauge,
InstrumentKindObservableCounter,
InstrumentKindObservableUpDownCounter,
InstrumentKindObservableGauge,

View File

@@ -185,6 +185,7 @@ func TestNewViewMatch(t *testing.T) {
{},
{Kind: InstrumentKindUpDownCounter},
{Kind: InstrumentKindHistogram},
{Kind: InstrumentKindGauge},
{Kind: InstrumentKindObservableCounter},
{Kind: InstrumentKindObservableUpDownCounter},
{Kind: InstrumentKindObservableGauge},