1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-01-03 22:52:30 +02:00

Return noop meters once the provider has been shutdown (#4154)

This commit is contained in:
Damien Mathieu 2023-06-05 09:51:21 +02:00 committed by GitHub
parent b4faa3dfdb
commit be82610b44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 44 additions and 0 deletions

View File

@ -28,6 +28,7 @@ See our [versioning policy](VERSIONING.md) for more information about these stab
### Changed
- Use `strings.Cut()` instead of `string.SplitN()` for better readability and memory use. (#4049)
- `MeterProvider` returns noop meters once it has been shutdown. (#4154)
### Removed

View File

@ -16,10 +16,12 @@ package metric // import "go.opentelemetry.io/otel/sdk/metric"
import (
"context"
"sync/atomic"
"go.opentelemetry.io/otel/internal/global"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/embedded"
"go.opentelemetry.io/otel/metric/noop"
"go.opentelemetry.io/otel/sdk/instrumentation"
)
@ -34,6 +36,7 @@ type MeterProvider struct {
meters cache[instrumentation.Scope, *meter]
forceFlush, shutdown func(context.Context) error
stopped atomic.Bool
}
// Compile-time check MeterProvider implements metric.MeterProvider.
@ -70,6 +73,10 @@ func (mp *MeterProvider) Meter(name string, options ...metric.MeterOption) metri
global.Warn("Invalid Meter name.", "name", name)
}
if mp.stopped.Load() {
return noop.Meter{}
}
c := metric.NewMeterConfig(options...)
s := instrumentation.Scope{
Name: name,
@ -113,6 +120,15 @@ func (mp *MeterProvider) ForceFlush(ctx context.Context) error {
//
// This method is safe to call concurrently.
func (mp *MeterProvider) Shutdown(ctx context.Context) error {
// Even though it may seem like there is a synchronization issue between the
// call to `Store` and checking `shutdown`, the Go concurrency model ensures
// that is not the case, as all the atomic operations executed in a program
// behave as though executed in some sequentially consistent order. This
// definition provides the same semantics as C++'s sequentially consistent
// atomics and Java's volatile variables.
// See https://go.dev/ref/mem#atomic and https://pkg.go.dev/sync/atomic.
mp.stopped.Store(true)
if mp.shutdown != nil {
return mp.shutdown(ctx)
}

View File

@ -22,8 +22,10 @@ import (
"github.com/go-logr/logr/funcr"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/metric/noop"
)
func TestMeterConcurrentSafe(t *testing.T) {
@ -57,6 +59,17 @@ func TestShutdownConcurrentSafe(t *testing.T) {
_ = mp.Shutdown(context.Background())
}
func TestMeterAndShutdownConcurrentSafe(t *testing.T) {
const name = "TestMeterAndShutdownConcurrentSafe meter"
mp := NewMeterProvider()
go func() {
_ = mp.Shutdown(context.Background())
}()
_ = mp.Meter(name)
}
func TestMeterDoesNotPanicForEmptyMeterProvider(t *testing.T) {
mp := MeterProvider{}
assert.NotPanics(t, func() { _ = mp.Meter("") })
@ -93,3 +106,17 @@ func TestEmptyMeterName(t *testing.T) {
assert.Contains(t, buf.String(), `"level"=1 "msg"="Invalid Meter name." "name"=""`)
}
func TestMeterProviderReturnsNoopMeterAfterShutdown(t *testing.T) {
mp := NewMeterProvider()
m := mp.Meter("")
_, ok := m.(noop.Meter)
assert.False(t, ok, "Meter from running MeterProvider is NoOp")
require.NoError(t, mp.Shutdown(context.Background()))
m = mp.Meter("")
_, ok = m.(noop.Meter)
assert.Truef(t, ok, "Meter from shutdown MeterProvider is not NoOp: %T", m)
}