summaryrefslogtreecommitdiffstats
path: root/vendor/go.opentelemetry.io/otel/metric/registry/registry.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/go.opentelemetry.io/otel/metric/registry/registry.go')
-rw-r--r--vendor/go.opentelemetry.io/otel/metric/registry/registry.go170
1 files changed, 170 insertions, 0 deletions
diff --git a/vendor/go.opentelemetry.io/otel/metric/registry/registry.go b/vendor/go.opentelemetry.io/otel/metric/registry/registry.go
new file mode 100644
index 0000000000..f1d9819c31
--- /dev/null
+++ b/vendor/go.opentelemetry.io/otel/metric/registry/registry.go
@@ -0,0 +1,170 @@
+// 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 registry // import "go.opentelemetry.io/otel/metric/registry"
+
+import (
+ "context"
+ "fmt"
+ "sync"
+
+ "go.opentelemetry.io/otel/label"
+ "go.opentelemetry.io/otel/metric"
+)
+
+// MeterProvider is a standard MeterProvider for wrapping `MeterImpl`
+type MeterProvider struct {
+ impl metric.MeterImpl
+}
+
+var _ metric.MeterProvider = (*MeterProvider)(nil)
+
+// uniqueInstrumentMeterImpl implements the metric.MeterImpl interface, adding
+// uniqueness checking for instrument descriptors. Use NewUniqueInstrumentMeter
+// to wrap an implementation with uniqueness checking.
+type uniqueInstrumentMeterImpl struct {
+ lock sync.Mutex
+ impl metric.MeterImpl
+ state map[key]metric.InstrumentImpl
+}
+
+var _ metric.MeterImpl = (*uniqueInstrumentMeterImpl)(nil)
+
+type key struct {
+ instrumentName string
+ instrumentationName string
+ InstrumentationVersion string
+}
+
+// NewMeterProvider returns a new provider that implements instrument
+// name-uniqueness checking.
+func NewMeterProvider(impl metric.MeterImpl) *MeterProvider {
+ return &MeterProvider{
+ impl: NewUniqueInstrumentMeterImpl(impl),
+ }
+}
+
+// Meter implements MeterProvider.
+func (p *MeterProvider) Meter(instrumentationName string, opts ...metric.MeterOption) metric.Meter {
+ return metric.WrapMeterImpl(p.impl, instrumentationName, opts...)
+}
+
+// ErrMetricKindMismatch is the standard error for mismatched metric
+// instrument definitions.
+var ErrMetricKindMismatch = fmt.Errorf(
+ "A metric was already registered by this name with another kind or number type")
+
+// NewUniqueInstrumentMeterImpl returns a wrapped metric.MeterImpl with
+// the addition of uniqueness checking.
+func NewUniqueInstrumentMeterImpl(impl metric.MeterImpl) metric.MeterImpl {
+ return &uniqueInstrumentMeterImpl{
+ impl: impl,
+ state: map[key]metric.InstrumentImpl{},
+ }
+}
+
+// RecordBatch implements metric.MeterImpl.
+func (u *uniqueInstrumentMeterImpl) RecordBatch(ctx context.Context, labels []label.KeyValue, ms ...metric.Measurement) {
+ u.impl.RecordBatch(ctx, labels, ms...)
+}
+
+func keyOf(descriptor metric.Descriptor) key {
+ return key{
+ descriptor.Name(),
+ descriptor.InstrumentationName(),
+ descriptor.InstrumentationVersion(),
+ }
+}
+
+// NewMetricKindMismatchError formats an error that describes a
+// mismatched metric instrument definition.
+func NewMetricKindMismatchError(desc metric.Descriptor) error {
+ return fmt.Errorf("Metric was %s (%s %s)registered as a %s %s: %w",
+ desc.Name(),
+ desc.InstrumentationName(),
+ desc.InstrumentationVersion(),
+ desc.NumberKind(),
+ desc.InstrumentKind(),
+ ErrMetricKindMismatch)
+}
+
+// Compatible determines whether two metric.Descriptors are considered
+// the same for the purpose of uniqueness checking.
+func Compatible(candidate, existing metric.Descriptor) bool {
+ return candidate.InstrumentKind() == existing.InstrumentKind() &&
+ candidate.NumberKind() == existing.NumberKind()
+}
+
+// checkUniqueness returns an ErrMetricKindMismatch error if there is
+// a conflict between a descriptor that was already registered and the
+// `descriptor` argument. If there is an existing compatible
+// registration, this returns the already-registered instrument. If
+// there is no conflict and no prior registration, returns (nil, nil).
+func (u *uniqueInstrumentMeterImpl) checkUniqueness(descriptor metric.Descriptor) (metric.InstrumentImpl, error) {
+ impl, ok := u.state[keyOf(descriptor)]
+ if !ok {
+ return nil, nil
+ }
+
+ if !Compatible(descriptor, impl.Descriptor()) {
+ return nil, NewMetricKindMismatchError(impl.Descriptor())
+ }
+
+ return impl, nil
+}
+
+// NewSyncInstrument implements metric.MeterImpl.
+func (u *uniqueInstrumentMeterImpl) NewSyncInstrument(descriptor metric.Descriptor) (metric.SyncImpl, error) {
+ u.lock.Lock()
+ defer u.lock.Unlock()
+
+ impl, err := u.checkUniqueness(descriptor)
+
+ if err != nil {
+ return nil, err
+ } else if impl != nil {
+ return impl.(metric.SyncImpl), nil
+ }
+
+ syncInst, err := u.impl.NewSyncInstrument(descriptor)
+ if err != nil {
+ return nil, err
+ }
+ u.state[keyOf(descriptor)] = syncInst
+ return syncInst, nil
+}
+
+// NewAsyncInstrument implements metric.MeterImpl.
+func (u *uniqueInstrumentMeterImpl) NewAsyncInstrument(
+ descriptor metric.Descriptor,
+ runner metric.AsyncRunner,
+) (metric.AsyncImpl, error) {
+ u.lock.Lock()
+ defer u.lock.Unlock()
+
+ impl, err := u.checkUniqueness(descriptor)
+
+ if err != nil {
+ return nil, err
+ } else if impl != nil {
+ return impl.(metric.AsyncImpl), nil
+ }
+
+ asyncInst, err := u.impl.NewAsyncInstrument(descriptor, runner)
+ if err != nil {
+ return nil, err
+ }
+ u.state[keyOf(descriptor)] = asyncInst
+ return asyncInst, nil
+}