You've already forked opentelemetry-go
							
							
				mirror of
				https://github.com/open-telemetry/opentelemetry-go.git
				synced 2025-10-31 00:07:40 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			144 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			144 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright The OpenTelemetry Authors
 | |
| // SPDX-License-Identifier: Apache-2.0
 | |
| 
 | |
| 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"
 | |
| )
 | |
| 
 | |
| // MeterProvider handles the creation and coordination of Meters. All Meters
 | |
| // created by a MeterProvider will be associated with the same Resource, have
 | |
| // the same Views applied to them, and have their produced metric telemetry
 | |
| // passed to the configured Readers.
 | |
| type MeterProvider struct {
 | |
| 	embedded.MeterProvider
 | |
| 
 | |
| 	pipes  pipelines
 | |
| 	meters cache[instrumentation.Scope, *meter]
 | |
| 
 | |
| 	forceFlush, shutdown func(context.Context) error
 | |
| 	stopped              atomic.Bool
 | |
| }
 | |
| 
 | |
| // Compile-time check MeterProvider implements metric.MeterProvider.
 | |
| var _ metric.MeterProvider = (*MeterProvider)(nil)
 | |
| 
 | |
| // NewMeterProvider returns a new and configured MeterProvider.
 | |
| //
 | |
| // By default, the returned MeterProvider is configured with the default
 | |
| // Resource and no Readers. Readers cannot be added after a MeterProvider is
 | |
| // created. This means the returned MeterProvider, one created with no
 | |
| // Readers, will perform no operations.
 | |
| func NewMeterProvider(options ...Option) *MeterProvider {
 | |
| 	conf := newConfig(options)
 | |
| 	flush, sdown := conf.readerSignals()
 | |
| 
 | |
| 	mp := &MeterProvider{
 | |
| 		pipes:      newPipelines(conf.res, conf.readers, conf.views),
 | |
| 		forceFlush: flush,
 | |
| 		shutdown:   sdown,
 | |
| 	}
 | |
| 	// Log after creation so all readers show correctly they are registered.
 | |
| 	global.Info("MeterProvider created",
 | |
| 		"Resource", conf.res,
 | |
| 		"Readers", conf.readers,
 | |
| 		"Views", len(conf.views),
 | |
| 	)
 | |
| 	return mp
 | |
| }
 | |
| 
 | |
| // Meter returns a Meter with the given name and configured with options.
 | |
| //
 | |
| // The name should be the name of the instrumentation scope creating
 | |
| // telemetry. This name may be the same as the instrumented code only if that
 | |
| // code provides built-in instrumentation.
 | |
| //
 | |
| // Calls to the Meter method after Shutdown has been called will return Meters
 | |
| // that perform no operations.
 | |
| //
 | |
| // This method is safe to call concurrently.
 | |
| func (mp *MeterProvider) Meter(name string, options ...metric.MeterOption) metric.Meter {
 | |
| 	if name == "" {
 | |
| 		global.Warn("Invalid Meter name.", "name", name)
 | |
| 	}
 | |
| 
 | |
| 	if mp.stopped.Load() {
 | |
| 		return noop.Meter{}
 | |
| 	}
 | |
| 
 | |
| 	c := metric.NewMeterConfig(options...)
 | |
| 	s := instrumentation.Scope{
 | |
| 		Name:      name,
 | |
| 		Version:   c.InstrumentationVersion(),
 | |
| 		SchemaURL: c.SchemaURL(),
 | |
| 	}
 | |
| 
 | |
| 	global.Info("Meter created",
 | |
| 		"Name", s.Name,
 | |
| 		"Version", s.Version,
 | |
| 		"SchemaURL", s.SchemaURL,
 | |
| 	)
 | |
| 
 | |
| 	return mp.meters.Lookup(s, func() *meter {
 | |
| 		return newMeter(s, mp.pipes)
 | |
| 	})
 | |
| }
 | |
| 
 | |
| // ForceFlush flushes all pending telemetry.
 | |
| //
 | |
| // This method honors the deadline or cancellation of ctx. An appropriate
 | |
| // error will be returned in these situations. There is no guaranteed that all
 | |
| // telemetry be flushed or all resources have been released in these
 | |
| // situations.
 | |
| //
 | |
| // ForceFlush calls ForceFlush(context.Context) error
 | |
| // on all Readers that implements this method.
 | |
| //
 | |
| // This method is safe to call concurrently.
 | |
| func (mp *MeterProvider) ForceFlush(ctx context.Context) error {
 | |
| 	if mp.forceFlush != nil {
 | |
| 		return mp.forceFlush(ctx)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Shutdown shuts down the MeterProvider flushing all pending telemetry and
 | |
| // releasing any held computational resources.
 | |
| //
 | |
| // This call is idempotent. The first call will perform all flush and
 | |
| // releasing operations. Subsequent calls will perform no action and will
 | |
| // return an error stating this.
 | |
| //
 | |
| // Measurements made by instruments from meters this MeterProvider created
 | |
| // will not be exported after Shutdown is called.
 | |
| //
 | |
| // This method honors the deadline or cancellation of ctx. An appropriate
 | |
| // error will be returned in these situations. There is no guaranteed that all
 | |
| // telemetry be flushed or all resources have been released in these
 | |
| // situations.
 | |
| //
 | |
| // 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)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 |