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 internal

import (
	
	
	
	

	
	
	
)
This file contains the forwarding implementation of metric.Provider used as the default global instance. Metric events using instruments provided by this implementation are no-ops until the first Meter implementation is set as the global provider. The implementation here uses Mutexes to maintain a list of active Meters in the Provider and Instruments in each Meter, under the assumption that these interfaces are not performance-critical. We have the invariant that setDelegate() will be called before a new metric.Provider implementation is registered as the global provider. Mutexes in the Provider and Meters ensure that each instrument has a delegate before the global provider is set. Bound instrument operations are implemented by delegating to the instrument after it is registered, with a sync.Once initializer to protect against races with Release(). Metric uniqueness checking is implemented by calling the exported methods of the api/metric/registry package.

type meterKey struct {
	Name, Version string
}

type meterProvider struct {
	delegate metric.Provider
lock protects `delegate` and `meters`.
meters maintains a unique entry for every named Meter that has been registered through the global instance.
	meters map[meterKey]*meterEntry
}

type meterImpl struct {
	delegate unsafe.Pointer // (*metric.MeterImpl)

	lock       sync.Mutex
	syncInsts  []*syncImpl
	asyncInsts []*asyncImpl
}

type meterEntry struct {
	unique metric.MeterImpl
	impl   meterImpl
}

type instrument struct {
	descriptor metric.Descriptor
}

type syncImpl struct {
	delegate unsafe.Pointer // (*metric.SyncImpl)

	instrument
}

type asyncImpl struct {
	delegate unsafe.Pointer // (*metric.AsyncImpl)

	instrument

	runner metric.AsyncRunner
}
SyncImpler is implemented by all of the sync metric instruments.
type SyncImpler interface {
	SyncImpl() metric.SyncImpl
}
AsyncImpler is implemented by all of the async metric instruments.
type AsyncImpler interface {
	AsyncImpl() metric.AsyncImpl
}

type syncHandle struct {
	delegate unsafe.Pointer // (*metric.HandleImpl)

	inst   *syncImpl
	labels []label.KeyValue

	initialize sync.Once
}

var _ metric.Provider = &meterProvider{}
var _ metric.MeterImpl = &meterImpl{}
var _ metric.InstrumentImpl = &syncImpl{}
var _ metric.BoundSyncImpl = &syncHandle{}
var _ metric.AsyncImpl = &asyncImpl{}

func ( *instrument) () metric.Descriptor {
	return .descriptor
}
Provider interface and delegation

func () *meterProvider {
	return &meterProvider{
		meters: map[meterKey]*meterEntry{},
	}
}

func ( *meterProvider) ( metric.Provider) {
	.lock.Lock()
	defer .lock.Unlock()

	.delegate = 
	for ,  := range .meters {
		.impl.setDelegate(.Name, .Version, )
	}
	.meters = nil
}

func ( *meterProvider) ( string,  ...metric.MeterOption) metric.Meter {
	.lock.Lock()
	defer .lock.Unlock()

	if .delegate != nil {
		return .delegate.Meter(, ...)
	}

	 := meterKey{
		Name:    ,
		Version: metric.ConfigureMeter().InstrumentationVersion,
	}
	,  := .meters[]
	if ! {
		 = &meterEntry{}
		.unique = registry.NewUniqueInstrumentMeterImpl(&.impl)
		.meters[] = 

	}
	return metric.WrapMeterImpl(.unique, .Name, metric.WithInstrumentationVersion(.Version))
}
Meter interface and delegation

func ( *meterImpl) (,  string,  metric.Provider) {
	.lock.Lock()
	defer .lock.Unlock()

	 := new(metric.MeterImpl)
	* = .Meter(, metric.WithInstrumentationVersion()).MeterImpl()
	.delegate = unsafe.Pointer()

	for ,  := range .syncInsts {
		.setDelegate(*)
	}
	.syncInsts = nil
	for ,  := range .asyncInsts {
		.setDelegate(*)
	}
	.asyncInsts = nil
}

func ( *meterImpl) ( metric.Descriptor) (metric.SyncImpl, error) {
	.lock.Lock()
	defer .lock.Unlock()

	if  := (*metric.MeterImpl)(atomic.LoadPointer(&.delegate));  != nil {
		return (*).NewSyncInstrument()
	}

	 := &syncImpl{
		instrument: instrument{
			descriptor: ,
		},
	}
	.syncInsts = append(.syncInsts, )
	return , nil
}
Synchronous delegation

func ( *syncImpl) ( metric.MeterImpl) {
	 := new(metric.SyncImpl)

	var  error
	*,  = .NewSyncInstrument(.descriptor)

TODO: There is no standard way to deliver this error to the user. See https://github.com/open-telemetry/opentelemetry-go/issues/514 Note that the default SDK will not generate any errors yet, this is only for added safety.
		panic()
	}

	atomic.StorePointer(&.delegate, unsafe.Pointer())
}

func ( *syncImpl) () interface{} {
	if  := (*metric.SyncImpl)(atomic.LoadPointer(&.delegate));  != nil {
		return (*).Implementation()
	}
	return 
}

func ( *syncImpl) ( []label.KeyValue) metric.BoundSyncImpl {
	if  := (*metric.SyncImpl)(atomic.LoadPointer(&.delegate));  != nil {
		return (*).Bind()
	}
	return &syncHandle{
		inst:   ,
		labels: ,
	}
}

func ( *syncHandle) () {
	.initialize.Do(func() {})

	 := (*metric.BoundSyncImpl)(atomic.LoadPointer(&.delegate))

	if  == nil {
		return
	}

	(*).Unbind()
}
Async delegation

func ( *meterImpl) (
	 metric.Descriptor,
	 metric.AsyncRunner,
) (metric.AsyncImpl, error) {

	.lock.Lock()
	defer .lock.Unlock()

	if  := (*metric.MeterImpl)(atomic.LoadPointer(&.delegate));  != nil {
		return (*).NewAsyncInstrument(, )
	}

	 := &asyncImpl{
		instrument: instrument{
			descriptor: ,
		},
		runner: ,
	}
	.asyncInsts = append(.asyncInsts, )
	return , nil
}

func ( *asyncImpl) () interface{} {
	if  := (*metric.AsyncImpl)(atomic.LoadPointer(&.delegate));  != nil {
		return (*).Implementation()
	}
	return 
}

func ( *asyncImpl) ( metric.MeterImpl) {
	 := new(metric.AsyncImpl)

	var  error
	*,  = .NewAsyncInstrument(.descriptor, .runner)

TODO: There is no standard way to deliver this error to the user. See https://github.com/open-telemetry/opentelemetry-go/issues/514 Note that the default SDK will not generate any errors yet, this is only for added safety.
		panic()
	}

	atomic.StorePointer(&.delegate, unsafe.Pointer())
}
Metric updates

func ( *meterImpl) ( context.Context,  []label.KeyValue,  ...metric.Measurement) {
	if  := (*metric.MeterImpl)(atomic.LoadPointer(&.delegate));  != nil {
		(*).RecordBatch(, , ...)
	}
}

func ( *syncImpl) ( context.Context,  metric.Number,  []label.KeyValue) {
	if  := (*metric.SyncImpl)(atomic.LoadPointer(&.delegate));  != nil {
		(*).RecordOne(, , )
	}
}
Bound instrument initialization

func ( *syncHandle) ( context.Context,  metric.Number) {
	 := (*metric.SyncImpl)(atomic.LoadPointer(&.inst.delegate))
	if  == nil {
		return
	}
	var  *metric.BoundSyncImpl
	.initialize.Do(func() {
		 = new(metric.BoundSyncImpl)
		* = (*).Bind(.labels)
		atomic.StorePointer(&.delegate, unsafe.Pointer())
	})
	if  == nil {
		 = (*metric.BoundSyncImpl)(atomic.LoadPointer(&.delegate))
This may still be nil if instrument was created and bound without a delegate, then the instrument was set to have a delegate and unbound.
	if  == nil {
		return
	}
	(*).RecordOne(, )
}

func () map[string]uintptr {
	return map[string]uintptr{
		"meterProvider.delegate": unsafe.Offsetof(meterProvider{}.delegate),
		"meterImpl.delegate":     unsafe.Offsetof(meterImpl{}.delegate),
		"syncImpl.delegate":      unsafe.Offsetof(syncImpl{}.delegate),
		"asyncImpl.delegate":     unsafe.Offsetof(asyncImpl{}.delegate),
		"syncHandle.delegate":    unsafe.Offsetof(syncHandle{}.delegate),
	}