From 281a6622034a337eb56e2e5fb0266d7de034dfeb Mon Sep 17 00:00:00 2001 From: Aaron Clawson Date: Wed, 26 Jan 2022 18:45:25 +0000 Subject: [PATCH 1/6] Empty All of the metrics dir --- internal/metric/async.go | 149 ------ internal/metric/global/benchmark_test.go | 41 -- internal/metric/global/internal_test.go | 40 -- internal/metric/global/meter.go | 287 ------------ internal/metric/global/meter_test.go | 253 ---------- internal/metric/global/metric.go | 66 --- internal/metric/global/registry_test.go | 131 ------ internal/metric/global/state_test.go | 45 -- internal/metric/registry/doc.go | 24 - internal/metric/registry/registry.go | 139 ------ internal/metric/registry/registry_test.go | 127 ----- metric/config.go | 124 ----- metric/doc.go | 67 --- metric/global/metric.go | 49 -- metric/global/metric_test.go | 42 -- metric/go.mod | 76 --- metric/go.sum | 19 - metric/metric.go | 538 ---------------------- metric/metric_instrument.go | 464 ------------------- metric/metric_test.go | 497 -------------------- metric/metrictest/alignment_test.go | 42 -- metric/metrictest/meter.go | 290 ------------ metric/noop.go | 30 -- metric/noop_test.go | 34 -- metric/number/doc.go | 23 - metric/number/kind_string.go | 24 - metric/number/number.go | 538 ---------------------- metric/number/number_test.go | 212 --------- metric/sdkapi/descriptor.go | 70 --- metric/sdkapi/descriptor_test.go | 33 -- metric/sdkapi/instrumentkind.go | 80 ---- metric/sdkapi/instrumentkind_string.go | 28 -- metric/sdkapi/instrumentkind_test.go | 32 -- metric/sdkapi/noop.go | 66 --- metric/sdkapi/sdkapi.go | 159 ------- metric/sdkapi/sdkapi_test.go | 41 -- metric/unit/doc.go | 20 - metric/unit/unit.go | 24 - 38 files changed, 4924 deletions(-) delete mode 100644 internal/metric/async.go delete mode 100644 internal/metric/global/benchmark_test.go delete mode 100644 internal/metric/global/internal_test.go delete mode 100644 internal/metric/global/meter.go delete mode 100644 internal/metric/global/meter_test.go delete mode 100644 internal/metric/global/metric.go delete mode 100644 internal/metric/global/registry_test.go delete mode 100644 internal/metric/global/state_test.go delete mode 100644 internal/metric/registry/doc.go delete mode 100644 internal/metric/registry/registry.go delete mode 100644 internal/metric/registry/registry_test.go delete mode 100644 metric/config.go delete mode 100644 metric/doc.go delete mode 100644 metric/global/metric.go delete mode 100644 metric/global/metric_test.go delete mode 100644 metric/go.mod delete mode 100644 metric/go.sum delete mode 100644 metric/metric.go delete mode 100644 metric/metric_instrument.go delete mode 100644 metric/metric_test.go delete mode 100644 metric/metrictest/alignment_test.go delete mode 100644 metric/metrictest/meter.go delete mode 100644 metric/noop.go delete mode 100644 metric/noop_test.go delete mode 100644 metric/number/doc.go delete mode 100644 metric/number/kind_string.go delete mode 100644 metric/number/number.go delete mode 100644 metric/number/number_test.go delete mode 100644 metric/sdkapi/descriptor.go delete mode 100644 metric/sdkapi/descriptor_test.go delete mode 100644 metric/sdkapi/instrumentkind.go delete mode 100644 metric/sdkapi/instrumentkind_string.go delete mode 100644 metric/sdkapi/instrumentkind_test.go delete mode 100644 metric/sdkapi/noop.go delete mode 100644 metric/sdkapi/sdkapi.go delete mode 100644 metric/sdkapi/sdkapi_test.go delete mode 100644 metric/unit/doc.go delete mode 100644 metric/unit/unit.go diff --git a/internal/metric/async.go b/internal/metric/async.go deleted file mode 100644 index 94801b7ff3c..00000000000 --- a/internal/metric/async.go +++ /dev/null @@ -1,149 +0,0 @@ -// 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 metric // import "go.opentelemetry.io/otel/internal/metric" - -import ( - "context" - "errors" - "fmt" - "sync" - - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/metric/sdkapi" -) - -//nolint:revive // ignoring missing comments for exported error in an internal package -var ErrInvalidAsyncRunner = errors.New("unknown async runner type") - -// AsyncCollector is an interface used between the MeterImpl and the -// AsyncInstrumentState helper below. This interface is implemented by -// the SDK to provide support for running observer callbacks. -type AsyncCollector interface { - // CollectAsync passes a batch of observations to the MeterImpl. - CollectAsync(labels []attribute.KeyValue, observation ...sdkapi.Observation) -} - -// AsyncInstrumentState manages an ordered set of asynchronous -// instruments and the distinct runners, taking into account batch -// observer callbacks. -type AsyncInstrumentState struct { - lock sync.Mutex - - // errorOnce will use the otel.Handler to report an error - // once in case of an invalid runner attempting to run. - errorOnce sync.Once - - // runnerMap keeps the set of runners that will run each - // collection interval. Singletons are entered with a real - // instrument each, batch observers are entered with a nil - // instrument, ensuring that when a singleton callback is used - // repeatedly, it is executed repeatedly in the interval, while - // when a batch callback is used repeatedly, it only executes - // once per interval. - runnerMap map[asyncRunnerPair]struct{} - - // runners maintains the set of runners in the order they were - // registered. - runners []asyncRunnerPair - - // instruments maintains the set of instruments in the order - // they were registered. - instruments []sdkapi.AsyncImpl -} - -// asyncRunnerPair is a map entry for Observer callback runners. -type asyncRunnerPair struct { - // runner is used as a map key here. The API ensures - // that all callbacks are pointers for this reason. - runner sdkapi.AsyncRunner - - // inst refers to a non-nil instrument when `runner` is a - // AsyncSingleRunner. - inst sdkapi.AsyncImpl -} - -// NewAsyncInstrumentState returns a new *AsyncInstrumentState, for -// use by MeterImpl to manage running the set of observer callbacks in -// the correct order. -func NewAsyncInstrumentState() *AsyncInstrumentState { - return &AsyncInstrumentState{ - runnerMap: map[asyncRunnerPair]struct{}{}, - } -} - -// Instruments returns the asynchronous instruments managed by this -// object, the set that should be checkpointed after observers are -// run. -func (a *AsyncInstrumentState) Instruments() []sdkapi.AsyncImpl { - a.lock.Lock() - defer a.lock.Unlock() - return a.instruments -} - -// Register adds a new asynchronous instrument to by managed by this -// object. This should be called during NewAsyncInstrument() and -// assumes that errors (e.g., duplicate registration) have already -// been checked. -func (a *AsyncInstrumentState) Register(inst sdkapi.AsyncImpl, runner sdkapi.AsyncRunner) { - a.lock.Lock() - defer a.lock.Unlock() - - a.instruments = append(a.instruments, inst) - - // asyncRunnerPair reflects this callback in the asyncRunners - // list. If this is a batch runner, the instrument is nil. - // If this is a single-Observer runner, the instrument is - // included. This ensures that batch callbacks are called - // once and single callbacks are called once per instrument. - rp := asyncRunnerPair{ - runner: runner, - } - if _, ok := runner.(sdkapi.AsyncSingleRunner); ok { - rp.inst = inst - } - - if _, ok := a.runnerMap[rp]; !ok { - a.runnerMap[rp] = struct{}{} - a.runners = append(a.runners, rp) - } -} - -// Run executes the complete set of observer callbacks. -func (a *AsyncInstrumentState) Run(ctx context.Context, collector AsyncCollector) { - a.lock.Lock() - runners := a.runners - a.lock.Unlock() - - for _, rp := range runners { - // The runner must be a single or batch runner, no - // other implementations are possible because the - // interface has un-exported methods. - - if singleRunner, ok := rp.runner.(sdkapi.AsyncSingleRunner); ok { - singleRunner.Run(ctx, rp.inst, collector.CollectAsync) - continue - } - - if multiRunner, ok := rp.runner.(sdkapi.AsyncBatchRunner); ok { - multiRunner.Run(ctx, collector.CollectAsync) - continue - } - - a.errorOnce.Do(func() { - otel.Handle(fmt.Errorf("%w: type %T (reported once)", ErrInvalidAsyncRunner, rp)) - }) - } -} diff --git a/internal/metric/global/benchmark_test.go b/internal/metric/global/benchmark_test.go deleted file mode 100644 index 05cab62d2dc..00000000000 --- a/internal/metric/global/benchmark_test.go +++ /dev/null @@ -1,41 +0,0 @@ -// 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 global_test - -import ( - "context" - "testing" - - "go.opentelemetry.io/otel/attribute" - internalglobal "go.opentelemetry.io/otel/internal/metric/global" - metricglobal "go.opentelemetry.io/otel/metric/global" -) - -func BenchmarkGlobalInt64CounterAddNoSDK(b *testing.B) { - // Compare with BenchmarkGlobalInt64CounterAddWithSDK() in - // ../../sdk/metric/benchmark_test.go to see the overhead of the - // global no-op system against a registered SDK. - internalglobal.ResetForTest() - ctx := context.Background() - sdk := metricglobal.Meter("test") - labs := []attribute.KeyValue{attribute.String("A", "B")} - cnt := Must(sdk).NewInt64Counter("int64.counter") - - b.ResetTimer() - - for i := 0; i < b.N; i++ { - cnt.Add(ctx, 1, labs...) - } -} diff --git a/internal/metric/global/internal_test.go b/internal/metric/global/internal_test.go deleted file mode 100644 index 44e1904aefe..00000000000 --- a/internal/metric/global/internal_test.go +++ /dev/null @@ -1,40 +0,0 @@ -// 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 global_test - -import ( - "os" - "testing" - - ottest "go.opentelemetry.io/otel/internal/internaltest" - "go.opentelemetry.io/otel/internal/metric/global" -) - -// Ensure struct alignment prior to running tests. -func TestMain(m *testing.M) { - fieldsMap := global.AtomicFieldOffsets() - fields := make([]ottest.FieldOffset, 0, len(fieldsMap)) - for name, offset := range fieldsMap { - fields = append(fields, ottest.FieldOffset{ - Name: name, - Offset: offset, - }) - } - if !ottest.Aligned8Byte(fields, os.Stderr) { - os.Exit(1) - } - - os.Exit(m.Run()) -} diff --git a/internal/metric/global/meter.go b/internal/metric/global/meter.go deleted file mode 100644 index 77781ead118..00000000000 --- a/internal/metric/global/meter.go +++ /dev/null @@ -1,287 +0,0 @@ -// 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 global // import "go.opentelemetry.io/otel/internal/metric/global" - -import ( - "context" - "sync" - "sync/atomic" - "unsafe" - - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/internal/metric/registry" - "go.opentelemetry.io/otel/metric" - "go.opentelemetry.io/otel/metric/number" - "go.opentelemetry.io/otel/metric/sdkapi" -) - -// This file contains the forwarding implementation of MeterProvider 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 MeterProvider 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 -// MeterProvider implementation is registered as the global provider. Mutexes -// in the MeterProvider and Meters ensure that each instrument has a delegate -// before the global provider is set. -// -// Metric uniqueness checking is implemented by calling the exported -// methods of the api/metric/registry package. - -type meterKey struct { - InstrumentationName string - InstrumentationVersion string - SchemaURL string -} - -type meterProvider struct { - delegate metric.MeterProvider - - // lock protects `delegate` and `meters`. - lock sync.Mutex - - // 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 sdkapi.MeterImpl - impl meterImpl -} - -type instrument struct { - descriptor sdkapi.Descriptor -} - -type syncImpl struct { - delegate unsafe.Pointer // (*sdkapi.SyncImpl) - - instrument -} - -type asyncImpl struct { - delegate unsafe.Pointer // (*sdkapi.AsyncImpl) - - instrument - - runner sdkapi.AsyncRunner -} - -var _ metric.MeterProvider = &meterProvider{} -var _ sdkapi.MeterImpl = &meterImpl{} -var _ sdkapi.InstrumentImpl = &syncImpl{} -var _ sdkapi.AsyncImpl = &asyncImpl{} - -func (inst *instrument) Descriptor() sdkapi.Descriptor { - return inst.descriptor -} - -// MeterProvider interface and delegation - -func newMeterProvider() *meterProvider { - return &meterProvider{ - meters: map[meterKey]*meterEntry{}, - } -} - -func (p *meterProvider) setDelegate(provider metric.MeterProvider) { - p.lock.Lock() - defer p.lock.Unlock() - - p.delegate = provider - for key, entry := range p.meters { - entry.impl.setDelegate(key, provider) - } - p.meters = nil -} - -func (p *meterProvider) Meter(instrumentationName string, opts ...metric.MeterOption) metric.Meter { - p.lock.Lock() - defer p.lock.Unlock() - - if p.delegate != nil { - return p.delegate.Meter(instrumentationName, opts...) - } - - cfg := metric.NewMeterConfig(opts...) - key := meterKey{ - InstrumentationName: instrumentationName, - InstrumentationVersion: cfg.InstrumentationVersion(), - SchemaURL: cfg.SchemaURL(), - } - entry, ok := p.meters[key] - if !ok { - entry = &meterEntry{} - // Note: This code implements its own MeterProvider - // name-uniqueness logic because there is - // synchronization required at the moment of - // delegation. We use the same instrument-uniqueness - // checking the real SDK uses here: - entry.unique = registry.NewUniqueInstrumentMeterImpl(&entry.impl) - p.meters[key] = entry - } - return metric.WrapMeterImpl(entry.unique) -} - -// Meter interface and delegation - -func (m *meterImpl) setDelegate(key meterKey, provider metric.MeterProvider) { - m.lock.Lock() - defer m.lock.Unlock() - - d := new(sdkapi.MeterImpl) - *d = provider.Meter( - key.InstrumentationName, - metric.WithInstrumentationVersion(key.InstrumentationVersion), - metric.WithSchemaURL(key.SchemaURL), - ).MeterImpl() - m.delegate = unsafe.Pointer(d) - - for _, inst := range m.syncInsts { - inst.setDelegate(*d) - } - m.syncInsts = nil - for _, obs := range m.asyncInsts { - obs.setDelegate(*d) - } - m.asyncInsts = nil -} - -func (m *meterImpl) NewSyncInstrument(desc sdkapi.Descriptor) (sdkapi.SyncImpl, error) { - m.lock.Lock() - defer m.lock.Unlock() - - if meterPtr := (*sdkapi.MeterImpl)(atomic.LoadPointer(&m.delegate)); meterPtr != nil { - return (*meterPtr).NewSyncInstrument(desc) - } - - inst := &syncImpl{ - instrument: instrument{ - descriptor: desc, - }, - } - m.syncInsts = append(m.syncInsts, inst) - return inst, nil -} - -// Synchronous delegation - -func (inst *syncImpl) setDelegate(d sdkapi.MeterImpl) { - implPtr := new(sdkapi.SyncImpl) - - var err error - *implPtr, err = d.NewSyncInstrument(inst.descriptor) - - if err != nil { - // 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(err) - } - - atomic.StorePointer(&inst.delegate, unsafe.Pointer(implPtr)) -} - -func (inst *syncImpl) Implementation() interface{} { - if implPtr := (*sdkapi.SyncImpl)(atomic.LoadPointer(&inst.delegate)); implPtr != nil { - return (*implPtr).Implementation() - } - return inst -} - -// Async delegation - -func (m *meterImpl) NewAsyncInstrument( - desc sdkapi.Descriptor, - runner sdkapi.AsyncRunner, -) (sdkapi.AsyncImpl, error) { - - m.lock.Lock() - defer m.lock.Unlock() - - if meterPtr := (*sdkapi.MeterImpl)(atomic.LoadPointer(&m.delegate)); meterPtr != nil { - return (*meterPtr).NewAsyncInstrument(desc, runner) - } - - inst := &asyncImpl{ - instrument: instrument{ - descriptor: desc, - }, - runner: runner, - } - m.asyncInsts = append(m.asyncInsts, inst) - return inst, nil -} - -func (obs *asyncImpl) Implementation() interface{} { - if implPtr := (*sdkapi.AsyncImpl)(atomic.LoadPointer(&obs.delegate)); implPtr != nil { - return (*implPtr).Implementation() - } - return obs -} - -func (obs *asyncImpl) setDelegate(d sdkapi.MeterImpl) { - implPtr := new(sdkapi.AsyncImpl) - - var err error - *implPtr, err = d.NewAsyncInstrument(obs.descriptor, obs.runner) - - if err != nil { - // 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(err) - } - - atomic.StorePointer(&obs.delegate, unsafe.Pointer(implPtr)) -} - -// Metric updates - -func (m *meterImpl) RecordBatch(ctx context.Context, labels []attribute.KeyValue, measurements ...sdkapi.Measurement) { - if delegatePtr := (*sdkapi.MeterImpl)(atomic.LoadPointer(&m.delegate)); delegatePtr != nil { - (*delegatePtr).RecordBatch(ctx, labels, measurements...) - } -} - -func (inst *syncImpl) RecordOne(ctx context.Context, number number.Number, labels []attribute.KeyValue) { - if instPtr := (*sdkapi.SyncImpl)(atomic.LoadPointer(&inst.delegate)); instPtr != nil { - (*instPtr).RecordOne(ctx, number, labels) - } -} - -func AtomicFieldOffsets() 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), - } -} diff --git a/internal/metric/global/meter_test.go b/internal/metric/global/meter_test.go deleted file mode 100644 index 2062ecf8b07..00000000000 --- a/internal/metric/global/meter_test.go +++ /dev/null @@ -1,253 +0,0 @@ -// 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 global_test - -import ( - "context" - "errors" - "testing" - - "github.com/stretchr/testify/require" - - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/internal/metric/global" - "go.opentelemetry.io/otel/metric" - metricglobal "go.opentelemetry.io/otel/metric/global" - "go.opentelemetry.io/otel/metric/metrictest" - "go.opentelemetry.io/otel/metric/number" - "go.opentelemetry.io/otel/metric/sdkapi" -) - -var Must = metric.Must - -var asInt = number.NewInt64Number -var asFloat = number.NewFloat64Number - -func TestDirect(t *testing.T) { - global.ResetForTest() - - ctx := context.Background() - meter1 := metricglobal.Meter("test1", metric.WithInstrumentationVersion("semver:v1.0.0")) - meter2 := metricglobal.Meter("test2", metric.WithSchemaURL("hello")) - - library1 := metrictest.Library{ - InstrumentationName: "test1", - InstrumentationVersion: "semver:v1.0.0", - } - library2 := metrictest.Library{ - InstrumentationName: "test2", - SchemaURL: "hello", - } - - labels1 := []attribute.KeyValue{attribute.String("A", "B")} - labels2 := []attribute.KeyValue{attribute.String("C", "D")} - labels3 := []attribute.KeyValue{attribute.String("E", "F")} - - counter := Must(meter1).NewInt64Counter("test.counter") - counter.Add(ctx, 1, labels1...) - counter.Add(ctx, 1, labels1...) - - histogram := Must(meter1).NewFloat64Histogram("test.histogram") - histogram.Record(ctx, 1, labels1...) - histogram.Record(ctx, 2, labels1...) - - _ = Must(meter1).NewFloat64GaugeObserver("test.gauge.float", func(_ context.Context, result metric.Float64ObserverResult) { - result.Observe(1., labels1...) - result.Observe(2., labels2...) - }) - - _ = Must(meter1).NewInt64GaugeObserver("test.gauge.int", func(_ context.Context, result metric.Int64ObserverResult) { - result.Observe(1, labels1...) - result.Observe(2, labels2...) - }) - - second := Must(meter2).NewFloat64Histogram("test.second") - second.Record(ctx, 1, labels3...) - second.Record(ctx, 2, labels3...) - - provider := metrictest.NewMeterProvider() - metricglobal.SetMeterProvider(provider) - - counter.Add(ctx, 1, labels1...) - histogram.Record(ctx, 3, labels1...) - second.Record(ctx, 3, labels3...) - - provider.RunAsyncInstruments() - - measurements := metrictest.AsStructs(provider.MeasurementBatches) - - require.EqualValues(t, - []metrictest.Measured{ - { - Name: "test.counter", - Library: library1, - Labels: metrictest.LabelsToMap(labels1...), - Number: asInt(1), - }, - { - Name: "test.histogram", - Library: library1, - Labels: metrictest.LabelsToMap(labels1...), - Number: asFloat(3), - }, - { - Name: "test.second", - Library: library2, - Labels: metrictest.LabelsToMap(labels3...), - Number: asFloat(3), - }, - { - Name: "test.gauge.float", - Library: library1, - Labels: metrictest.LabelsToMap(labels1...), - Number: asFloat(1), - }, - { - Name: "test.gauge.float", - Library: library1, - Labels: metrictest.LabelsToMap(labels2...), - Number: asFloat(2), - }, - { - Name: "test.gauge.int", - Library: library1, - Labels: metrictest.LabelsToMap(labels1...), - Number: asInt(1), - }, - { - Name: "test.gauge.int", - Library: library1, - Labels: metrictest.LabelsToMap(labels2...), - Number: asInt(2), - }, - }, - measurements, - ) -} - -type meterProviderWithConstructorError struct { - metric.MeterProvider -} - -type meterWithConstructorError struct { - sdkapi.MeterImpl -} - -func (m *meterProviderWithConstructorError) Meter(iName string, opts ...metric.MeterOption) metric.Meter { - return metric.WrapMeterImpl(&meterWithConstructorError{m.MeterProvider.Meter(iName, opts...).MeterImpl()}) -} - -func (m *meterWithConstructorError) NewSyncInstrument(_ sdkapi.Descriptor) (sdkapi.SyncImpl, error) { - return sdkapi.NewNoopSyncInstrument(), errors.New("constructor error") -} - -func TestErrorInDeferredConstructor(t *testing.T) { - global.ResetForTest() - - ctx := context.Background() - meter := metricglobal.GetMeterProvider().Meter("builtin") - - c1 := Must(meter).NewInt64Counter("test") - c2 := Must(meter).NewInt64Counter("test") - - provider := metrictest.NewMeterProvider() - sdk := &meterProviderWithConstructorError{provider} - - require.Panics(t, func() { - metricglobal.SetMeterProvider(sdk) - }) - - c1.Add(ctx, 1) - c2.Add(ctx, 2) -} - -func TestImplementationIndirection(t *testing.T) { - global.ResetForTest() - - // Test that Implementation() does the proper indirection, i.e., - // returns the implementation interface not the global, after - // registered. - - meter1 := metricglobal.Meter("test1") - - // Sync: no SDK yet - counter := Must(meter1).NewInt64Counter("interface.counter") - - ival := counter.Measurement(1).SyncImpl().Implementation() - require.NotNil(t, ival) - - _, ok := ival.(*metrictest.Sync) - require.False(t, ok) - - // Async: no SDK yet - gauge := Must(meter1).NewFloat64GaugeObserver( - "interface.gauge", - func(_ context.Context, result metric.Float64ObserverResult) {}, - ) - - ival = gauge.AsyncImpl().Implementation() - require.NotNil(t, ival) - - _, ok = ival.(*metrictest.Async) - require.False(t, ok) - - // Register the SDK - provider := metrictest.NewMeterProvider() - metricglobal.SetMeterProvider(provider) - - // Repeat the above tests - - // Sync - ival = counter.Measurement(1).SyncImpl().Implementation() - require.NotNil(t, ival) - - _, ok = ival.(*metrictest.Sync) - require.True(t, ok) - - // Async - ival = gauge.AsyncImpl().Implementation() - require.NotNil(t, ival) - - _, ok = ival.(*metrictest.Async) - require.True(t, ok) -} - -func TestRecordBatchMock(t *testing.T) { - global.ResetForTest() - - meter := metricglobal.GetMeterProvider().Meter("builtin") - - counter := Must(meter).NewInt64Counter("test.counter") - - meter.RecordBatch(context.Background(), nil, counter.Measurement(1)) - - provider := metrictest.NewMeterProvider() - metricglobal.SetMeterProvider(provider) - - meter.RecordBatch(context.Background(), nil, counter.Measurement(1)) - - require.EqualValues(t, - []metrictest.Measured{ - { - Name: "test.counter", - Library: metrictest.Library{ - InstrumentationName: "builtin", - }, - Labels: metrictest.LabelsToMap(), - Number: asInt(1), - }, - }, - metrictest.AsStructs(provider.MeasurementBatches)) -} diff --git a/internal/metric/global/metric.go b/internal/metric/global/metric.go deleted file mode 100644 index 896c6dd1c30..00000000000 --- a/internal/metric/global/metric.go +++ /dev/null @@ -1,66 +0,0 @@ -// 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 global // import "go.opentelemetry.io/otel/internal/metric/global" - -import ( - "sync" - "sync/atomic" - - "go.opentelemetry.io/otel/metric" -) - -type meterProviderHolder struct { - mp metric.MeterProvider -} - -var ( - globalMeter = defaultMeterValue() - - delegateMeterOnce sync.Once -) - -// MeterProvider is the internal implementation for global.MeterProvider. -func MeterProvider() metric.MeterProvider { - return globalMeter.Load().(meterProviderHolder).mp -} - -// SetMeterProvider is the internal implementation for global.SetMeterProvider. -func SetMeterProvider(mp metric.MeterProvider) { - delegateMeterOnce.Do(func() { - current := MeterProvider() - - if current == mp { - // Setting the provider to the prior default is nonsense, panic. - // Panic is acceptable because we are likely still early in the - // process lifetime. - panic("invalid MeterProvider, the global instance cannot be reinstalled") - } else if def, ok := current.(*meterProvider); ok { - def.setDelegate(mp) - } - }) - globalMeter.Store(meterProviderHolder{mp: mp}) -} - -func defaultMeterValue() *atomic.Value { - v := &atomic.Value{} - v.Store(meterProviderHolder{mp: newMeterProvider()}) - return v -} - -// ResetForTest restores the initial global state, for testing purposes. -func ResetForTest() { - globalMeter = defaultMeterValue() - delegateMeterOnce = sync.Once{} -} diff --git a/internal/metric/global/registry_test.go b/internal/metric/global/registry_test.go deleted file mode 100644 index 0d92c044ef1..00000000000 --- a/internal/metric/global/registry_test.go +++ /dev/null @@ -1,131 +0,0 @@ -// 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 global - -import ( - "context" - "errors" - "testing" - - "github.com/stretchr/testify/require" - - "go.opentelemetry.io/otel/internal/metric/registry" - "go.opentelemetry.io/otel/metric" - "go.opentelemetry.io/otel/metric/metrictest" - "go.opentelemetry.io/otel/metric/sdkapi" -) - -type ( - newFunc func(name, libraryName string) (sdkapi.InstrumentImpl, error) -) - -var ( - allNew = map[string]newFunc{ - "counter.int64": func(name, libraryName string) (sdkapi.InstrumentImpl, error) { - return unwrap(MeterProvider().Meter(libraryName).NewInt64Counter(name)) - }, - "counter.float64": func(name, libraryName string) (sdkapi.InstrumentImpl, error) { - return unwrap(MeterProvider().Meter(libraryName).NewFloat64Counter(name)) - }, - "histogram.int64": func(name, libraryName string) (sdkapi.InstrumentImpl, error) { - return unwrap(MeterProvider().Meter(libraryName).NewInt64Histogram(name)) - }, - "histogram.float64": func(name, libraryName string) (sdkapi.InstrumentImpl, error) { - return unwrap(MeterProvider().Meter(libraryName).NewFloat64Histogram(name)) - }, - "gauge.int64": func(name, libraryName string) (sdkapi.InstrumentImpl, error) { - return unwrap(MeterProvider().Meter(libraryName).NewInt64GaugeObserver(name, func(context.Context, metric.Int64ObserverResult) {})) - }, - "gauge.float64": func(name, libraryName string) (sdkapi.InstrumentImpl, error) { - return unwrap(MeterProvider().Meter(libraryName).NewFloat64GaugeObserver(name, func(context.Context, metric.Float64ObserverResult) {})) - }, - } -) - -func unwrap(impl interface{}, err error) (sdkapi.InstrumentImpl, error) { - if impl == nil { - return nil, err - } - if s, ok := impl.(interface { - SyncImpl() sdkapi.SyncImpl - }); ok { - return s.SyncImpl(), err - } - if a, ok := impl.(interface { - AsyncImpl() sdkapi.AsyncImpl - }); ok { - return a.AsyncImpl(), err - } - return nil, err -} - -func TestRegistrySameInstruments(t *testing.T) { - for _, nf := range allNew { - ResetForTest() - inst1, err1 := nf("this", "meter") - inst2, err2 := nf("this", "meter") - - require.NoError(t, err1) - require.NoError(t, err2) - require.Equal(t, inst1, inst2) - - SetMeterProvider(metrictest.NewMeterProvider()) - - require.Equal(t, inst1, inst2) - } -} - -func TestRegistryDifferentNamespace(t *testing.T) { - for _, nf := range allNew { - ResetForTest() - inst1, err1 := nf("this", "meter1") - inst2, err2 := nf("this", "meter2") - - require.NoError(t, err1) - require.NoError(t, err2) - - if inst1.Descriptor().InstrumentKind().Synchronous() { - // They're equal because of a `nil` pointer at this point. - // (Only for synchronous instruments, which lack callacks.) - require.EqualValues(t, inst1, inst2) - } - - SetMeterProvider(metrictest.NewMeterProvider()) - - // They're different after the deferred setup. - require.NotEqual(t, inst1, inst2) - } -} - -func TestRegistryDiffInstruments(t *testing.T) { - for origName, origf := range allNew { - ResetForTest() - - _, err := origf("this", "super") - require.NoError(t, err) - - for newName, nf := range allNew { - if newName == origName { - continue - } - - other, err := nf("this", "super") - require.Error(t, err) - require.NotNil(t, other) - require.True(t, errors.Is(err, registry.ErrMetricKindMismatch)) - require.Contains(t, err.Error(), "by this name with another kind or number type") - } - } -} diff --git a/internal/metric/global/state_test.go b/internal/metric/global/state_test.go deleted file mode 100644 index 526eac7fa69..00000000000 --- a/internal/metric/global/state_test.go +++ /dev/null @@ -1,45 +0,0 @@ -// 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 global_test - -import ( - "testing" - - internalglobal "go.opentelemetry.io/otel/internal/metric/global" - metricglobal "go.opentelemetry.io/otel/metric/global" -) - -func TestResetsOfGlobalsPanic(t *testing.T) { - internalglobal.ResetForTest() - tests := map[string]func(){ - "SetMeterProvider": func() { - metricglobal.SetMeterProvider(metricglobal.GetMeterProvider()) - }, - } - - for name, test := range tests { - shouldPanic(t, name, test) - } -} - -func shouldPanic(t *testing.T, name string, f func()) { - defer func() { - if r := recover(); r == nil { - t.Errorf("calling %s with default global did not panic", name) - } - }() - - f() -} diff --git a/internal/metric/registry/doc.go b/internal/metric/registry/doc.go deleted file mode 100644 index 2f17562f0eb..00000000000 --- a/internal/metric/registry/doc.go +++ /dev/null @@ -1,24 +0,0 @@ -// 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 provides a non-standalone implementation of -MeterProvider that adds uniqueness checking for instrument descriptors -on top of other MeterProvider it wraps. - -This package is currently in a pre-GA phase. Backwards incompatible changes -may be introduced in subsequent minor version releases as we work to track the -evolving OpenTelemetry specification and user feedback. -*/ -package registry // import "go.opentelemetry.io/otel/internal/metric/registry" diff --git a/internal/metric/registry/registry.go b/internal/metric/registry/registry.go deleted file mode 100644 index c929bf45c85..00000000000 --- a/internal/metric/registry/registry.go +++ /dev/null @@ -1,139 +0,0 @@ -// 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/internal/metric/registry" - -import ( - "context" - "fmt" - "sync" - - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/metric/sdkapi" -) - -// UniqueInstrumentMeterImpl implements the metric.MeterImpl interface, adding -// uniqueness checking for instrument descriptors. -type UniqueInstrumentMeterImpl struct { - lock sync.Mutex - impl sdkapi.MeterImpl - state map[string]sdkapi.InstrumentImpl -} - -var _ sdkapi.MeterImpl = (*UniqueInstrumentMeterImpl)(nil) - -// 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 instrument name uniqueness checking. -func NewUniqueInstrumentMeterImpl(impl sdkapi.MeterImpl) *UniqueInstrumentMeterImpl { - return &UniqueInstrumentMeterImpl{ - impl: impl, - state: map[string]sdkapi.InstrumentImpl{}, - } -} - -// MeterImpl gives the caller access to the underlying MeterImpl -// used by this UniqueInstrumentMeterImpl. -func (u *UniqueInstrumentMeterImpl) MeterImpl() sdkapi.MeterImpl { - return u.impl -} - -// RecordBatch implements sdkapi.MeterImpl. -func (u *UniqueInstrumentMeterImpl) RecordBatch(ctx context.Context, labels []attribute.KeyValue, ms ...sdkapi.Measurement) { - u.impl.RecordBatch(ctx, labels, ms...) -} - -// NewMetricKindMismatchError formats an error that describes a -// mismatched metric instrument definition. -func NewMetricKindMismatchError(desc sdkapi.Descriptor) error { - return fmt.Errorf("metric %s registered as %s %s: %w", - desc.Name(), - desc.NumberKind(), - desc.InstrumentKind(), - ErrMetricKindMismatch) -} - -// Compatible determines whether two sdkapi.Descriptors are considered -// the same for the purpose of uniqueness checking. -func Compatible(candidate, existing sdkapi.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 sdkapi.Descriptor) (sdkapi.InstrumentImpl, error) { - impl, ok := u.state[descriptor.Name()] - if !ok { - return nil, nil - } - - if !Compatible(descriptor, impl.Descriptor()) { - return nil, NewMetricKindMismatchError(impl.Descriptor()) - } - - return impl, nil -} - -// NewSyncInstrument implements sdkapi.MeterImpl. -func (u *UniqueInstrumentMeterImpl) NewSyncInstrument(descriptor sdkapi.Descriptor) (sdkapi.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.(sdkapi.SyncImpl), nil - } - - syncInst, err := u.impl.NewSyncInstrument(descriptor) - if err != nil { - return nil, err - } - u.state[descriptor.Name()] = syncInst - return syncInst, nil -} - -// NewAsyncInstrument implements sdkapi.MeterImpl. -func (u *UniqueInstrumentMeterImpl) NewAsyncInstrument( - descriptor sdkapi.Descriptor, - runner sdkapi.AsyncRunner, -) (sdkapi.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.(sdkapi.AsyncImpl), nil - } - - asyncInst, err := u.impl.NewAsyncInstrument(descriptor, runner) - if err != nil { - return nil, err - } - u.state[descriptor.Name()] = asyncInst - return asyncInst, nil -} diff --git a/internal/metric/registry/registry_test.go b/internal/metric/registry/registry_test.go deleted file mode 100644 index 04884898822..00000000000 --- a/internal/metric/registry/registry_test.go +++ /dev/null @@ -1,127 +0,0 @@ -// 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_test - -import ( - "context" - "errors" - "testing" - - "github.com/stretchr/testify/require" - - "go.opentelemetry.io/otel/internal/metric/registry" - "go.opentelemetry.io/otel/metric" - "go.opentelemetry.io/otel/metric/metrictest" - "go.opentelemetry.io/otel/metric/sdkapi" -) - -type ( - newFunc func(m metric.Meter, name string) (sdkapi.InstrumentImpl, error) -) - -var ( - allNew = map[string]newFunc{ - "counter.int64": func(m metric.Meter, name string) (sdkapi.InstrumentImpl, error) { - return unwrap(m.NewInt64Counter(name)) - }, - "counter.float64": func(m metric.Meter, name string) (sdkapi.InstrumentImpl, error) { - return unwrap(m.NewFloat64Counter(name)) - }, - "histogram.int64": func(m metric.Meter, name string) (sdkapi.InstrumentImpl, error) { - return unwrap(m.NewInt64Histogram(name)) - }, - "histogram.float64": func(m metric.Meter, name string) (sdkapi.InstrumentImpl, error) { - return unwrap(m.NewFloat64Histogram(name)) - }, - "gaugeobserver.int64": func(m metric.Meter, name string) (sdkapi.InstrumentImpl, error) { - return unwrap(m.NewInt64GaugeObserver(name, func(context.Context, metric.Int64ObserverResult) {})) - }, - "gaugeobserver.float64": func(m metric.Meter, name string) (sdkapi.InstrumentImpl, error) { - return unwrap(m.NewFloat64GaugeObserver(name, func(context.Context, metric.Float64ObserverResult) {})) - }, - } -) - -func unwrap(impl interface{}, err error) (sdkapi.InstrumentImpl, error) { - if impl == nil { - return nil, err - } - if s, ok := impl.(interface { - SyncImpl() sdkapi.SyncImpl - }); ok { - return s.SyncImpl(), err - } - if a, ok := impl.(interface { - AsyncImpl() sdkapi.AsyncImpl - }); ok { - return a.AsyncImpl(), err - } - return nil, err -} - -func testMeterWithRegistry(name string) metric.Meter { - return metric.WrapMeterImpl( - registry.NewUniqueInstrumentMeterImpl( - metrictest.NewMeterProvider().Meter(name).MeterImpl(), - ), - ) -} - -func TestRegistrySameInstruments(t *testing.T) { - for _, nf := range allNew { - meter := testMeterWithRegistry("meter") - inst1, err1 := nf(meter, "this") - inst2, err2 := nf(meter, "this") - - require.NoError(t, err1) - require.NoError(t, err2) - require.Equal(t, inst1, inst2) - } -} - -func TestRegistryDifferentNamespace(t *testing.T) { - for _, nf := range allNew { - provider := metrictest.NewMeterProvider() - - meter1 := provider.Meter("meter1") - meter2 := provider.Meter("meter2") - inst1, err1 := nf(meter1, "this") - inst2, err2 := nf(meter2, "this") - - require.NoError(t, err1) - require.NoError(t, err2) - require.NotEqual(t, inst1, inst2) - } -} - -func TestRegistryDiffInstruments(t *testing.T) { - for origName, origf := range allNew { - meter := testMeterWithRegistry("meter") - - _, err := origf(meter, "this") - require.NoError(t, err) - - for newName, nf := range allNew { - if newName == origName { - continue - } - - other, err := nf(meter, "this") - require.Error(t, err) - require.NotNil(t, other) - require.True(t, errors.Is(err, registry.ErrMetricKindMismatch)) - } - } -} diff --git a/metric/config.go b/metric/config.go deleted file mode 100644 index 686ca7c1acb..00000000000 --- a/metric/config.go +++ /dev/null @@ -1,124 +0,0 @@ -// 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 metric // import "go.opentelemetry.io/otel/metric" - -import ( - "go.opentelemetry.io/otel/metric/unit" -) - -// InstrumentConfig contains options for metric instrument descriptors. -type InstrumentConfig struct { - description string - unit unit.Unit -} - -// Description describes the instrument in human-readable terms. -func (cfg *InstrumentConfig) Description() string { - return cfg.description -} - -// Unit describes the measurement unit for a instrument. -func (cfg *InstrumentConfig) Unit() unit.Unit { - return cfg.unit -} - -// InstrumentOption is an interface for applying metric instrument options. -type InstrumentOption interface { - // ApplyMeter is used to set a InstrumentOption value of a - // InstrumentConfig. - applyInstrument(*InstrumentConfig) -} - -// NewInstrumentConfig creates a new InstrumentConfig -// and applies all the given options. -func NewInstrumentConfig(opts ...InstrumentOption) InstrumentConfig { - var config InstrumentConfig - for _, o := range opts { - o.applyInstrument(&config) - } - return config -} - -type instrumentOptionFunc func(*InstrumentConfig) - -func (fn instrumentOptionFunc) applyInstrument(cfg *InstrumentConfig) { - fn(cfg) -} - -// WithDescription applies provided description. -func WithDescription(desc string) InstrumentOption { - return instrumentOptionFunc(func(cfg *InstrumentConfig) { - cfg.description = desc - }) -} - -// WithUnit applies provided unit. -func WithUnit(unit unit.Unit) InstrumentOption { - return instrumentOptionFunc(func(cfg *InstrumentConfig) { - cfg.unit = unit - }) -} - -// MeterConfig contains options for Meters. -type MeterConfig struct { - instrumentationVersion string - schemaURL string -} - -// InstrumentationVersion is the version of the library providing instrumentation. -func (cfg *MeterConfig) InstrumentationVersion() string { - return cfg.instrumentationVersion -} - -// SchemaURL is the schema_url of the library providing instrumentation. -func (cfg *MeterConfig) SchemaURL() string { - return cfg.schemaURL -} - -// MeterOption is an interface for applying Meter options. -type MeterOption interface { - // ApplyMeter is used to set a MeterOption value of a MeterConfig. - applyMeter(*MeterConfig) -} - -// NewMeterConfig creates a new MeterConfig and applies -// all the given options. -func NewMeterConfig(opts ...MeterOption) MeterConfig { - var config MeterConfig - for _, o := range opts { - o.applyMeter(&config) - } - return config -} - -type meterOptionFunc func(*MeterConfig) - -func (fn meterOptionFunc) applyMeter(cfg *MeterConfig) { - fn(cfg) -} - -// WithInstrumentationVersion sets the instrumentation version. -func WithInstrumentationVersion(version string) MeterOption { - return meterOptionFunc(func(config *MeterConfig) { - config.instrumentationVersion = version - }) -} - -// WithSchemaURL sets the schema URL. -func WithSchemaURL(schemaURL string) MeterOption { - return meterOptionFunc(func(config *MeterConfig) { - config.schemaURL = schemaURL - }) -} diff --git a/metric/doc.go b/metric/doc.go deleted file mode 100644 index 4baf0719fcc..00000000000 --- a/metric/doc.go +++ /dev/null @@ -1,67 +0,0 @@ -// 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 metric provides an implementation of the metrics part of the -OpenTelemetry API. - -This package is currently in a pre-GA phase. Backwards incompatible changes -may be introduced in subsequent minor version releases as we work to track the -evolving OpenTelemetry specification and user feedback. - -Measurements can be made about an operation being performed or the state of a -system in general. These measurements can be crucial to the reliable operation -of code and provide valuable insights about the inner workings of a system. - -Measurements are made using instruments provided by this package. The type of -instrument used will depend on the type of measurement being made and of what -part of a system is being measured. - -Instruments are categorized as Synchronous or Asynchronous and independently -as Adding or Grouping. Synchronous instruments are called by the user with a -Context. Asynchronous instruments are called by the SDK during collection. -Adding instruments are semantically intended for capturing a sum. Grouping -instruments are intended for capturing a distribution. - -Adding instruments may be monotonic, in which case they are non-decreasing -and naturally define a rate. - -The synchronous instrument names are: - - Counter: adding, monotonic - UpDownCounter: adding - Histogram: grouping - -and the asynchronous instruments are: - - CounterObserver: adding, monotonic - UpDownCounterObserver: adding - GaugeObserver: grouping - -All instruments are provided with support for either float64 or int64 input -values. - -An instrument is created using a Meter. Additionally, a Meter is used to -record batches of synchronous measurements or asynchronous observations. A -Meter is obtained using a MeterProvider. A Meter, like a Tracer, is unique to -the instrumentation it instruments and must be named and versioned when -created with a MeterProvider with the name and version of the instrumentation -library. - -Instrumentation should be designed to accept a MeterProvider from which it can -create its own unique Meter. Alternatively, the registered global -MeterProvider from the go.opentelemetry.io/otel package can be used as a -default. -*/ -package metric // import "go.opentelemetry.io/otel/metric" diff --git a/metric/global/metric.go b/metric/global/metric.go deleted file mode 100644 index 14ba862002a..00000000000 --- a/metric/global/metric.go +++ /dev/null @@ -1,49 +0,0 @@ -// 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 global // import "go.opentelemetry.io/otel/metric/global" - -import ( - "go.opentelemetry.io/otel/internal/metric/global" - "go.opentelemetry.io/otel/metric" -) - -// Meter creates an implementation of the Meter interface from the global -// MeterProvider. The instrumentationName must be the name of the library -// providing instrumentation. This name may be the same as the instrumented -// code only if that code provides built-in instrumentation. If the -// instrumentationName is empty, then a implementation defined default name -// will be used instead. -// -// This is short for MeterProvider().Meter(name) -func Meter(instrumentationName string, opts ...metric.MeterOption) metric.Meter { - return GetMeterProvider().Meter(instrumentationName, opts...) -} - -// GetMeterProvider returns the registered global meter provider. If -// none is registered then a default meter provider is returned that -// forwards the Meter interface to the first registered Meter. -// -// Use the meter provider to create a named meter. E.g. -// meter := global.MeterProvider().Meter("example.com/foo") -// or -// meter := global.Meter("example.com/foo") -func GetMeterProvider() metric.MeterProvider { - return global.MeterProvider() -} - -// SetMeterProvider registers `mp` as the global meter provider. -func SetMeterProvider(mp metric.MeterProvider) { - global.SetMeterProvider(mp) -} diff --git a/metric/global/metric_test.go b/metric/global/metric_test.go deleted file mode 100644 index dc4d9370a92..00000000000 --- a/metric/global/metric_test.go +++ /dev/null @@ -1,42 +0,0 @@ -// 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 global - -import ( - "testing" - - "go.opentelemetry.io/otel/metric" -) - -type testMeterProvider struct{} - -var _ metric.MeterProvider = &testMeterProvider{} - -func (*testMeterProvider) Meter(_ string, _ ...metric.MeterOption) metric.Meter { - return metric.Meter{} -} - -func TestMultipleGlobalMeterProvider(t *testing.T) { - p1 := testMeterProvider{} - p2 := metric.NewNoopMeterProvider() - SetMeterProvider(&p1) - SetMeterProvider(p2) - - got := GetMeterProvider() - want := p2 - if got != want { - t.Fatalf("MeterProvider: got %p, want %p\n", got, want) - } -} diff --git a/metric/go.mod b/metric/go.mod deleted file mode 100644 index 5b9387bf3f6..00000000000 --- a/metric/go.mod +++ /dev/null @@ -1,76 +0,0 @@ -module go.opentelemetry.io/otel/metric - -go 1.16 - -replace go.opentelemetry.io/otel => ../ - -replace go.opentelemetry.io/otel/bridge/opencensus => ../bridge/opencensus - -replace go.opentelemetry.io/otel/bridge/opentracing => ../bridge/opentracing - -replace go.opentelemetry.io/otel/example/jaeger => ../example/jaeger - -replace go.opentelemetry.io/otel/example/namedtracer => ../example/namedtracer - -replace go.opentelemetry.io/otel/example/opencensus => ../example/opencensus - -replace go.opentelemetry.io/otel/example/otel-collector => ../example/otel-collector - -replace go.opentelemetry.io/otel/example/prom-collector => ../example/prom-collector - -replace go.opentelemetry.io/otel/example/prometheus => ../example/prometheus - -replace go.opentelemetry.io/otel/example/zipkin => ../example/zipkin - -replace go.opentelemetry.io/otel/exporters/prometheus => ../exporters/prometheus - -replace go.opentelemetry.io/otel/exporters/jaeger => ../exporters/jaeger - -replace go.opentelemetry.io/otel/exporters/zipkin => ../exporters/zipkin - -replace go.opentelemetry.io/otel/internal/tools => ../internal/tools - -replace go.opentelemetry.io/otel/metric => ./ - -replace go.opentelemetry.io/otel/sdk => ../sdk - -replace go.opentelemetry.io/otel/sdk/export/metric => ../sdk/export/metric - -replace go.opentelemetry.io/otel/sdk/metric => ../sdk/metric - -replace go.opentelemetry.io/otel/trace => ../trace - -require ( - github.com/google/go-cmp v0.5.7 - github.com/stretchr/testify v1.7.0 - go.opentelemetry.io/otel v1.3.0 - go.opentelemetry.io/otel/internal/metric v0.26.0 -) - -replace go.opentelemetry.io/otel/example/passthrough => ../example/passthrough - -replace go.opentelemetry.io/otel/exporters/otlp/otlptrace => ../exporters/otlp/otlptrace - -replace go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc => ../exporters/otlp/otlptrace/otlptracegrpc - -replace go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp => ../exporters/otlp/otlptrace/otlptracehttp - -replace go.opentelemetry.io/otel/internal/metric => ../internal/metric - -replace go.opentelemetry.io/otel/exporters/otlp/otlpmetric => ../exporters/otlp/otlpmetric - -replace go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc => ../exporters/otlp/otlpmetric/otlpmetricgrpc - -replace go.opentelemetry.io/otel/exporters/stdout/stdoutmetric => ../exporters/stdout/stdoutmetric - -replace go.opentelemetry.io/otel/exporters/stdout/stdouttrace => ../exporters/stdout/stdouttrace - -replace go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp => ../exporters/otlp/otlpmetric/otlpmetrichttp - -replace go.opentelemetry.io/otel/bridge/opencensus/test => ../bridge/opencensus/test - -replace go.opentelemetry.io/otel/example/fib => ../example/fib - -replace go.opentelemetry.io/otel/schema => ../schema - -replace go.opentelemetry.io/otel/exporters/otlp/internal/retry => ../exporters/otlp/internal/retry diff --git a/metric/go.sum b/metric/go.sum deleted file mode 100644 index 531cae722ed..00000000000 --- a/metric/go.sum +++ /dev/null @@ -1,19 +0,0 @@ -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/metric/metric.go b/metric/metric.go deleted file mode 100644 index d8c5a6b3f35..00000000000 --- a/metric/metric.go +++ /dev/null @@ -1,538 +0,0 @@ -// 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 metric // import "go.opentelemetry.io/otel/metric" - -import ( - "context" - - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/metric/number" - "go.opentelemetry.io/otel/metric/sdkapi" -) - -// MeterProvider supports named Meter instances. -type MeterProvider interface { - // Meter creates an implementation of the Meter interface. - // The instrumentationName must be the name of the library providing - // instrumentation. This name may be the same as the instrumented code - // only if that code provides built-in instrumentation. If the - // instrumentationName is empty, then a implementation defined default - // name will be used instead. - Meter(instrumentationName string, opts ...MeterOption) Meter -} - -// Meter is the creator of metric instruments. -// -// An uninitialized Meter is a no-op implementation. -type Meter struct { - impl sdkapi.MeterImpl -} - -// WrapMeterImpl constructs a `Meter` implementation from a -// `MeterImpl` implementation. -func WrapMeterImpl(impl sdkapi.MeterImpl) Meter { - return Meter{ - impl: impl, - } -} - -// Measurement is used for reporting a synchronous batch of metric -// values. Instances of this type should be created by synchronous -// instruments (e.g., Int64Counter.Measurement()). -// -// Note: This is an alias because it is a first-class member of the -// API but is also part of the lower-level sdkapi interface. -type Measurement = sdkapi.Measurement - -// Observation is used for reporting an asynchronous batch of metric -// values. Instances of this type should be created by asynchronous -// instruments (e.g., Int64GaugeObserver.Observation()). -// -// Note: This is an alias because it is a first-class member of the -// API but is also part of the lower-level sdkapi interface. -type Observation = sdkapi.Observation - -// RecordBatch atomically records a batch of measurements. -func (m Meter) RecordBatch(ctx context.Context, ls []attribute.KeyValue, ms ...Measurement) { - if m.impl == nil { - return - } - m.impl.RecordBatch(ctx, ls, ms...) -} - -// NewBatchObserver creates a new BatchObserver that supports -// making batches of observations for multiple instruments. -func (m Meter) NewBatchObserver(callback BatchObserverFunc) BatchObserver { - return BatchObserver{ - meter: m, - runner: newBatchAsyncRunner(callback), - } -} - -// NewInt64Counter creates a new integer Counter instrument with the -// given name, customized with options. May return an error if the -// name is invalid (e.g., empty) or improperly registered (e.g., -// duplicate registration). -func (m Meter) NewInt64Counter(name string, options ...InstrumentOption) (Int64Counter, error) { - return wrapInt64CounterInstrument( - m.newSync(name, sdkapi.CounterInstrumentKind, number.Int64Kind, options)) -} - -// NewFloat64Counter creates a new floating point Counter with the -// given name, customized with options. May return an error if the -// name is invalid (e.g., empty) or improperly registered (e.g., -// duplicate registration). -func (m Meter) NewFloat64Counter(name string, options ...InstrumentOption) (Float64Counter, error) { - return wrapFloat64CounterInstrument( - m.newSync(name, sdkapi.CounterInstrumentKind, number.Float64Kind, options)) -} - -// NewInt64UpDownCounter creates a new integer UpDownCounter instrument with the -// given name, customized with options. May return an error if the -// name is invalid (e.g., empty) or improperly registered (e.g., -// duplicate registration). -func (m Meter) NewInt64UpDownCounter(name string, options ...InstrumentOption) (Int64UpDownCounter, error) { - return wrapInt64UpDownCounterInstrument( - m.newSync(name, sdkapi.UpDownCounterInstrumentKind, number.Int64Kind, options)) -} - -// NewFloat64UpDownCounter creates a new floating point UpDownCounter with the -// given name, customized with options. May return an error if the -// name is invalid (e.g., empty) or improperly registered (e.g., -// duplicate registration). -func (m Meter) NewFloat64UpDownCounter(name string, options ...InstrumentOption) (Float64UpDownCounter, error) { - return wrapFloat64UpDownCounterInstrument( - m.newSync(name, sdkapi.UpDownCounterInstrumentKind, number.Float64Kind, options)) -} - -// NewInt64Histogram creates a new integer Histogram instrument with the -// given name, customized with options. May return an error if the -// name is invalid (e.g., empty) or improperly registered (e.g., -// duplicate registration). -func (m Meter) NewInt64Histogram(name string, opts ...InstrumentOption) (Int64Histogram, error) { - return wrapInt64HistogramInstrument( - m.newSync(name, sdkapi.HistogramInstrumentKind, number.Int64Kind, opts)) -} - -// NewFloat64Histogram creates a new floating point Histogram with the -// given name, customized with options. May return an error if the -// name is invalid (e.g., empty) or improperly registered (e.g., -// duplicate registration). -func (m Meter) NewFloat64Histogram(name string, opts ...InstrumentOption) (Float64Histogram, error) { - return wrapFloat64HistogramInstrument( - m.newSync(name, sdkapi.HistogramInstrumentKind, number.Float64Kind, opts)) -} - -// NewInt64GaugeObserver creates a new integer GaugeObserver instrument -// with the given name, running a given callback, and customized with -// options. May return an error if the name is invalid (e.g., empty) -// or improperly registered (e.g., duplicate registration). -func (m Meter) NewInt64GaugeObserver(name string, callback Int64ObserverFunc, opts ...InstrumentOption) (Int64GaugeObserver, error) { - if callback == nil { - return wrapInt64GaugeObserverInstrument(sdkapi.NewNoopAsyncInstrument(), nil) - } - return wrapInt64GaugeObserverInstrument( - m.newAsync(name, sdkapi.GaugeObserverInstrumentKind, number.Int64Kind, opts, - newInt64AsyncRunner(callback))) -} - -// NewFloat64GaugeObserver creates a new floating point GaugeObserver with -// the given name, running a given callback, and customized with -// options. May return an error if the name is invalid (e.g., empty) -// or improperly registered (e.g., duplicate registration). -func (m Meter) NewFloat64GaugeObserver(name string, callback Float64ObserverFunc, opts ...InstrumentOption) (Float64GaugeObserver, error) { - if callback == nil { - return wrapFloat64GaugeObserverInstrument(sdkapi.NewNoopAsyncInstrument(), nil) - } - return wrapFloat64GaugeObserverInstrument( - m.newAsync(name, sdkapi.GaugeObserverInstrumentKind, number.Float64Kind, opts, - newFloat64AsyncRunner(callback))) -} - -// NewInt64CounterObserver creates a new integer CounterObserver instrument -// with the given name, running a given callback, and customized with -// options. May return an error if the name is invalid (e.g., empty) -// or improperly registered (e.g., duplicate registration). -func (m Meter) NewInt64CounterObserver(name string, callback Int64ObserverFunc, opts ...InstrumentOption) (Int64CounterObserver, error) { - if callback == nil { - return wrapInt64CounterObserverInstrument(sdkapi.NewNoopAsyncInstrument(), nil) - } - return wrapInt64CounterObserverInstrument( - m.newAsync(name, sdkapi.CounterObserverInstrumentKind, number.Int64Kind, opts, - newInt64AsyncRunner(callback))) -} - -// NewFloat64CounterObserver creates a new floating point CounterObserver with -// the given name, running a given callback, and customized with -// options. May return an error if the name is invalid (e.g., empty) -// or improperly registered (e.g., duplicate registration). -func (m Meter) NewFloat64CounterObserver(name string, callback Float64ObserverFunc, opts ...InstrumentOption) (Float64CounterObserver, error) { - if callback == nil { - return wrapFloat64CounterObserverInstrument(sdkapi.NewNoopAsyncInstrument(), nil) - } - return wrapFloat64CounterObserverInstrument( - m.newAsync(name, sdkapi.CounterObserverInstrumentKind, number.Float64Kind, opts, - newFloat64AsyncRunner(callback))) -} - -// NewInt64UpDownCounterObserver creates a new integer UpDownCounterObserver instrument -// with the given name, running a given callback, and customized with -// options. May return an error if the name is invalid (e.g., empty) -// or improperly registered (e.g., duplicate registration). -func (m Meter) NewInt64UpDownCounterObserver(name string, callback Int64ObserverFunc, opts ...InstrumentOption) (Int64UpDownCounterObserver, error) { - if callback == nil { - return wrapInt64UpDownCounterObserverInstrument(sdkapi.NewNoopAsyncInstrument(), nil) - } - return wrapInt64UpDownCounterObserverInstrument( - m.newAsync(name, sdkapi.UpDownCounterObserverInstrumentKind, number.Int64Kind, opts, - newInt64AsyncRunner(callback))) -} - -// NewFloat64UpDownCounterObserver creates a new floating point UpDownCounterObserver with -// the given name, running a given callback, and customized with -// options. May return an error if the name is invalid (e.g., empty) -// or improperly registered (e.g., duplicate registration). -func (m Meter) NewFloat64UpDownCounterObserver(name string, callback Float64ObserverFunc, opts ...InstrumentOption) (Float64UpDownCounterObserver, error) { - if callback == nil { - return wrapFloat64UpDownCounterObserverInstrument(sdkapi.NewNoopAsyncInstrument(), nil) - } - return wrapFloat64UpDownCounterObserverInstrument( - m.newAsync(name, sdkapi.UpDownCounterObserverInstrumentKind, number.Float64Kind, opts, - newFloat64AsyncRunner(callback))) -} - -// NewInt64GaugeObserver creates a new integer GaugeObserver instrument -// with the given name, running in a batch callback, and customized with -// options. May return an error if the name is invalid (e.g., empty) -// or improperly registered (e.g., duplicate registration). -func (b BatchObserver) NewInt64GaugeObserver(name string, opts ...InstrumentOption) (Int64GaugeObserver, error) { - if b.runner == nil { - return wrapInt64GaugeObserverInstrument(sdkapi.NewNoopAsyncInstrument(), nil) - } - return wrapInt64GaugeObserverInstrument( - b.meter.newAsync(name, sdkapi.GaugeObserverInstrumentKind, number.Int64Kind, opts, b.runner)) -} - -// NewFloat64GaugeObserver creates a new floating point GaugeObserver with -// the given name, running in a batch callback, and customized with -// options. May return an error if the name is invalid (e.g., empty) -// or improperly registered (e.g., duplicate registration). -func (b BatchObserver) NewFloat64GaugeObserver(name string, opts ...InstrumentOption) (Float64GaugeObserver, error) { - if b.runner == nil { - return wrapFloat64GaugeObserverInstrument(sdkapi.NewNoopAsyncInstrument(), nil) - } - return wrapFloat64GaugeObserverInstrument( - b.meter.newAsync(name, sdkapi.GaugeObserverInstrumentKind, number.Float64Kind, opts, - b.runner)) -} - -// NewInt64CounterObserver creates a new integer CounterObserver instrument -// with the given name, running in a batch callback, and customized with -// options. May return an error if the name is invalid (e.g., empty) -// or improperly registered (e.g., duplicate registration). -func (b BatchObserver) NewInt64CounterObserver(name string, opts ...InstrumentOption) (Int64CounterObserver, error) { - if b.runner == nil { - return wrapInt64CounterObserverInstrument(sdkapi.NewNoopAsyncInstrument(), nil) - } - return wrapInt64CounterObserverInstrument( - b.meter.newAsync(name, sdkapi.CounterObserverInstrumentKind, number.Int64Kind, opts, b.runner)) -} - -// NewFloat64CounterObserver creates a new floating point CounterObserver with -// the given name, running in a batch callback, and customized with -// options. May return an error if the name is invalid (e.g., empty) -// or improperly registered (e.g., duplicate registration). -func (b BatchObserver) NewFloat64CounterObserver(name string, opts ...InstrumentOption) (Float64CounterObserver, error) { - if b.runner == nil { - return wrapFloat64CounterObserverInstrument(sdkapi.NewNoopAsyncInstrument(), nil) - } - return wrapFloat64CounterObserverInstrument( - b.meter.newAsync(name, sdkapi.CounterObserverInstrumentKind, number.Float64Kind, opts, - b.runner)) -} - -// NewInt64UpDownCounterObserver creates a new integer UpDownCounterObserver instrument -// with the given name, running in a batch callback, and customized with -// options. May return an error if the name is invalid (e.g., empty) -// or improperly registered (e.g., duplicate registration). -func (b BatchObserver) NewInt64UpDownCounterObserver(name string, opts ...InstrumentOption) (Int64UpDownCounterObserver, error) { - if b.runner == nil { - return wrapInt64UpDownCounterObserverInstrument(sdkapi.NewNoopAsyncInstrument(), nil) - } - return wrapInt64UpDownCounterObserverInstrument( - b.meter.newAsync(name, sdkapi.UpDownCounterObserverInstrumentKind, number.Int64Kind, opts, b.runner)) -} - -// NewFloat64UpDownCounterObserver creates a new floating point UpDownCounterObserver with -// the given name, running in a batch callback, and customized with -// options. May return an error if the name is invalid (e.g., empty) -// or improperly registered (e.g., duplicate registration). -func (b BatchObserver) NewFloat64UpDownCounterObserver(name string, opts ...InstrumentOption) (Float64UpDownCounterObserver, error) { - if b.runner == nil { - return wrapFloat64UpDownCounterObserverInstrument(sdkapi.NewNoopAsyncInstrument(), nil) - } - return wrapFloat64UpDownCounterObserverInstrument( - b.meter.newAsync(name, sdkapi.UpDownCounterObserverInstrumentKind, number.Float64Kind, opts, - b.runner)) -} - -// MeterImpl returns the underlying MeterImpl of this Meter. -func (m Meter) MeterImpl() sdkapi.MeterImpl { - return m.impl -} - -// newAsync constructs one new asynchronous instrument. -func (m Meter) newAsync( - name string, - mkind sdkapi.InstrumentKind, - nkind number.Kind, - opts []InstrumentOption, - runner sdkapi.AsyncRunner, -) ( - sdkapi.AsyncImpl, - error, -) { - if m.impl == nil { - return sdkapi.NewNoopAsyncInstrument(), nil - } - cfg := NewInstrumentConfig(opts...) - desc := sdkapi.NewDescriptor(name, mkind, nkind, cfg.description, cfg.unit) - return m.impl.NewAsyncInstrument(desc, runner) -} - -// newSync constructs one new synchronous instrument. -func (m Meter) newSync( - name string, - metricKind sdkapi.InstrumentKind, - numberKind number.Kind, - opts []InstrumentOption, -) ( - sdkapi.SyncImpl, - error, -) { - if m.impl == nil { - return sdkapi.NewNoopSyncInstrument(), nil - } - cfg := NewInstrumentConfig(opts...) - desc := sdkapi.NewDescriptor(name, metricKind, numberKind, cfg.description, cfg.unit) - return m.impl.NewSyncInstrument(desc) -} - -// MeterMust is a wrapper for Meter interfaces that panics when any -// instrument constructor encounters an error. -type MeterMust struct { - meter Meter -} - -// BatchObserverMust is a wrapper for BatchObserver that panics when -// any instrument constructor encounters an error. -type BatchObserverMust struct { - batch BatchObserver -} - -// Must constructs a MeterMust implementation from a Meter, allowing -// the application to panic when any instrument constructor yields an -// error. -func Must(meter Meter) MeterMust { - return MeterMust{meter: meter} -} - -// NewInt64Counter calls `Meter.NewInt64Counter` and returns the -// instrument, panicking if it encounters an error. -func (mm MeterMust) NewInt64Counter(name string, cos ...InstrumentOption) Int64Counter { - if inst, err := mm.meter.NewInt64Counter(name, cos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewFloat64Counter calls `Meter.NewFloat64Counter` and returns the -// instrument, panicking if it encounters an error. -func (mm MeterMust) NewFloat64Counter(name string, cos ...InstrumentOption) Float64Counter { - if inst, err := mm.meter.NewFloat64Counter(name, cos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewInt64UpDownCounter calls `Meter.NewInt64UpDownCounter` and returns the -// instrument, panicking if it encounters an error. -func (mm MeterMust) NewInt64UpDownCounter(name string, cos ...InstrumentOption) Int64UpDownCounter { - if inst, err := mm.meter.NewInt64UpDownCounter(name, cos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewFloat64UpDownCounter calls `Meter.NewFloat64UpDownCounter` and returns the -// instrument, panicking if it encounters an error. -func (mm MeterMust) NewFloat64UpDownCounter(name string, cos ...InstrumentOption) Float64UpDownCounter { - if inst, err := mm.meter.NewFloat64UpDownCounter(name, cos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewInt64Histogram calls `Meter.NewInt64Histogram` and returns the -// instrument, panicking if it encounters an error. -func (mm MeterMust) NewInt64Histogram(name string, mos ...InstrumentOption) Int64Histogram { - if inst, err := mm.meter.NewInt64Histogram(name, mos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewFloat64Histogram calls `Meter.NewFloat64Histogram` and returns the -// instrument, panicking if it encounters an error. -func (mm MeterMust) NewFloat64Histogram(name string, mos ...InstrumentOption) Float64Histogram { - if inst, err := mm.meter.NewFloat64Histogram(name, mos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewInt64GaugeObserver calls `Meter.NewInt64GaugeObserver` and -// returns the instrument, panicking if it encounters an error. -func (mm MeterMust) NewInt64GaugeObserver(name string, callback Int64ObserverFunc, oos ...InstrumentOption) Int64GaugeObserver { - if inst, err := mm.meter.NewInt64GaugeObserver(name, callback, oos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewFloat64GaugeObserver calls `Meter.NewFloat64GaugeObserver` and -// returns the instrument, panicking if it encounters an error. -func (mm MeterMust) NewFloat64GaugeObserver(name string, callback Float64ObserverFunc, oos ...InstrumentOption) Float64GaugeObserver { - if inst, err := mm.meter.NewFloat64GaugeObserver(name, callback, oos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewInt64CounterObserver calls `Meter.NewInt64CounterObserver` and -// returns the instrument, panicking if it encounters an error. -func (mm MeterMust) NewInt64CounterObserver(name string, callback Int64ObserverFunc, oos ...InstrumentOption) Int64CounterObserver { - if inst, err := mm.meter.NewInt64CounterObserver(name, callback, oos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewFloat64CounterObserver calls `Meter.NewFloat64CounterObserver` and -// returns the instrument, panicking if it encounters an error. -func (mm MeterMust) NewFloat64CounterObserver(name string, callback Float64ObserverFunc, oos ...InstrumentOption) Float64CounterObserver { - if inst, err := mm.meter.NewFloat64CounterObserver(name, callback, oos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewInt64UpDownCounterObserver calls `Meter.NewInt64UpDownCounterObserver` and -// returns the instrument, panicking if it encounters an error. -func (mm MeterMust) NewInt64UpDownCounterObserver(name string, callback Int64ObserverFunc, oos ...InstrumentOption) Int64UpDownCounterObserver { - if inst, err := mm.meter.NewInt64UpDownCounterObserver(name, callback, oos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewFloat64UpDownCounterObserver calls `Meter.NewFloat64UpDownCounterObserver` and -// returns the instrument, panicking if it encounters an error. -func (mm MeterMust) NewFloat64UpDownCounterObserver(name string, callback Float64ObserverFunc, oos ...InstrumentOption) Float64UpDownCounterObserver { - if inst, err := mm.meter.NewFloat64UpDownCounterObserver(name, callback, oos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewBatchObserver returns a wrapper around BatchObserver that panics -// when any instrument constructor returns an error. -func (mm MeterMust) NewBatchObserver(callback BatchObserverFunc) BatchObserverMust { - return BatchObserverMust{ - batch: mm.meter.NewBatchObserver(callback), - } -} - -// NewInt64GaugeObserver calls `BatchObserver.NewInt64GaugeObserver` and -// returns the instrument, panicking if it encounters an error. -func (bm BatchObserverMust) NewInt64GaugeObserver(name string, oos ...InstrumentOption) Int64GaugeObserver { - if inst, err := bm.batch.NewInt64GaugeObserver(name, oos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewFloat64GaugeObserver calls `BatchObserver.NewFloat64GaugeObserver` and -// returns the instrument, panicking if it encounters an error. -func (bm BatchObserverMust) NewFloat64GaugeObserver(name string, oos ...InstrumentOption) Float64GaugeObserver { - if inst, err := bm.batch.NewFloat64GaugeObserver(name, oos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewInt64CounterObserver calls `BatchObserver.NewInt64CounterObserver` and -// returns the instrument, panicking if it encounters an error. -func (bm BatchObserverMust) NewInt64CounterObserver(name string, oos ...InstrumentOption) Int64CounterObserver { - if inst, err := bm.batch.NewInt64CounterObserver(name, oos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewFloat64CounterObserver calls `BatchObserver.NewFloat64CounterObserver` and -// returns the instrument, panicking if it encounters an error. -func (bm BatchObserverMust) NewFloat64CounterObserver(name string, oos ...InstrumentOption) Float64CounterObserver { - if inst, err := bm.batch.NewFloat64CounterObserver(name, oos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewInt64UpDownCounterObserver calls `BatchObserver.NewInt64UpDownCounterObserver` and -// returns the instrument, panicking if it encounters an error. -func (bm BatchObserverMust) NewInt64UpDownCounterObserver(name string, oos ...InstrumentOption) Int64UpDownCounterObserver { - if inst, err := bm.batch.NewInt64UpDownCounterObserver(name, oos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewFloat64UpDownCounterObserver calls `BatchObserver.NewFloat64UpDownCounterObserver` and -// returns the instrument, panicking if it encounters an error. -func (bm BatchObserverMust) NewFloat64UpDownCounterObserver(name string, oos ...InstrumentOption) Float64UpDownCounterObserver { - if inst, err := bm.batch.NewFloat64UpDownCounterObserver(name, oos...); err != nil { - panic(err) - } else { - return inst - } -} diff --git a/metric/metric_instrument.go b/metric/metric_instrument.go deleted file mode 100644 index 2da24c8f211..00000000000 --- a/metric/metric_instrument.go +++ /dev/null @@ -1,464 +0,0 @@ -// 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 metric // import "go.opentelemetry.io/otel/metric" - -import ( - "context" - "errors" - - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/metric/number" - "go.opentelemetry.io/otel/metric/sdkapi" -) - -// ErrSDKReturnedNilImpl is returned when a new `MeterImpl` returns nil. -var ErrSDKReturnedNilImpl = errors.New("SDK returned a nil implementation") - -// Int64ObserverFunc is a type of callback that integral -// observers run. -type Int64ObserverFunc func(context.Context, Int64ObserverResult) - -// Float64ObserverFunc is a type of callback that floating point -// observers run. -type Float64ObserverFunc func(context.Context, Float64ObserverResult) - -// BatchObserverFunc is a callback argument for use with any -// Observer instrument that will be reported as a batch of -// observations. -type BatchObserverFunc func(context.Context, BatchObserverResult) - -// Int64ObserverResult is passed to an observer callback to capture -// observations for one asynchronous integer metric instrument. -type Int64ObserverResult struct { - instrument sdkapi.AsyncImpl - function func([]attribute.KeyValue, ...Observation) -} - -// Float64ObserverResult is passed to an observer callback to capture -// observations for one asynchronous floating point metric instrument. -type Float64ObserverResult struct { - instrument sdkapi.AsyncImpl - function func([]attribute.KeyValue, ...Observation) -} - -// BatchObserverResult is passed to a batch observer callback to -// capture observations for multiple asynchronous instruments. -type BatchObserverResult struct { - function func([]attribute.KeyValue, ...Observation) -} - -// Observe captures a single integer value from the associated -// instrument callback, with the given labels. -func (ir Int64ObserverResult) Observe(value int64, labels ...attribute.KeyValue) { - ir.function(labels, sdkapi.NewObservation(ir.instrument, number.NewInt64Number(value))) -} - -// Observe captures a single floating point value from the associated -// instrument callback, with the given labels. -func (fr Float64ObserverResult) Observe(value float64, labels ...attribute.KeyValue) { - fr.function(labels, sdkapi.NewObservation(fr.instrument, number.NewFloat64Number(value))) -} - -// Observe captures a multiple observations from the associated batch -// instrument callback, with the given labels. -func (br BatchObserverResult) Observe(labels []attribute.KeyValue, obs ...Observation) { - br.function(labels, obs...) -} - -var _ sdkapi.AsyncSingleRunner = (*Int64ObserverFunc)(nil) -var _ sdkapi.AsyncSingleRunner = (*Float64ObserverFunc)(nil) -var _ sdkapi.AsyncBatchRunner = (*BatchObserverFunc)(nil) - -// newInt64AsyncRunner returns a single-observer callback for integer Observer instruments. -func newInt64AsyncRunner(c Int64ObserverFunc) sdkapi.AsyncSingleRunner { - return &c -} - -// newFloat64AsyncRunner returns a single-observer callback for floating point Observer instruments. -func newFloat64AsyncRunner(c Float64ObserverFunc) sdkapi.AsyncSingleRunner { - return &c -} - -// newBatchAsyncRunner returns a batch-observer callback use with multiple Observer instruments. -func newBatchAsyncRunner(c BatchObserverFunc) sdkapi.AsyncBatchRunner { - return &c -} - -// AnyRunner implements AsyncRunner. -func (*Int64ObserverFunc) AnyRunner() {} - -// AnyRunner implements AsyncRunner. -func (*Float64ObserverFunc) AnyRunner() {} - -// AnyRunner implements AsyncRunner. -func (*BatchObserverFunc) AnyRunner() {} - -// Run implements AsyncSingleRunner. -func (i *Int64ObserverFunc) Run(ctx context.Context, impl sdkapi.AsyncImpl, function func([]attribute.KeyValue, ...Observation)) { - (*i)(ctx, Int64ObserverResult{ - instrument: impl, - function: function, - }) -} - -// Run implements AsyncSingleRunner. -func (f *Float64ObserverFunc) Run(ctx context.Context, impl sdkapi.AsyncImpl, function func([]attribute.KeyValue, ...Observation)) { - (*f)(ctx, Float64ObserverResult{ - instrument: impl, - function: function, - }) -} - -// Run implements AsyncBatchRunner. -func (b *BatchObserverFunc) Run(ctx context.Context, function func([]attribute.KeyValue, ...Observation)) { - (*b)(ctx, BatchObserverResult{ - function: function, - }) -} - -// wrapInt64GaugeObserverInstrument converts an AsyncImpl into Int64GaugeObserver. -func wrapInt64GaugeObserverInstrument(asyncInst sdkapi.AsyncImpl, err error) (Int64GaugeObserver, error) { - common, err := checkNewAsync(asyncInst, err) - return Int64GaugeObserver{asyncInstrument: common}, err -} - -// wrapFloat64GaugeObserverInstrument converts an AsyncImpl into Float64GaugeObserver. -func wrapFloat64GaugeObserverInstrument(asyncInst sdkapi.AsyncImpl, err error) (Float64GaugeObserver, error) { - common, err := checkNewAsync(asyncInst, err) - return Float64GaugeObserver{asyncInstrument: common}, err -} - -// wrapInt64CounterObserverInstrument converts an AsyncImpl into Int64CounterObserver. -func wrapInt64CounterObserverInstrument(asyncInst sdkapi.AsyncImpl, err error) (Int64CounterObserver, error) { - common, err := checkNewAsync(asyncInst, err) - return Int64CounterObserver{asyncInstrument: common}, err -} - -// wrapFloat64CounterObserverInstrument converts an AsyncImpl into Float64CounterObserver. -func wrapFloat64CounterObserverInstrument(asyncInst sdkapi.AsyncImpl, err error) (Float64CounterObserver, error) { - common, err := checkNewAsync(asyncInst, err) - return Float64CounterObserver{asyncInstrument: common}, err -} - -// wrapInt64UpDownCounterObserverInstrument converts an AsyncImpl into Int64UpDownCounterObserver. -func wrapInt64UpDownCounterObserverInstrument(asyncInst sdkapi.AsyncImpl, err error) (Int64UpDownCounterObserver, error) { - common, err := checkNewAsync(asyncInst, err) - return Int64UpDownCounterObserver{asyncInstrument: common}, err -} - -// wrapFloat64UpDownCounterObserverInstrument converts an AsyncImpl into Float64UpDownCounterObserver. -func wrapFloat64UpDownCounterObserverInstrument(asyncInst sdkapi.AsyncImpl, err error) (Float64UpDownCounterObserver, error) { - common, err := checkNewAsync(asyncInst, err) - return Float64UpDownCounterObserver{asyncInstrument: common}, err -} - -// BatchObserver represents an Observer callback that can report -// observations for multiple instruments. -type BatchObserver struct { - meter Meter - runner sdkapi.AsyncBatchRunner -} - -// Int64GaugeObserver is a metric that captures a set of int64 values at a -// point in time. -type Int64GaugeObserver struct { - asyncInstrument -} - -// Float64GaugeObserver is a metric that captures a set of float64 values -// at a point in time. -type Float64GaugeObserver struct { - asyncInstrument -} - -// Int64CounterObserver is a metric that captures a precomputed sum of -// int64 values at a point in time. -type Int64CounterObserver struct { - asyncInstrument -} - -// Float64CounterObserver is a metric that captures a precomputed sum of -// float64 values at a point in time. -type Float64CounterObserver struct { - asyncInstrument -} - -// Int64UpDownCounterObserver is a metric that captures a precomputed sum of -// int64 values at a point in time. -type Int64UpDownCounterObserver struct { - asyncInstrument -} - -// Float64UpDownCounterObserver is a metric that captures a precomputed sum of -// float64 values at a point in time. -type Float64UpDownCounterObserver struct { - asyncInstrument -} - -// Observation returns an Observation, a BatchObserverFunc -// argument, for an asynchronous integer instrument. -// This returns an implementation-level object for use by the SDK, -// users should not refer to this. -func (i Int64GaugeObserver) Observation(v int64) Observation { - return sdkapi.NewObservation(i.instrument, number.NewInt64Number(v)) -} - -// Observation returns an Observation, a BatchObserverFunc -// argument, for an asynchronous integer instrument. -// This returns an implementation-level object for use by the SDK, -// users should not refer to this. -func (f Float64GaugeObserver) Observation(v float64) Observation { - return sdkapi.NewObservation(f.instrument, number.NewFloat64Number(v)) -} - -// Observation returns an Observation, a BatchObserverFunc -// argument, for an asynchronous integer instrument. -// This returns an implementation-level object for use by the SDK, -// users should not refer to this. -func (i Int64CounterObserver) Observation(v int64) Observation { - return sdkapi.NewObservation(i.instrument, number.NewInt64Number(v)) -} - -// Observation returns an Observation, a BatchObserverFunc -// argument, for an asynchronous integer instrument. -// This returns an implementation-level object for use by the SDK, -// users should not refer to this. -func (f Float64CounterObserver) Observation(v float64) Observation { - return sdkapi.NewObservation(f.instrument, number.NewFloat64Number(v)) -} - -// Observation returns an Observation, a BatchObserverFunc -// argument, for an asynchronous integer instrument. -// This returns an implementation-level object for use by the SDK, -// users should not refer to this. -func (i Int64UpDownCounterObserver) Observation(v int64) Observation { - return sdkapi.NewObservation(i.instrument, number.NewInt64Number(v)) -} - -// Observation returns an Observation, a BatchObserverFunc -// argument, for an asynchronous integer instrument. -// This returns an implementation-level object for use by the SDK, -// users should not refer to this. -func (f Float64UpDownCounterObserver) Observation(v float64) Observation { - return sdkapi.NewObservation(f.instrument, number.NewFloat64Number(v)) -} - -// syncInstrument contains a SyncImpl. -type syncInstrument struct { - instrument sdkapi.SyncImpl -} - -// asyncInstrument contains a AsyncImpl. -type asyncInstrument struct { - instrument sdkapi.AsyncImpl -} - -// AsyncImpl implements AsyncImpl. -func (a asyncInstrument) AsyncImpl() sdkapi.AsyncImpl { - return a.instrument -} - -// SyncImpl returns the implementation object for synchronous instruments. -func (s syncInstrument) SyncImpl() sdkapi.SyncImpl { - return s.instrument -} - -func (s syncInstrument) float64Measurement(value float64) Measurement { - return sdkapi.NewMeasurement(s.instrument, number.NewFloat64Number(value)) -} - -func (s syncInstrument) int64Measurement(value int64) Measurement { - return sdkapi.NewMeasurement(s.instrument, number.NewInt64Number(value)) -} - -func (s syncInstrument) directRecord(ctx context.Context, number number.Number, labels []attribute.KeyValue) { - s.instrument.RecordOne(ctx, number, labels) -} - -// checkNewAsync receives an AsyncImpl and potential -// error, and returns the same types, checking for and ensuring that -// the returned interface is not nil. -func checkNewAsync(instrument sdkapi.AsyncImpl, err error) (asyncInstrument, error) { - if instrument == nil { - if err == nil { - err = ErrSDKReturnedNilImpl - } - instrument = sdkapi.NewNoopAsyncInstrument() - } - return asyncInstrument{ - instrument: instrument, - }, err -} - -// checkNewSync receives an SyncImpl and potential -// error, and returns the same types, checking for and ensuring that -// the returned interface is not nil. -func checkNewSync(instrument sdkapi.SyncImpl, err error) (syncInstrument, error) { - if instrument == nil { - if err == nil { - err = ErrSDKReturnedNilImpl - } - // Note: an alternate behavior would be to synthesize a new name - // or group all duplicately-named instruments of a certain type - // together and use a tag for the original name, e.g., - // name = 'invalid.counter.int64' - // label = 'original-name=duplicate-counter-name' - instrument = sdkapi.NewNoopSyncInstrument() - } - return syncInstrument{ - instrument: instrument, - }, err -} - -// wrapInt64CounterInstrument converts a SyncImpl into Int64Counter. -func wrapInt64CounterInstrument(syncInst sdkapi.SyncImpl, err error) (Int64Counter, error) { - common, err := checkNewSync(syncInst, err) - return Int64Counter{syncInstrument: common}, err -} - -// wrapFloat64CounterInstrument converts a SyncImpl into Float64Counter. -func wrapFloat64CounterInstrument(syncInst sdkapi.SyncImpl, err error) (Float64Counter, error) { - common, err := checkNewSync(syncInst, err) - return Float64Counter{syncInstrument: common}, err -} - -// wrapInt64UpDownCounterInstrument converts a SyncImpl into Int64UpDownCounter. -func wrapInt64UpDownCounterInstrument(syncInst sdkapi.SyncImpl, err error) (Int64UpDownCounter, error) { - common, err := checkNewSync(syncInst, err) - return Int64UpDownCounter{syncInstrument: common}, err -} - -// wrapFloat64UpDownCounterInstrument converts a SyncImpl into Float64UpDownCounter. -func wrapFloat64UpDownCounterInstrument(syncInst sdkapi.SyncImpl, err error) (Float64UpDownCounter, error) { - common, err := checkNewSync(syncInst, err) - return Float64UpDownCounter{syncInstrument: common}, err -} - -// wrapInt64HistogramInstrument converts a SyncImpl into Int64Histogram. -func wrapInt64HistogramInstrument(syncInst sdkapi.SyncImpl, err error) (Int64Histogram, error) { - common, err := checkNewSync(syncInst, err) - return Int64Histogram{syncInstrument: common}, err -} - -// wrapFloat64HistogramInstrument converts a SyncImpl into Float64Histogram. -func wrapFloat64HistogramInstrument(syncInst sdkapi.SyncImpl, err error) (Float64Histogram, error) { - common, err := checkNewSync(syncInst, err) - return Float64Histogram{syncInstrument: common}, err -} - -// Float64Counter is a metric that accumulates float64 values. -type Float64Counter struct { - syncInstrument -} - -// Int64Counter is a metric that accumulates int64 values. -type Int64Counter struct { - syncInstrument -} - -// Measurement creates a Measurement object to use with batch -// recording. -func (c Float64Counter) Measurement(value float64) Measurement { - return c.float64Measurement(value) -} - -// Measurement creates a Measurement object to use with batch -// recording. -func (c Int64Counter) Measurement(value int64) Measurement { - return c.int64Measurement(value) -} - -// Add adds the value to the counter's sum. The labels should contain -// the keys and values to be associated with this value. -func (c Float64Counter) Add(ctx context.Context, value float64, labels ...attribute.KeyValue) { - c.directRecord(ctx, number.NewFloat64Number(value), labels) -} - -// Add adds the value to the counter's sum. The labels should contain -// the keys and values to be associated with this value. -func (c Int64Counter) Add(ctx context.Context, value int64, labels ...attribute.KeyValue) { - c.directRecord(ctx, number.NewInt64Number(value), labels) -} - -// Float64UpDownCounter is a metric instrument that sums floating -// point values. -type Float64UpDownCounter struct { - syncInstrument -} - -// Int64UpDownCounter is a metric instrument that sums integer values. -type Int64UpDownCounter struct { - syncInstrument -} - -// Measurement creates a Measurement object to use with batch -// recording. -func (c Float64UpDownCounter) Measurement(value float64) Measurement { - return c.float64Measurement(value) -} - -// Measurement creates a Measurement object to use with batch -// recording. -func (c Int64UpDownCounter) Measurement(value int64) Measurement { - return c.int64Measurement(value) -} - -// Add adds the value to the counter's sum. The labels should contain -// the keys and values to be associated with this value. -func (c Float64UpDownCounter) Add(ctx context.Context, value float64, labels ...attribute.KeyValue) { - c.directRecord(ctx, number.NewFloat64Number(value), labels) -} - -// Add adds the value to the counter's sum. The labels should contain -// the keys and values to be associated with this value. -func (c Int64UpDownCounter) Add(ctx context.Context, value int64, labels ...attribute.KeyValue) { - c.directRecord(ctx, number.NewInt64Number(value), labels) -} - -// Float64Histogram is a metric that records float64 values. -type Float64Histogram struct { - syncInstrument -} - -// Int64Histogram is a metric that records int64 values. -type Int64Histogram struct { - syncInstrument -} - -// Measurement creates a Measurement object to use with batch -// recording. -func (c Float64Histogram) Measurement(value float64) Measurement { - return c.float64Measurement(value) -} - -// Measurement creates a Measurement object to use with batch -// recording. -func (c Int64Histogram) Measurement(value int64) Measurement { - return c.int64Measurement(value) -} - -// Record adds a new value to the list of Histogram's records. The -// labels should contain the keys and values to be associated with -// this value. -func (c Float64Histogram) Record(ctx context.Context, value float64, labels ...attribute.KeyValue) { - c.directRecord(ctx, number.NewFloat64Number(value), labels) -} - -// Record adds a new value to the Histogram's distribution. The -// labels should contain the keys and values to be associated with -// this value. -func (c Int64Histogram) Record(ctx context.Context, value int64, labels ...attribute.KeyValue) { - c.directRecord(ctx, number.NewInt64Number(value), labels) -} diff --git a/metric/metric_test.go b/metric/metric_test.go deleted file mode 100644 index ab8e916b829..00000000000 --- a/metric/metric_test.go +++ /dev/null @@ -1,497 +0,0 @@ -// 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 metric_test - -import ( - "context" - "errors" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/metric" - "go.opentelemetry.io/otel/metric/metrictest" - "go.opentelemetry.io/otel/metric/number" - "go.opentelemetry.io/otel/metric/sdkapi" - "go.opentelemetry.io/otel/metric/unit" -) - -var Must = metric.Must - -var ( - syncKinds = []sdkapi.InstrumentKind{ - sdkapi.HistogramInstrumentKind, - sdkapi.CounterInstrumentKind, - sdkapi.UpDownCounterInstrumentKind, - } - asyncKinds = []sdkapi.InstrumentKind{ - sdkapi.GaugeObserverInstrumentKind, - sdkapi.CounterObserverInstrumentKind, - sdkapi.UpDownCounterObserverInstrumentKind, - } - addingKinds = []sdkapi.InstrumentKind{ - sdkapi.CounterInstrumentKind, - sdkapi.UpDownCounterInstrumentKind, - sdkapi.CounterObserverInstrumentKind, - sdkapi.UpDownCounterObserverInstrumentKind, - } - groupingKinds = []sdkapi.InstrumentKind{ - sdkapi.HistogramInstrumentKind, - sdkapi.GaugeObserverInstrumentKind, - } - - monotonicKinds = []sdkapi.InstrumentKind{ - sdkapi.CounterInstrumentKind, - sdkapi.CounterObserverInstrumentKind, - } - - nonMonotonicKinds = []sdkapi.InstrumentKind{ - sdkapi.UpDownCounterInstrumentKind, - sdkapi.UpDownCounterObserverInstrumentKind, - sdkapi.HistogramInstrumentKind, - sdkapi.GaugeObserverInstrumentKind, - } - - precomputedSumKinds = []sdkapi.InstrumentKind{ - sdkapi.CounterObserverInstrumentKind, - sdkapi.UpDownCounterObserverInstrumentKind, - } - - nonPrecomputedSumKinds = []sdkapi.InstrumentKind{ - sdkapi.CounterInstrumentKind, - sdkapi.UpDownCounterInstrumentKind, - sdkapi.HistogramInstrumentKind, - sdkapi.GaugeObserverInstrumentKind, - } -) - -func TestSynchronous(t *testing.T) { - for _, k := range syncKinds { - require.True(t, k.Synchronous()) - require.False(t, k.Asynchronous()) - } - for _, k := range asyncKinds { - require.True(t, k.Asynchronous()) - require.False(t, k.Synchronous()) - } -} - -func TestGrouping(t *testing.T) { - for _, k := range groupingKinds { - require.True(t, k.Grouping()) - require.False(t, k.Adding()) - } - for _, k := range addingKinds { - require.True(t, k.Adding()) - require.False(t, k.Grouping()) - } -} - -func TestMonotonic(t *testing.T) { - for _, k := range monotonicKinds { - require.True(t, k.Monotonic()) - } - for _, k := range nonMonotonicKinds { - require.False(t, k.Monotonic()) - } -} - -func TestPrecomputedSum(t *testing.T) { - for _, k := range precomputedSumKinds { - require.True(t, k.PrecomputedSum()) - } - for _, k := range nonPrecomputedSumKinds { - require.False(t, k.PrecomputedSum()) - } -} - -func checkSyncBatches(ctx context.Context, t *testing.T, labels []attribute.KeyValue, provider *metrictest.MeterProvider, nkind number.Kind, mkind sdkapi.InstrumentKind, instrument sdkapi.InstrumentImpl, expected ...float64) { - t.Helper() - - batchesCount := len(provider.MeasurementBatches) - if len(provider.MeasurementBatches) != len(expected) { - t.Errorf("Expected %d recorded measurement batches, got %d", batchesCount, len(provider.MeasurementBatches)) - } - recorded := metrictest.AsStructs(provider.MeasurementBatches) - - for i, batch := range provider.MeasurementBatches { - if len(batch.Measurements) != 1 { - t.Errorf("Expected 1 measurement in batch %d, got %d", i, len(batch.Measurements)) - } - - measurement := batch.Measurements[0] - descriptor := measurement.Instrument.Descriptor() - - expected := metrictest.Measured{ - Name: descriptor.Name(), - Library: metrictest.Library{ - InstrumentationName: "apitest", - }, - Labels: metrictest.LabelsToMap(labels...), - Number: metrictest.ResolveNumberByKind(t, nkind, expected[i]), - } - require.Equal(t, expected, recorded[i]) - } -} - -func TestOptions(t *testing.T) { - type testcase struct { - name string - opts []metric.InstrumentOption - desc string - unit unit.Unit - } - testcases := []testcase{ - { - name: "no opts", - opts: nil, - desc: "", - unit: "", - }, - { - name: "description", - opts: []metric.InstrumentOption{ - metric.WithDescription("stuff"), - }, - desc: "stuff", - unit: "", - }, - { - name: "description override", - opts: []metric.InstrumentOption{ - metric.WithDescription("stuff"), - metric.WithDescription("things"), - }, - desc: "things", - unit: "", - }, - { - name: "unit", - opts: []metric.InstrumentOption{ - metric.WithUnit("s"), - }, - desc: "", - unit: "s", - }, - { - name: "description override", - opts: []metric.InstrumentOption{ - metric.WithDescription("stuff"), - metric.WithDescription("things"), - }, - desc: "things", - unit: "", - }, - { - name: "unit", - opts: []metric.InstrumentOption{ - metric.WithUnit("s"), - }, - desc: "", - unit: "s", - }, - - { - name: "unit override", - opts: []metric.InstrumentOption{ - metric.WithUnit("s"), - metric.WithUnit("h"), - }, - desc: "", - unit: "h", - }, - { - name: "all", - opts: []metric.InstrumentOption{ - metric.WithDescription("stuff"), - metric.WithUnit("s"), - }, - desc: "stuff", - unit: "s", - }, - } - for idx, tt := range testcases { - t.Logf("Testing counter case %s (%d)", tt.name, idx) - cfg := metric.NewInstrumentConfig(tt.opts...) - if diff := cmp.Diff(cfg.Description(), tt.desc); diff != "" { - t.Errorf("Compare Description: -got +want %s", diff) - } - if diff := cmp.Diff(cfg.Unit(), tt.unit); diff != "" { - t.Errorf("Compare Unit: -got +want %s", diff) - } - } -} -func testPair() (*metrictest.MeterProvider, metric.Meter) { - provider := metrictest.NewMeterProvider() - return provider, provider.Meter("apitest") -} - -func TestCounter(t *testing.T) { - // N.B. the API does not check for negative - // values, that's the SDK's responsibility. - t.Run("float64 counter", func(t *testing.T) { - provider, meter := testPair() - c := Must(meter).NewFloat64Counter("test.counter.float") - ctx := context.Background() - labels := []attribute.KeyValue{attribute.String("A", "B")} - c.Add(ctx, 1994.1, labels...) - meter.RecordBatch(ctx, labels, c.Measurement(42)) - checkSyncBatches(ctx, t, labels, provider, number.Float64Kind, sdkapi.CounterInstrumentKind, c.SyncImpl(), - 1994.1, 42, - ) - }) - t.Run("int64 counter", func(t *testing.T) { - provider, meter := testPair() - c := Must(meter).NewInt64Counter("test.counter.int") - ctx := context.Background() - labels := []attribute.KeyValue{attribute.String("A", "B"), attribute.String("C", "D")} - c.Add(ctx, 42, labels...) - meter.RecordBatch(ctx, labels, c.Measurement(420000)) - checkSyncBatches(ctx, t, labels, provider, number.Int64Kind, sdkapi.CounterInstrumentKind, c.SyncImpl(), - 42, 420000, - ) - - }) - t.Run("int64 updowncounter", func(t *testing.T) { - provider, meter := testPair() - c := Must(meter).NewInt64UpDownCounter("test.updowncounter.int") - ctx := context.Background() - labels := []attribute.KeyValue{attribute.String("A", "B"), attribute.String("C", "D")} - c.Add(ctx, 100, labels...) - meter.RecordBatch(ctx, labels, c.Measurement(42)) - checkSyncBatches(ctx, t, labels, provider, number.Int64Kind, sdkapi.UpDownCounterInstrumentKind, c.SyncImpl(), - 100, 42, - ) - }) - t.Run("float64 updowncounter", func(t *testing.T) { - provider, meter := testPair() - c := Must(meter).NewFloat64UpDownCounter("test.updowncounter.float") - ctx := context.Background() - labels := []attribute.KeyValue{attribute.String("A", "B"), attribute.String("C", "D")} - c.Add(ctx, 100.1, labels...) - meter.RecordBatch(ctx, labels, c.Measurement(-100.1)) - checkSyncBatches(ctx, t, labels, provider, number.Float64Kind, sdkapi.UpDownCounterInstrumentKind, c.SyncImpl(), - 100.1, -100.1, - ) - }) -} - -func TestHistogram(t *testing.T) { - t.Run("float64 histogram", func(t *testing.T) { - provider, meter := testPair() - m := Must(meter).NewFloat64Histogram("test.histogram.float") - ctx := context.Background() - labels := []attribute.KeyValue{} - m.Record(ctx, 42, labels...) - meter.RecordBatch(ctx, labels, m.Measurement(-100.5)) - checkSyncBatches(ctx, t, labels, provider, number.Float64Kind, sdkapi.HistogramInstrumentKind, m.SyncImpl(), - 42, -100.5, - ) - }) - t.Run("int64 histogram", func(t *testing.T) { - provider, meter := testPair() - m := Must(meter).NewInt64Histogram("test.histogram.int") - ctx := context.Background() - labels := []attribute.KeyValue{attribute.Int("I", 1)} - m.Record(ctx, 173, labels...) - meter.RecordBatch(ctx, labels, m.Measurement(0)) - checkSyncBatches(ctx, t, labels, provider, number.Int64Kind, sdkapi.HistogramInstrumentKind, m.SyncImpl(), - 173, 0, - ) - }) -} - -func TestObserverInstruments(t *testing.T) { - t.Run("float gauge", func(t *testing.T) { - labels := []attribute.KeyValue{attribute.String("O", "P")} - provider, meter := testPair() - o := Must(meter).NewFloat64GaugeObserver("test.gauge.float", func(_ context.Context, result metric.Float64ObserverResult) { - result.Observe(42.1, labels...) - }) - provider.RunAsyncInstruments() - checkObserverBatch(t, labels, provider, number.Float64Kind, sdkapi.GaugeObserverInstrumentKind, o.AsyncImpl(), - 42.1, - ) - }) - t.Run("int gauge", func(t *testing.T) { - labels := []attribute.KeyValue{} - provider, meter := testPair() - o := Must(meter).NewInt64GaugeObserver("test.gauge.int", func(_ context.Context, result metric.Int64ObserverResult) { - result.Observe(-142, labels...) - }) - provider.RunAsyncInstruments() - checkObserverBatch(t, labels, provider, number.Int64Kind, sdkapi.GaugeObserverInstrumentKind, o.AsyncImpl(), - -142, - ) - }) - t.Run("float counterobserver", func(t *testing.T) { - labels := []attribute.KeyValue{attribute.String("O", "P")} - provider, meter := testPair() - o := Must(meter).NewFloat64CounterObserver("test.counter.float", func(_ context.Context, result metric.Float64ObserverResult) { - result.Observe(42.1, labels...) - }) - provider.RunAsyncInstruments() - checkObserverBatch(t, labels, provider, number.Float64Kind, sdkapi.CounterObserverInstrumentKind, o.AsyncImpl(), - 42.1, - ) - }) - t.Run("int counterobserver", func(t *testing.T) { - labels := []attribute.KeyValue{} - provider, meter := testPair() - o := Must(meter).NewInt64CounterObserver("test.counter.int", func(_ context.Context, result metric.Int64ObserverResult) { - result.Observe(-142, labels...) - }) - provider.RunAsyncInstruments() - checkObserverBatch(t, labels, provider, number.Int64Kind, sdkapi.CounterObserverInstrumentKind, o.AsyncImpl(), - -142, - ) - }) - t.Run("float updowncounterobserver", func(t *testing.T) { - labels := []attribute.KeyValue{attribute.String("O", "P")} - provider, meter := testPair() - o := Must(meter).NewFloat64UpDownCounterObserver("test.updowncounter.float", func(_ context.Context, result metric.Float64ObserverResult) { - result.Observe(42.1, labels...) - }) - provider.RunAsyncInstruments() - checkObserverBatch(t, labels, provider, number.Float64Kind, sdkapi.UpDownCounterObserverInstrumentKind, o.AsyncImpl(), - 42.1, - ) - }) - t.Run("int updowncounterobserver", func(t *testing.T) { - labels := []attribute.KeyValue{} - provider, meter := testPair() - o := Must(meter).NewInt64UpDownCounterObserver("test..int", func(_ context.Context, result metric.Int64ObserverResult) { - result.Observe(-142, labels...) - }) - provider.RunAsyncInstruments() - checkObserverBatch(t, labels, provider, number.Int64Kind, sdkapi.UpDownCounterObserverInstrumentKind, o.AsyncImpl(), - -142, - ) - }) -} - -func TestBatchObserverInstruments(t *testing.T) { - provider, meter := testPair() - - var obs1 metric.Int64GaugeObserver - var obs2 metric.Float64GaugeObserver - - labels := []attribute.KeyValue{ - attribute.String("A", "B"), - attribute.String("C", "D"), - } - - cb := Must(meter).NewBatchObserver( - func(_ context.Context, result metric.BatchObserverResult) { - result.Observe(labels, - obs1.Observation(42), - obs2.Observation(42.0), - ) - }, - ) - obs1 = cb.NewInt64GaugeObserver("test.gauge.int") - obs2 = cb.NewFloat64GaugeObserver("test.gauge.float") - - provider.RunAsyncInstruments() - - require.Len(t, provider.MeasurementBatches, 1) - - impl1 := obs1.AsyncImpl().Implementation().(*metrictest.Async) - impl2 := obs2.AsyncImpl().Implementation().(*metrictest.Async) - - require.NotNil(t, impl1) - require.NotNil(t, impl2) - - got := provider.MeasurementBatches[0] - require.Equal(t, labels, got.Labels) - require.Len(t, got.Measurements, 2) - - m1 := got.Measurements[0] - require.Equal(t, impl1, m1.Instrument.Implementation().(*metrictest.Async)) - require.Equal(t, 0, m1.Number.CompareNumber(number.Int64Kind, metrictest.ResolveNumberByKind(t, number.Int64Kind, 42))) - - m2 := got.Measurements[1] - require.Equal(t, impl2, m2.Instrument.Implementation().(*metrictest.Async)) - require.Equal(t, 0, m2.Number.CompareNumber(number.Float64Kind, metrictest.ResolveNumberByKind(t, number.Float64Kind, 42))) -} - -func checkObserverBatch(t *testing.T, labels []attribute.KeyValue, provider *metrictest.MeterProvider, nkind number.Kind, mkind sdkapi.InstrumentKind, observer sdkapi.AsyncImpl, expected float64) { - t.Helper() - assert.Len(t, provider.MeasurementBatches, 1) - if len(provider.MeasurementBatches) < 1 { - return - } - o := observer.Implementation().(*metrictest.Async) - if !assert.NotNil(t, o) { - return - } - got := provider.MeasurementBatches[0] - assert.Equal(t, labels, got.Labels) - assert.Len(t, got.Measurements, 1) - if len(got.Measurements) < 1 { - return - } - measurement := got.Measurements[0] - require.Equal(t, mkind, measurement.Instrument.Descriptor().InstrumentKind()) - assert.Equal(t, o, measurement.Instrument.Implementation().(*metrictest.Async)) - ft := metrictest.ResolveNumberByKind(t, nkind, expected) - assert.Equal(t, 0, measurement.Number.CompareNumber(nkind, ft)) -} - -type testWrappedMeter struct { -} - -var _ sdkapi.MeterImpl = testWrappedMeter{} - -func (testWrappedMeter) RecordBatch(context.Context, []attribute.KeyValue, ...sdkapi.Measurement) { -} - -func (testWrappedMeter) NewSyncInstrument(_ sdkapi.Descriptor) (sdkapi.SyncImpl, error) { - return nil, nil -} - -func (testWrappedMeter) NewAsyncInstrument(_ sdkapi.Descriptor, _ sdkapi.AsyncRunner) (sdkapi.AsyncImpl, error) { - return nil, errors.New("Test wrap error") -} - -func TestWrappedInstrumentError(t *testing.T) { - impl := &testWrappedMeter{} - meter := metric.WrapMeterImpl(impl) - - histogram, err := meter.NewInt64Histogram("test.histogram") - - require.Equal(t, err, metric.ErrSDKReturnedNilImpl) - require.NotNil(t, histogram.SyncImpl()) - - observer, err := meter.NewInt64GaugeObserver("test.observer", func(_ context.Context, result metric.Int64ObserverResult) {}) - - require.NotNil(t, err) - require.NotNil(t, observer.AsyncImpl()) -} - -func TestNilCallbackObserverNoop(t *testing.T) { - // Tests that a nil callback yields a no-op observer without error. - _, meter := testPair() - - observer := Must(meter).NewInt64GaugeObserver("test.observer", nil) - - impl := observer.AsyncImpl().Implementation() - desc := observer.AsyncImpl().Descriptor() - require.Equal(t, nil, impl) - require.Equal(t, "", desc.Name()) -} diff --git a/metric/metrictest/alignment_test.go b/metric/metrictest/alignment_test.go deleted file mode 100644 index 183d46bda82..00000000000 --- a/metric/metrictest/alignment_test.go +++ /dev/null @@ -1,42 +0,0 @@ -// 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 metrictest - -import ( - "os" - "testing" - "unsafe" - - "go.opentelemetry.io/otel/internal/internaltest" -) - -// TestMain ensures struct alignment prior to running tests. -func TestMain(m *testing.M) { - fields := []internaltest.FieldOffset{ - { - Name: "Batch.Measurments", - Offset: unsafe.Offsetof(Batch{}.Measurements), - }, - { - Name: "Measurement.Number", - Offset: unsafe.Offsetof(Measurement{}.Number), - }, - } - if !internaltest.Aligned8Byte(fields, os.Stderr) { - os.Exit(1) - } - - os.Exit(m.Run()) -} diff --git a/metric/metrictest/meter.go b/metric/metrictest/meter.go deleted file mode 100644 index 759bb04baec..00000000000 --- a/metric/metrictest/meter.go +++ /dev/null @@ -1,290 +0,0 @@ -// 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 metrictest // import "go.opentelemetry.io/otel/metric/metrictest" - -import ( - "context" - "sync" - "testing" - - "go.opentelemetry.io/otel/attribute" - internalmetric "go.opentelemetry.io/otel/internal/metric" - "go.opentelemetry.io/otel/metric" - "go.opentelemetry.io/otel/metric/number" - "go.opentelemetry.io/otel/metric/sdkapi" -) - -type ( - Handle struct { - Instrument *Sync - Labels []attribute.KeyValue - } - - // Library is the same as "sdk/instrumentation".Library but there is - // a package cycle to use it. - Library struct { - InstrumentationName string - InstrumentationVersion string - SchemaURL string - } - - Batch struct { - // Measurement needs to be aligned for 64-bit atomic operations. - Measurements []Measurement - Ctx context.Context - Labels []attribute.KeyValue - Library Library - } - - // MeterImpl is an OpenTelemetry Meter implementation used for testing. - MeterImpl struct { - library Library - provider *MeterProvider - asyncInstruments *internalmetric.AsyncInstrumentState - } - - // MeterProvider is a collection of named MeterImpls used for testing. - MeterProvider struct { - lock sync.Mutex - - MeasurementBatches []Batch - impls []*MeterImpl - } - - Measurement struct { - // Number needs to be aligned for 64-bit atomic operations. - Number number.Number - Instrument sdkapi.InstrumentImpl - } - - Instrument struct { - meter *MeterImpl - descriptor sdkapi.Descriptor - } - - Async struct { - Instrument - - runner sdkapi.AsyncRunner - } - - Sync struct { - Instrument - } -) - -var ( - _ sdkapi.SyncImpl = &Sync{} - _ sdkapi.MeterImpl = &MeterImpl{} - _ sdkapi.AsyncImpl = &Async{} -) - -// NewDescriptor is a test helper for constructing test metric -// descriptors using standard options. -func NewDescriptor(name string, ikind sdkapi.InstrumentKind, nkind number.Kind, opts ...metric.InstrumentOption) sdkapi.Descriptor { - cfg := metric.NewInstrumentConfig(opts...) - return sdkapi.NewDescriptor(name, ikind, nkind, cfg.Description(), cfg.Unit()) -} - -func (i Instrument) Descriptor() sdkapi.Descriptor { - return i.descriptor -} - -func (a *Async) Implementation() interface{} { - return a -} - -func (s *Sync) Implementation() interface{} { - return s -} - -func (s *Sync) RecordOne(ctx context.Context, number number.Number, labels []attribute.KeyValue) { - s.meter.doRecordSingle(ctx, labels, s, number) -} - -func (h *Handle) RecordOne(ctx context.Context, number number.Number) { - h.Instrument.meter.doRecordSingle(ctx, h.Labels, h.Instrument, number) -} - -func (h *Handle) Unbind() { -} - -func (m *MeterImpl) doRecordSingle(ctx context.Context, labels []attribute.KeyValue, instrument sdkapi.InstrumentImpl, number number.Number) { - m.collect(ctx, labels, []Measurement{{ - Instrument: instrument, - Number: number, - }}) -} - -// NewMeterProvider returns a MeterProvider suitable for testing. -// When the test is complete, consult MeterProvider.MeasurementBatches. -func NewMeterProvider() *MeterProvider { - return &MeterProvider{} -} - -// Meter implements metric.MeterProvider. -func (p *MeterProvider) Meter(name string, opts ...metric.MeterOption) metric.Meter { - p.lock.Lock() - defer p.lock.Unlock() - cfg := metric.NewMeterConfig(opts...) - impl := &MeterImpl{ - library: Library{ - InstrumentationName: name, - InstrumentationVersion: cfg.InstrumentationVersion(), - SchemaURL: cfg.SchemaURL(), - }, - provider: p, - asyncInstruments: internalmetric.NewAsyncInstrumentState(), - } - p.impls = append(p.impls, impl) - return metric.WrapMeterImpl(impl) -} - -// NewSyncInstrument implements sdkapi.MeterImpl. -func (m *MeterImpl) NewSyncInstrument(descriptor sdkapi.Descriptor) (sdkapi.SyncImpl, error) { - return &Sync{ - Instrument{ - descriptor: descriptor, - meter: m, - }, - }, nil -} - -// NewAsyncInstrument implements sdkapi.MeterImpl. -func (m *MeterImpl) NewAsyncInstrument(descriptor sdkapi.Descriptor, runner sdkapi.AsyncRunner) (sdkapi.AsyncImpl, error) { - a := &Async{ - Instrument: Instrument{ - descriptor: descriptor, - meter: m, - }, - runner: runner, - } - m.provider.registerAsyncInstrument(a, m, runner) - return a, nil -} - -// RecordBatch implements sdkapi.MeterImpl. -func (m *MeterImpl) RecordBatch(ctx context.Context, labels []attribute.KeyValue, measurements ...sdkapi.Measurement) { - mm := make([]Measurement, len(measurements)) - for i := 0; i < len(measurements); i++ { - m := measurements[i] - mm[i] = Measurement{ - Instrument: m.SyncImpl().Implementation().(*Sync), - Number: m.Number(), - } - } - m.collect(ctx, labels, mm) -} - -// CollectAsync is called from asyncInstruments.Run() with the lock held. -func (m *MeterImpl) CollectAsync(labels []attribute.KeyValue, obs ...sdkapi.Observation) { - mm := make([]Measurement, len(obs)) - for i := 0; i < len(obs); i++ { - o := obs[i] - mm[i] = Measurement{ - Instrument: o.AsyncImpl(), - Number: o.Number(), - } - } - m.collect(context.Background(), labels, mm) -} - -// collect is called from CollectAsync() or RecordBatch() with the lock held. -func (m *MeterImpl) collect(ctx context.Context, labels []attribute.KeyValue, measurements []Measurement) { - m.provider.addMeasurement(Batch{ - Ctx: ctx, - Labels: labels, - Measurements: measurements, - Library: m.library, - }) -} - -// registerAsyncInstrument locks the provider and registers the new Async instrument. -func (p *MeterProvider) registerAsyncInstrument(a *Async, m *MeterImpl, runner sdkapi.AsyncRunner) { - p.lock.Lock() - defer p.lock.Unlock() - - m.asyncInstruments.Register(a, runner) -} - -// addMeasurement locks the provider and adds the new measurement batch. -func (p *MeterProvider) addMeasurement(b Batch) { - p.lock.Lock() - defer p.lock.Unlock() - p.MeasurementBatches = append(p.MeasurementBatches, b) -} - -// copyImpls locks the provider and copies the current list of *MeterImpls. -func (p *MeterProvider) copyImpls() []*MeterImpl { - p.lock.Lock() - defer p.lock.Unlock() - cpy := make([]*MeterImpl, len(p.impls)) - copy(cpy, p.impls) - return cpy -} - -// RunAsyncInstruments is used in tests to trigger collection from -// asynchronous instruments. -func (p *MeterProvider) RunAsyncInstruments() { - for _, impl := range p.copyImpls() { - impl.asyncInstruments.Run(context.Background(), impl) - } -} - -// Measured is the helper struct which provides flat representation of recorded measurements -// to simplify testing -type Measured struct { - Name string - Labels map[attribute.Key]attribute.Value - Number number.Number - Library Library -} - -// LabelsToMap converts label set to keyValue map, to be easily used in tests -func LabelsToMap(kvs ...attribute.KeyValue) map[attribute.Key]attribute.Value { - m := map[attribute.Key]attribute.Value{} - for _, label := range kvs { - m[label.Key] = label.Value - } - return m -} - -// AsStructs converts recorded batches to array of flat, readable Measured helper structures -func AsStructs(batches []Batch) []Measured { - var r []Measured - for _, batch := range batches { - for _, m := range batch.Measurements { - r = append(r, Measured{ - Name: m.Instrument.Descriptor().Name(), - Labels: LabelsToMap(batch.Labels...), - Number: m.Number, - Library: batch.Library, - }) - } - } - return r -} - -// ResolveNumberByKind takes defined metric descriptor creates a concrete typed metric number -func ResolveNumberByKind(t *testing.T, kind number.Kind, value float64) number.Number { - t.Helper() - switch kind { - case number.Int64Kind: - return number.NewInt64Number(int64(value)) - case number.Float64Kind: - return number.NewFloat64Number(value) - } - panic("invalid number kind") -} diff --git a/metric/noop.go b/metric/noop.go deleted file mode 100644 index 37c653f51a1..00000000000 --- a/metric/noop.go +++ /dev/null @@ -1,30 +0,0 @@ -// 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 metric // import "go.opentelemetry.io/otel/metric" - -type noopMeterProvider struct{} - -// NewNoopMeterProvider returns an implementation of MeterProvider that -// performs no operations. The Meter and Instrument created from the returned -// MeterProvider also perform no operations. -func NewNoopMeterProvider() MeterProvider { - return noopMeterProvider{} -} - -var _ MeterProvider = noopMeterProvider{} - -func (noopMeterProvider) Meter(instrumentationName string, opts ...MeterOption) Meter { - return Meter{} -} diff --git a/metric/noop_test.go b/metric/noop_test.go deleted file mode 100644 index e5a7528a217..00000000000 --- a/metric/noop_test.go +++ /dev/null @@ -1,34 +0,0 @@ -// 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 metric - -import ( - "testing" -) - -func TestNewNoopMeterProvider(t *testing.T) { - got, want := NewNoopMeterProvider(), noopMeterProvider{} - if got != want { - t.Errorf("NewNoopMeterProvider() returned %#v, want %#v", got, want) - } -} - -func TestNoopMeterProviderMeter(t *testing.T) { - mp := NewNoopMeterProvider() - got, want := mp.Meter(""), Meter{} - if got != want { - t.Errorf("noopMeterProvider.Meter() returned %#v, want %#v", got, want) - } -} diff --git a/metric/number/doc.go b/metric/number/doc.go deleted file mode 100644 index 0649ff875e7..00000000000 --- a/metric/number/doc.go +++ /dev/null @@ -1,23 +0,0 @@ -// 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 number provides a number abstraction for instruments that -either support int64 or float64 input values. - -This package is currently in a pre-GA phase. Backwards incompatible changes -may be introduced in subsequent minor version releases as we work to track the -evolving OpenTelemetry specification and user feedback. -*/ -package number // import "go.opentelemetry.io/otel/metric/number" diff --git a/metric/number/kind_string.go b/metric/number/kind_string.go deleted file mode 100644 index 6288c7ea295..00000000000 --- a/metric/number/kind_string.go +++ /dev/null @@ -1,24 +0,0 @@ -// Code generated by "stringer -type=Kind"; DO NOT EDIT. - -package number - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[Int64Kind-0] - _ = x[Float64Kind-1] -} - -const _Kind_name = "Int64KindFloat64Kind" - -var _Kind_index = [...]uint8{0, 9, 20} - -func (i Kind) String() string { - if i < 0 || i >= Kind(len(_Kind_index)-1) { - return "Kind(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _Kind_name[_Kind_index[i]:_Kind_index[i+1]] -} diff --git a/metric/number/number.go b/metric/number/number.go deleted file mode 100644 index 3ec95e2014d..00000000000 --- a/metric/number/number.go +++ /dev/null @@ -1,538 +0,0 @@ -// 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 number // import "go.opentelemetry.io/otel/metric/number" - -//go:generate stringer -type=Kind - -import ( - "fmt" - "math" - "sync/atomic" - - "go.opentelemetry.io/otel/internal" -) - -// Kind describes the data type of the Number. -type Kind int8 - -const ( - // Int64Kind means that the Number stores int64. - Int64Kind Kind = iota - // Float64Kind means that the Number stores float64. - Float64Kind -) - -// Zero returns a zero value for a given Kind -func (k Kind) Zero() Number { - switch k { - case Int64Kind: - return NewInt64Number(0) - case Float64Kind: - return NewFloat64Number(0.) - default: - return Number(0) - } -} - -// Minimum returns the minimum representable value -// for a given Kind -func (k Kind) Minimum() Number { - switch k { - case Int64Kind: - return NewInt64Number(math.MinInt64) - case Float64Kind: - return NewFloat64Number(-1. * math.MaxFloat64) - default: - return Number(0) - } -} - -// Maximum returns the maximum representable value -// for a given Kind -func (k Kind) Maximum() Number { - switch k { - case Int64Kind: - return NewInt64Number(math.MaxInt64) - case Float64Kind: - return NewFloat64Number(math.MaxFloat64) - default: - return Number(0) - } -} - -// Number represents either an integral or a floating point value. It -// needs to be accompanied with a source of Kind that describes -// the actual type of the value stored within Number. -type Number uint64 - -// - constructors - -// NewNumberFromRaw creates a new Number from a raw value. -func NewNumberFromRaw(r uint64) Number { - return Number(r) -} - -// NewInt64Number creates an integral Number. -func NewInt64Number(i int64) Number { - return NewNumberFromRaw(internal.Int64ToRaw(i)) -} - -// NewFloat64Number creates a floating point Number. -func NewFloat64Number(f float64) Number { - return NewNumberFromRaw(internal.Float64ToRaw(f)) -} - -// NewNumberSignChange returns a number with the same magnitude and -// the opposite sign. `kind` must describe the kind of number in `nn`. -func NewNumberSignChange(kind Kind, nn Number) Number { - switch kind { - case Int64Kind: - return NewInt64Number(-nn.AsInt64()) - case Float64Kind: - return NewFloat64Number(-nn.AsFloat64()) - } - return nn -} - -// - as x - -// AsNumber gets the Number. -func (n *Number) AsNumber() Number { - return *n -} - -// AsRaw gets the uninterpreted raw value. Might be useful for some -// atomic operations. -func (n *Number) AsRaw() uint64 { - return uint64(*n) -} - -// AsInt64 assumes that the value contains an int64 and returns it as -// such. -func (n *Number) AsInt64() int64 { - return internal.RawToInt64(n.AsRaw()) -} - -// AsFloat64 assumes that the measurement value contains a float64 and -// returns it as such. -func (n *Number) AsFloat64() float64 { - return internal.RawToFloat64(n.AsRaw()) -} - -// - as x atomic - -// AsNumberAtomic gets the Number atomically. -func (n *Number) AsNumberAtomic() Number { - return NewNumberFromRaw(n.AsRawAtomic()) -} - -// AsRawAtomic gets the uninterpreted raw value atomically. Might be -// useful for some atomic operations. -func (n *Number) AsRawAtomic() uint64 { - return atomic.LoadUint64(n.AsRawPtr()) -} - -// AsInt64Atomic assumes that the number contains an int64 and returns -// it as such atomically. -func (n *Number) AsInt64Atomic() int64 { - return atomic.LoadInt64(n.AsInt64Ptr()) -} - -// AsFloat64Atomic assumes that the measurement value contains a -// float64 and returns it as such atomically. -func (n *Number) AsFloat64Atomic() float64 { - return internal.RawToFloat64(n.AsRawAtomic()) -} - -// - as x ptr - -// AsRawPtr gets the pointer to the raw, uninterpreted raw -// value. Might be useful for some atomic operations. -func (n *Number) AsRawPtr() *uint64 { - return (*uint64)(n) -} - -// AsInt64Ptr assumes that the number contains an int64 and returns a -// pointer to it. -func (n *Number) AsInt64Ptr() *int64 { - return internal.RawPtrToInt64Ptr(n.AsRawPtr()) -} - -// AsFloat64Ptr assumes that the number contains a float64 and returns a -// pointer to it. -func (n *Number) AsFloat64Ptr() *float64 { - return internal.RawPtrToFloat64Ptr(n.AsRawPtr()) -} - -// - coerce - -// CoerceToInt64 casts the number to int64. May result in -// data/precision loss. -func (n *Number) CoerceToInt64(kind Kind) int64 { - switch kind { - case Int64Kind: - return n.AsInt64() - case Float64Kind: - return int64(n.AsFloat64()) - default: - // you get what you deserve - return 0 - } -} - -// CoerceToFloat64 casts the number to float64. May result in -// data/precision loss. -func (n *Number) CoerceToFloat64(kind Kind) float64 { - switch kind { - case Int64Kind: - return float64(n.AsInt64()) - case Float64Kind: - return n.AsFloat64() - default: - // you get what you deserve - return 0 - } -} - -// - set - -// SetNumber sets the number to the passed number. Both should be of -// the same kind. -func (n *Number) SetNumber(nn Number) { - *n.AsRawPtr() = nn.AsRaw() -} - -// SetRaw sets the number to the passed raw value. Both number and the -// raw number should represent the same kind. -func (n *Number) SetRaw(r uint64) { - *n.AsRawPtr() = r -} - -// SetInt64 assumes that the number contains an int64 and sets it to -// the passed value. -func (n *Number) SetInt64(i int64) { - *n.AsInt64Ptr() = i -} - -// SetFloat64 assumes that the number contains a float64 and sets it -// to the passed value. -func (n *Number) SetFloat64(f float64) { - *n.AsFloat64Ptr() = f -} - -// - set atomic - -// SetNumberAtomic sets the number to the passed number -// atomically. Both should be of the same kind. -func (n *Number) SetNumberAtomic(nn Number) { - atomic.StoreUint64(n.AsRawPtr(), nn.AsRaw()) -} - -// SetRawAtomic sets the number to the passed raw value -// atomically. Both number and the raw number should represent the -// same kind. -func (n *Number) SetRawAtomic(r uint64) { - atomic.StoreUint64(n.AsRawPtr(), r) -} - -// SetInt64Atomic assumes that the number contains an int64 and sets -// it to the passed value atomically. -func (n *Number) SetInt64Atomic(i int64) { - atomic.StoreInt64(n.AsInt64Ptr(), i) -} - -// SetFloat64Atomic assumes that the number contains a float64 and -// sets it to the passed value atomically. -func (n *Number) SetFloat64Atomic(f float64) { - atomic.StoreUint64(n.AsRawPtr(), internal.Float64ToRaw(f)) -} - -// - swap - -// SwapNumber sets the number to the passed number and returns the old -// number. Both this number and the passed number should be of the -// same kind. -func (n *Number) SwapNumber(nn Number) Number { - old := *n - n.SetNumber(nn) - return old -} - -// SwapRaw sets the number to the passed raw value and returns the old -// raw value. Both number and the raw number should represent the same -// kind. -func (n *Number) SwapRaw(r uint64) uint64 { - old := n.AsRaw() - n.SetRaw(r) - return old -} - -// SwapInt64 assumes that the number contains an int64, sets it to the -// passed value and returns the old int64 value. -func (n *Number) SwapInt64(i int64) int64 { - old := n.AsInt64() - n.SetInt64(i) - return old -} - -// SwapFloat64 assumes that the number contains an float64, sets it to -// the passed value and returns the old float64 value. -func (n *Number) SwapFloat64(f float64) float64 { - old := n.AsFloat64() - n.SetFloat64(f) - return old -} - -// - swap atomic - -// SwapNumberAtomic sets the number to the passed number and returns -// the old number atomically. Both this number and the passed number -// should be of the same kind. -func (n *Number) SwapNumberAtomic(nn Number) Number { - return NewNumberFromRaw(atomic.SwapUint64(n.AsRawPtr(), nn.AsRaw())) -} - -// SwapRawAtomic sets the number to the passed raw value and returns -// the old raw value atomically. Both number and the raw number should -// represent the same kind. -func (n *Number) SwapRawAtomic(r uint64) uint64 { - return atomic.SwapUint64(n.AsRawPtr(), r) -} - -// SwapInt64Atomic assumes that the number contains an int64, sets it -// to the passed value and returns the old int64 value atomically. -func (n *Number) SwapInt64Atomic(i int64) int64 { - return atomic.SwapInt64(n.AsInt64Ptr(), i) -} - -// SwapFloat64Atomic assumes that the number contains an float64, sets -// it to the passed value and returns the old float64 value -// atomically. -func (n *Number) SwapFloat64Atomic(f float64) float64 { - return internal.RawToFloat64(atomic.SwapUint64(n.AsRawPtr(), internal.Float64ToRaw(f))) -} - -// - add - -// AddNumber assumes that this and the passed number are of the passed -// kind and adds the passed number to this number. -func (n *Number) AddNumber(kind Kind, nn Number) { - switch kind { - case Int64Kind: - n.AddInt64(nn.AsInt64()) - case Float64Kind: - n.AddFloat64(nn.AsFloat64()) - } -} - -// AddRaw assumes that this number and the passed raw value are of the -// passed kind and adds the passed raw value to this number. -func (n *Number) AddRaw(kind Kind, r uint64) { - n.AddNumber(kind, NewNumberFromRaw(r)) -} - -// AddInt64 assumes that the number contains an int64 and adds the -// passed int64 to it. -func (n *Number) AddInt64(i int64) { - *n.AsInt64Ptr() += i -} - -// AddFloat64 assumes that the number contains a float64 and adds the -// passed float64 to it. -func (n *Number) AddFloat64(f float64) { - *n.AsFloat64Ptr() += f -} - -// - add atomic - -// AddNumberAtomic assumes that this and the passed number are of the -// passed kind and adds the passed number to this number atomically. -func (n *Number) AddNumberAtomic(kind Kind, nn Number) { - switch kind { - case Int64Kind: - n.AddInt64Atomic(nn.AsInt64()) - case Float64Kind: - n.AddFloat64Atomic(nn.AsFloat64()) - } -} - -// AddRawAtomic assumes that this number and the passed raw value are -// of the passed kind and adds the passed raw value to this number -// atomically. -func (n *Number) AddRawAtomic(kind Kind, r uint64) { - n.AddNumberAtomic(kind, NewNumberFromRaw(r)) -} - -// AddInt64Atomic assumes that the number contains an int64 and adds -// the passed int64 to it atomically. -func (n *Number) AddInt64Atomic(i int64) { - atomic.AddInt64(n.AsInt64Ptr(), i) -} - -// AddFloat64Atomic assumes that the number contains a float64 and -// adds the passed float64 to it atomically. -func (n *Number) AddFloat64Atomic(f float64) { - for { - o := n.AsFloat64Atomic() - if n.CompareAndSwapFloat64(o, o+f) { - break - } - } -} - -// - compare and swap (atomic only) - -// CompareAndSwapNumber does the atomic CAS operation on this -// number. This number and passed old and new numbers should be of the -// same kind. -func (n *Number) CompareAndSwapNumber(on, nn Number) bool { - return atomic.CompareAndSwapUint64(n.AsRawPtr(), on.AsRaw(), nn.AsRaw()) -} - -// CompareAndSwapRaw does the atomic CAS operation on this -// number. This number and passed old and new raw values should be of -// the same kind. -func (n *Number) CompareAndSwapRaw(or, nr uint64) bool { - return atomic.CompareAndSwapUint64(n.AsRawPtr(), or, nr) -} - -// CompareAndSwapInt64 assumes that this number contains an int64 and -// does the atomic CAS operation on it. -func (n *Number) CompareAndSwapInt64(oi, ni int64) bool { - return atomic.CompareAndSwapInt64(n.AsInt64Ptr(), oi, ni) -} - -// CompareAndSwapFloat64 assumes that this number contains a float64 and -// does the atomic CAS operation on it. -func (n *Number) CompareAndSwapFloat64(of, nf float64) bool { - return atomic.CompareAndSwapUint64(n.AsRawPtr(), internal.Float64ToRaw(of), internal.Float64ToRaw(nf)) -} - -// - compare - -// CompareNumber compares two Numbers given their kind. Both numbers -// should have the same kind. This returns: -// 0 if the numbers are equal -// -1 if the subject `n` is less than the argument `nn` -// +1 if the subject `n` is greater than the argument `nn` -func (n *Number) CompareNumber(kind Kind, nn Number) int { - switch kind { - case Int64Kind: - return n.CompareInt64(nn.AsInt64()) - case Float64Kind: - return n.CompareFloat64(nn.AsFloat64()) - default: - // you get what you deserve - return 0 - } -} - -// CompareRaw compares two numbers, where one is input as a raw -// uint64, interpreting both values as a `kind` of number. -func (n *Number) CompareRaw(kind Kind, r uint64) int { - return n.CompareNumber(kind, NewNumberFromRaw(r)) -} - -// CompareInt64 assumes that the Number contains an int64 and performs -// a comparison between the value and the other value. It returns the -// typical result of the compare function: -1 if the value is less -// than the other, 0 if both are equal, 1 if the value is greater than -// the other. -func (n *Number) CompareInt64(i int64) int { - this := n.AsInt64() - if this < i { - return -1 - } else if this > i { - return 1 - } - return 0 -} - -// CompareFloat64 assumes that the Number contains a float64 and -// performs a comparison between the value and the other value. It -// returns the typical result of the compare function: -1 if the value -// is less than the other, 0 if both are equal, 1 if the value is -// greater than the other. -// -// Do not compare NaN values. -func (n *Number) CompareFloat64(f float64) int { - this := n.AsFloat64() - if this < f { - return -1 - } else if this > f { - return 1 - } - return 0 -} - -// - relations to zero - -// IsPositive returns true if the actual value is greater than zero. -func (n *Number) IsPositive(kind Kind) bool { - return n.compareWithZero(kind) > 0 -} - -// IsNegative returns true if the actual value is less than zero. -func (n *Number) IsNegative(kind Kind) bool { - return n.compareWithZero(kind) < 0 -} - -// IsZero returns true if the actual value is equal to zero. -func (n *Number) IsZero(kind Kind) bool { - return n.compareWithZero(kind) == 0 -} - -// - misc - -// Emit returns a string representation of the raw value of the -// Number. A %d is used for integral values, %f for floating point -// values. -func (n *Number) Emit(kind Kind) string { - switch kind { - case Int64Kind: - return fmt.Sprintf("%d", n.AsInt64()) - case Float64Kind: - return fmt.Sprintf("%f", n.AsFloat64()) - default: - return "" - } -} - -// AsInterface returns the number as an interface{}, typically used -// for Kind-correct JSON conversion. -func (n *Number) AsInterface(kind Kind) interface{} { - switch kind { - case Int64Kind: - return n.AsInt64() - case Float64Kind: - return n.AsFloat64() - default: - return math.NaN() - } -} - -// - private stuff - -func (n *Number) compareWithZero(kind Kind) int { - switch kind { - case Int64Kind: - return n.CompareInt64(0) - case Float64Kind: - return n.CompareFloat64(0.) - default: - // you get what you deserve - return 0 - } -} diff --git a/metric/number/number_test.go b/metric/number/number_test.go deleted file mode 100644 index e8d675c7fc3..00000000000 --- a/metric/number/number_test.go +++ /dev/null @@ -1,212 +0,0 @@ -// 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 number - -import ( - "math" - "testing" - "unsafe" - - "github.com/stretchr/testify/require" -) - -func TestNumber(t *testing.T) { - iNeg := NewInt64Number(-42) - iZero := NewInt64Number(0) - iPos := NewInt64Number(42) - i64Numbers := [3]Number{iNeg, iZero, iPos} - - for idx, i := range []int64{-42, 0, 42} { - n := i64Numbers[idx] - if got := n.AsInt64(); got != i { - t.Errorf("Number %#v (%s) int64 check failed, expected %d, got %d", n, n.Emit(Int64Kind), i, got) - } - } - - for _, n := range i64Numbers { - expected := unsafe.Pointer(&n) - got := unsafe.Pointer(n.AsRawPtr()) - if expected != got { - t.Errorf("Getting raw pointer failed, got %v, expected %v", got, expected) - } - } - - fNeg := NewFloat64Number(-42.) - fZero := NewFloat64Number(0.) - fPos := NewFloat64Number(42.) - f64Numbers := [3]Number{fNeg, fZero, fPos} - - for idx, f := range []float64{-42., 0., 42.} { - n := f64Numbers[idx] - if got := n.AsFloat64(); got != f { - t.Errorf("Number %#v (%s) float64 check failed, expected %f, got %f", n, n.Emit(Int64Kind), f, got) - } - } - - for _, n := range f64Numbers { - expected := unsafe.Pointer(&n) - got := unsafe.Pointer(n.AsRawPtr()) - if expected != got { - t.Errorf("Getting raw pointer failed, got %v, expected %v", got, expected) - } - } - - cmpsForNeg := [3]int{0, -1, -1} - cmpsForZero := [3]int{1, 0, -1} - cmpsForPos := [3]int{1, 1, 0} - - type testcase struct { - // n needs to be aligned for 64-bit atomic operations. - n Number - // nums needs to be aligned for 64-bit atomic operations. - nums [3]Number - kind Kind - pos bool - zero bool - neg bool - cmps [3]int - } - testcases := []testcase{ - { - n: iNeg, - kind: Int64Kind, - pos: false, - zero: false, - neg: true, - nums: i64Numbers, - cmps: cmpsForNeg, - }, - { - n: iZero, - kind: Int64Kind, - pos: false, - zero: true, - neg: false, - nums: i64Numbers, - cmps: cmpsForZero, - }, - { - n: iPos, - kind: Int64Kind, - pos: true, - zero: false, - neg: false, - nums: i64Numbers, - cmps: cmpsForPos, - }, - { - n: fNeg, - kind: Float64Kind, - pos: false, - zero: false, - neg: true, - nums: f64Numbers, - cmps: cmpsForNeg, - }, - { - n: fZero, - kind: Float64Kind, - pos: false, - zero: true, - neg: false, - nums: f64Numbers, - cmps: cmpsForZero, - }, - { - n: fPos, - kind: Float64Kind, - pos: true, - zero: false, - neg: false, - nums: f64Numbers, - cmps: cmpsForPos, - }, - } - for _, tt := range testcases { - if got := tt.n.IsPositive(tt.kind); got != tt.pos { - t.Errorf("Number %#v (%s) positive check failed, expected %v, got %v", tt.n, tt.n.Emit(tt.kind), tt.pos, got) - } - if got := tt.n.IsZero(tt.kind); got != tt.zero { - t.Errorf("Number %#v (%s) zero check failed, expected %v, got %v", tt.n, tt.n.Emit(tt.kind), tt.pos, got) - } - if got := tt.n.IsNegative(tt.kind); got != tt.neg { - t.Errorf("Number %#v (%s) negative check failed, expected %v, got %v", tt.n, tt.n.Emit(tt.kind), tt.pos, got) - } - for i := 0; i < 3; i++ { - if got := tt.n.CompareRaw(tt.kind, tt.nums[i].AsRaw()); got != tt.cmps[i] { - t.Errorf("Number %#v (%s) compare check with %#v (%s) failed, expected %d, got %d", tt.n, tt.n.Emit(tt.kind), tt.nums[i], tt.nums[i].Emit(tt.kind), tt.cmps[i], got) - } - } - } -} - -func TestNumberZero(t *testing.T) { - zero := Number(0) - zerof := NewFloat64Number(0) - zeroi := NewInt64Number(0) - - if zero != zerof || zero != zeroi { - t.Errorf("Invalid zero representations") - } -} - -func TestNumberAsInterface(t *testing.T) { - i64 := NewInt64Number(10) - f64 := NewFloat64Number(11.11) - require.Equal(t, int64(10), (&i64).AsInterface(Int64Kind).(int64)) - require.Equal(t, 11.11, (&f64).AsInterface(Float64Kind).(float64)) -} - -func TestNumberSignChange(t *testing.T) { - t.Run("Int64", func(t *testing.T) { - posInt := NewInt64Number(10) - negInt := NewInt64Number(-10) - - require.Equal(t, posInt, NewNumberSignChange(Int64Kind, negInt)) - require.Equal(t, negInt, NewNumberSignChange(Int64Kind, posInt)) - }) - - t.Run("Float64", func(t *testing.T) { - posFloat := NewFloat64Number(10) - negFloat := NewFloat64Number(-10) - - require.Equal(t, posFloat, NewNumberSignChange(Float64Kind, negFloat)) - require.Equal(t, negFloat, NewNumberSignChange(Float64Kind, posFloat)) - }) - - t.Run("Float64Zero", func(t *testing.T) { - posFloat := NewFloat64Number(0) - negFloat := NewFloat64Number(math.Copysign(0, -1)) - - require.Equal(t, posFloat, NewNumberSignChange(Float64Kind, negFloat)) - require.Equal(t, negFloat, NewNumberSignChange(Float64Kind, posFloat)) - }) - - t.Run("Float64Inf", func(t *testing.T) { - posFloat := NewFloat64Number(math.Inf(+1)) - negFloat := NewFloat64Number(math.Inf(-1)) - - require.Equal(t, posFloat, NewNumberSignChange(Float64Kind, negFloat)) - require.Equal(t, negFloat, NewNumberSignChange(Float64Kind, posFloat)) - }) - - t.Run("Float64NaN", func(t *testing.T) { - posFloat := NewFloat64Number(math.NaN()) - negFloat := NewFloat64Number(math.Copysign(math.NaN(), -1)) - - require.Equal(t, posFloat, NewNumberSignChange(Float64Kind, negFloat)) - require.Equal(t, negFloat, NewNumberSignChange(Float64Kind, posFloat)) - }) -} diff --git a/metric/sdkapi/descriptor.go b/metric/sdkapi/descriptor.go deleted file mode 100644 index 14eb0532e45..00000000000 --- a/metric/sdkapi/descriptor.go +++ /dev/null @@ -1,70 +0,0 @@ -// 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 sdkapi // import "go.opentelemetry.io/otel/metric/sdkapi" - -import ( - "go.opentelemetry.io/otel/metric/number" - "go.opentelemetry.io/otel/metric/unit" -) - -// Descriptor contains all the settings that describe an instrument, -// including its name, metric kind, number kind, and the configurable -// options. -type Descriptor struct { - name string - instrumentKind InstrumentKind - numberKind number.Kind - description string - unit unit.Unit -} - -// NewDescriptor returns a Descriptor with the given contents. -func NewDescriptor(name string, ikind InstrumentKind, nkind number.Kind, description string, unit unit.Unit) Descriptor { - return Descriptor{ - name: name, - instrumentKind: ikind, - numberKind: nkind, - description: description, - unit: unit, - } -} - -// Name returns the metric instrument's name. -func (d Descriptor) Name() string { - return d.name -} - -// InstrumentKind returns the specific kind of instrument. -func (d Descriptor) InstrumentKind() InstrumentKind { - return d.instrumentKind -} - -// Description provides a human-readable description of the metric -// instrument. -func (d Descriptor) Description() string { - return d.description -} - -// Unit describes the units of the metric instrument. Unitless -// metrics return the empty string. -func (d Descriptor) Unit() unit.Unit { - return d.unit -} - -// NumberKind returns whether this instrument is declared over int64, -// float64, or uint64 values. -func (d Descriptor) NumberKind() number.Kind { - return d.numberKind -} diff --git a/metric/sdkapi/descriptor_test.go b/metric/sdkapi/descriptor_test.go deleted file mode 100644 index 6b6927075f9..00000000000 --- a/metric/sdkapi/descriptor_test.go +++ /dev/null @@ -1,33 +0,0 @@ -// 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 sdkapi - -import ( - "testing" - - "github.com/stretchr/testify/require" - - "go.opentelemetry.io/otel/metric/number" - "go.opentelemetry.io/otel/metric/unit" -) - -func TestDescriptorGetters(t *testing.T) { - d := NewDescriptor("name", HistogramInstrumentKind, number.Int64Kind, "my description", "my unit") - require.Equal(t, "name", d.Name()) - require.Equal(t, HistogramInstrumentKind, d.InstrumentKind()) - require.Equal(t, number.Int64Kind, d.NumberKind()) - require.Equal(t, "my description", d.Description()) - require.Equal(t, unit.Unit("my unit"), d.Unit()) -} diff --git a/metric/sdkapi/instrumentkind.go b/metric/sdkapi/instrumentkind.go deleted file mode 100644 index 64aa5ead123..00000000000 --- a/metric/sdkapi/instrumentkind.go +++ /dev/null @@ -1,80 +0,0 @@ -// 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. - -//go:generate stringer -type=InstrumentKind - -package sdkapi // import "go.opentelemetry.io/otel/metric/sdkapi" - -// InstrumentKind describes the kind of instrument. -type InstrumentKind int8 - -const ( - // HistogramInstrumentKind indicates a Histogram instrument. - HistogramInstrumentKind InstrumentKind = iota - // GaugeObserverInstrumentKind indicates an GaugeObserver instrument. - GaugeObserverInstrumentKind - - // CounterInstrumentKind indicates a Counter instrument. - CounterInstrumentKind - // UpDownCounterInstrumentKind indicates a UpDownCounter instrument. - UpDownCounterInstrumentKind - - // CounterObserverInstrumentKind indicates a CounterObserver instrument. - CounterObserverInstrumentKind - // UpDownCounterObserverInstrumentKind indicates a UpDownCounterObserver - // instrument. - UpDownCounterObserverInstrumentKind -) - -// Synchronous returns whether this is a synchronous kind of instrument. -func (k InstrumentKind) Synchronous() bool { - switch k { - case CounterInstrumentKind, UpDownCounterInstrumentKind, HistogramInstrumentKind: - return true - } - return false -} - -// Asynchronous returns whether this is an asynchronous kind of instrument. -func (k InstrumentKind) Asynchronous() bool { - return !k.Synchronous() -} - -// Adding returns whether this kind of instrument adds its inputs (as opposed to Grouping). -func (k InstrumentKind) Adding() bool { - switch k { - case CounterInstrumentKind, UpDownCounterInstrumentKind, CounterObserverInstrumentKind, UpDownCounterObserverInstrumentKind: - return true - } - return false -} - -// Grouping returns whether this kind of instrument groups its inputs (as opposed to Adding). -func (k InstrumentKind) Grouping() bool { - return !k.Adding() -} - -// Monotonic returns whether this kind of instrument exposes a non-decreasing sum. -func (k InstrumentKind) Monotonic() bool { - switch k { - case CounterInstrumentKind, CounterObserverInstrumentKind: - return true - } - return false -} - -// PrecomputedSum returns whether this kind of instrument receives precomputed sums. -func (k InstrumentKind) PrecomputedSum() bool { - return k.Adding() && k.Asynchronous() -} diff --git a/metric/sdkapi/instrumentkind_string.go b/metric/sdkapi/instrumentkind_string.go deleted file mode 100644 index 3a2e79d823e..00000000000 --- a/metric/sdkapi/instrumentkind_string.go +++ /dev/null @@ -1,28 +0,0 @@ -// Code generated by "stringer -type=InstrumentKind"; DO NOT EDIT. - -package sdkapi - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[HistogramInstrumentKind-0] - _ = x[GaugeObserverInstrumentKind-1] - _ = x[CounterInstrumentKind-2] - _ = x[UpDownCounterInstrumentKind-3] - _ = x[CounterObserverInstrumentKind-4] - _ = x[UpDownCounterObserverInstrumentKind-5] -} - -const _InstrumentKind_name = "HistogramInstrumentKindGaugeObserverInstrumentKindCounterInstrumentKindUpDownCounterInstrumentKindCounterObserverInstrumentKindUpDownCounterObserverInstrumentKind" - -var _InstrumentKind_index = [...]uint8{0, 23, 50, 71, 98, 127, 162} - -func (i InstrumentKind) String() string { - if i < 0 || i >= InstrumentKind(len(_InstrumentKind_index)-1) { - return "InstrumentKind(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _InstrumentKind_name[_InstrumentKind_index[i]:_InstrumentKind_index[i+1]] -} diff --git a/metric/sdkapi/instrumentkind_test.go b/metric/sdkapi/instrumentkind_test.go deleted file mode 100644 index 0b2901383b2..00000000000 --- a/metric/sdkapi/instrumentkind_test.go +++ /dev/null @@ -1,32 +0,0 @@ -// 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 sdkapi_test - -import ( - "testing" - - "github.com/stretchr/testify/require" - - "go.opentelemetry.io/otel/metric/sdkapi" -) - -func TestInstrumentKinds(t *testing.T) { - require.Equal(t, sdkapi.HistogramInstrumentKind.String(), "HistogramInstrumentKind") - require.Equal(t, sdkapi.GaugeObserverInstrumentKind.String(), "GaugeObserverInstrumentKind") - require.Equal(t, sdkapi.CounterInstrumentKind.String(), "CounterInstrumentKind") - require.Equal(t, sdkapi.UpDownCounterInstrumentKind.String(), "UpDownCounterInstrumentKind") - require.Equal(t, sdkapi.CounterObserverInstrumentKind.String(), "CounterObserverInstrumentKind") - require.Equal(t, sdkapi.UpDownCounterObserverInstrumentKind.String(), "UpDownCounterObserverInstrumentKind") -} diff --git a/metric/sdkapi/noop.go b/metric/sdkapi/noop.go deleted file mode 100644 index f22895dae6f..00000000000 --- a/metric/sdkapi/noop.go +++ /dev/null @@ -1,66 +0,0 @@ -// 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 sdkapi // import "go.opentelemetry.io/otel/metric/sdkapi" - -import ( - "context" - - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/metric/number" -) - -type noopInstrument struct { - descriptor Descriptor -} -type noopSyncInstrument struct{ noopInstrument } -type noopAsyncInstrument struct{ noopInstrument } - -var _ SyncImpl = noopSyncInstrument{} -var _ AsyncImpl = noopAsyncInstrument{} - -// NewNoopSyncInstrument returns a No-op implementation of the -// synchronous instrument interface. -func NewNoopSyncInstrument() SyncImpl { - return noopSyncInstrument{ - noopInstrument{ - descriptor: Descriptor{ - instrumentKind: CounterInstrumentKind, - }, - }, - } -} - -// NewNoopAsyncInstrument returns a No-op implementation of the -// asynchronous instrument interface. -func NewNoopAsyncInstrument() AsyncImpl { - return noopAsyncInstrument{ - noopInstrument{ - descriptor: Descriptor{ - instrumentKind: CounterObserverInstrumentKind, - }, - }, - } -} - -func (noopInstrument) Implementation() interface{} { - return nil -} - -func (n noopInstrument) Descriptor() Descriptor { - return n.descriptor -} - -func (noopSyncInstrument) RecordOne(context.Context, number.Number, []attribute.KeyValue) { -} diff --git a/metric/sdkapi/sdkapi.go b/metric/sdkapi/sdkapi.go deleted file mode 100644 index 36836364bdc..00000000000 --- a/metric/sdkapi/sdkapi.go +++ /dev/null @@ -1,159 +0,0 @@ -// 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 sdkapi // import "go.opentelemetry.io/otel/metric/sdkapi" - -import ( - "context" - - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/metric/number" -) - -// MeterImpl is the interface an SDK must implement to supply a Meter -// implementation. -type MeterImpl interface { - // RecordBatch atomically records a batch of measurements. - RecordBatch(ctx context.Context, labels []attribute.KeyValue, measurement ...Measurement) - - // NewSyncInstrument returns a newly constructed - // synchronous instrument implementation or an error, should - // one occur. - NewSyncInstrument(descriptor Descriptor) (SyncImpl, error) - - // NewAsyncInstrument returns a newly constructed - // asynchronous instrument implementation or an error, should - // one occur. - NewAsyncInstrument( - descriptor Descriptor, - runner AsyncRunner, - ) (AsyncImpl, error) -} - -// InstrumentImpl is a common interface for synchronous and -// asynchronous instruments. -type InstrumentImpl interface { - // Implementation returns the underlying implementation of the - // instrument, which allows the implementation to gain access - // to its own representation especially from a `Measurement`. - Implementation() interface{} - - // Descriptor returns a copy of the instrument's Descriptor. - Descriptor() Descriptor -} - -// SyncImpl is the implementation-level interface to a generic -// synchronous instrument (e.g., Histogram and Counter instruments). -type SyncImpl interface { - InstrumentImpl - - // RecordOne captures a single synchronous metric event. - RecordOne(ctx context.Context, number number.Number, labels []attribute.KeyValue) -} - -// AsyncImpl is an implementation-level interface to an -// asynchronous instrument (e.g., Observer instruments). -type AsyncImpl interface { - InstrumentImpl -} - -// AsyncRunner is expected to convert into an AsyncSingleRunner or an -// AsyncBatchRunner. SDKs will encounter an error if the AsyncRunner -// does not satisfy one of these interfaces. -type AsyncRunner interface { - // AnyRunner is a non-exported method with no functional use - // other than to make this a non-empty interface. - AnyRunner() -} - -// AsyncSingleRunner is an interface implemented by single-observer -// callbacks. -type AsyncSingleRunner interface { - // Run accepts a single instrument and function for capturing - // observations of that instrument. Each call to the function - // receives one captured observation. (The function accepts - // multiple observations so the same implementation can be - // used for batch runners.) - Run(ctx context.Context, single AsyncImpl, capture func([]attribute.KeyValue, ...Observation)) - - AsyncRunner -} - -// AsyncBatchRunner is an interface implemented by batch-observer -// callbacks. -type AsyncBatchRunner interface { - // Run accepts a function for capturing observations of - // multiple instruments. - Run(ctx context.Context, capture func([]attribute.KeyValue, ...Observation)) - - AsyncRunner -} - -// NewMeasurement constructs a single observation, a binding between -// an asynchronous instrument and a number. -func NewMeasurement(instrument SyncImpl, number number.Number) Measurement { - return Measurement{ - instrument: instrument, - number: number, - } -} - -// Measurement is a low-level type used with synchronous instruments -// as a direct interface to the SDK via `RecordBatch`. -type Measurement struct { - // number needs to be aligned for 64-bit atomic operations. - number number.Number - instrument SyncImpl -} - -// SyncImpl returns the instrument that created this measurement. -// This returns an implementation-level object for use by the SDK, -// users should not refer to this. -func (m Measurement) SyncImpl() SyncImpl { - return m.instrument -} - -// Number returns a number recorded in this measurement. -func (m Measurement) Number() number.Number { - return m.number -} - -// NewObservation constructs a single observation, a binding between -// an asynchronous instrument and a number. -func NewObservation(instrument AsyncImpl, number number.Number) Observation { - return Observation{ - instrument: instrument, - number: number, - } -} - -// Observation is a low-level type used with asynchronous instruments -// as a direct interface to the SDK via `BatchObserver`. -type Observation struct { - // number needs to be aligned for 64-bit atomic operations. - number number.Number - instrument AsyncImpl -} - -// AsyncImpl returns the instrument that created this observation. -// This returns an implementation-level object for use by the SDK, -// users should not refer to this. -func (m Observation) AsyncImpl() AsyncImpl { - return m.instrument -} - -// Number returns a number recorded in this observation. -func (m Observation) Number() number.Number { - return m.number -} diff --git a/metric/sdkapi/sdkapi_test.go b/metric/sdkapi/sdkapi_test.go deleted file mode 100644 index 9c80f89bddb..00000000000 --- a/metric/sdkapi/sdkapi_test.go +++ /dev/null @@ -1,41 +0,0 @@ -// 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 sdkapi - -import ( - "testing" - - "github.com/stretchr/testify/require" - - "go.opentelemetry.io/otel/metric/number" -) - -func TestMeasurementGetters(t *testing.T) { - num := number.NewFloat64Number(1.5) - si := NewNoopSyncInstrument() - meas := NewMeasurement(si, num) - - require.Equal(t, si, meas.SyncImpl()) - require.Equal(t, num, meas.Number()) -} - -func TestObservationGetters(t *testing.T) { - num := number.NewFloat64Number(1.5) - ai := NewNoopAsyncInstrument() - obs := NewObservation(ai, num) - - require.Equal(t, ai, obs.AsyncImpl()) - require.Equal(t, num, obs.Number()) -} diff --git a/metric/unit/doc.go b/metric/unit/doc.go deleted file mode 100644 index f8e723593e6..00000000000 --- a/metric/unit/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -// 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 unit provides units. -// -// This package is currently in a pre-GA phase. Backwards incompatible changes -// may be introduced in subsequent minor version releases as we work to track -// the evolving OpenTelemetry specification and user feedback. -package unit // import "go.opentelemetry.io/otel/metric/unit" diff --git a/metric/unit/unit.go b/metric/unit/unit.go deleted file mode 100644 index 4615eb16f69..00000000000 --- a/metric/unit/unit.go +++ /dev/null @@ -1,24 +0,0 @@ -// 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 unit // import "go.opentelemetry.io/otel/metric/unit" - -type Unit string - -// Units defined by OpenTelemetry. -const ( - Dimensionless Unit = "1" - Bytes Unit = "By" - Milliseconds Unit = "ms" -) From 7bd4f00a4e0bc26753785b976b7e4101cdc072aa Mon Sep 17 00:00:00 2001 From: Aaron Clawson Date: Wed, 26 Jan 2022 20:41:35 +0000 Subject: [PATCH 2/6] Add instrument api with documentation --- metric/config.go | 67 ++++++++++++++++++ metric/doc.go | 23 ++++++ metric/go.mod | 69 ++++++++++++++++++ metric/go.sum | 15 ++++ .../instrument/asyncfloat64/asyncfloat64.go | 70 +++++++++++++++++++ metric/instrument/asyncint64/asyncint64.go | 70 +++++++++++++++++++ metric/instrument/config.go | 70 +++++++++++++++++++ metric/instrument/instrument.go | 30 ++++++++ metric/instrument/syncfloat64/syncfloat64.go | 56 +++++++++++++++ metric/instrument/syncint64/syncint64.go | 56 +++++++++++++++ metric/meter.go | 60 ++++++++++++++++ metric/unit/doc.go | 20 ++++++ metric/unit/unit.go | 24 +++++++ 13 files changed, 630 insertions(+) create mode 100644 metric/config.go create mode 100644 metric/doc.go create mode 100644 metric/go.mod create mode 100644 metric/go.sum create mode 100644 metric/instrument/asyncfloat64/asyncfloat64.go create mode 100644 metric/instrument/asyncint64/asyncint64.go create mode 100644 metric/instrument/config.go create mode 100644 metric/instrument/instrument.go create mode 100644 metric/instrument/syncfloat64/syncfloat64.go create mode 100644 metric/instrument/syncint64/syncint64.go create mode 100644 metric/meter.go create mode 100644 metric/unit/doc.go create mode 100644 metric/unit/unit.go diff --git a/metric/config.go b/metric/config.go new file mode 100644 index 00000000000..9485217df2c --- /dev/null +++ b/metric/config.go @@ -0,0 +1,67 @@ +// 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 metric // import "go.opentelemetry.io/otel/metric" + +// MeterConfig contains options for Meters. +type MeterConfig struct { + instrumentationVersion string + schemaURL string +} + +// InstrumentationVersion is the version of the library providing instrumentation. +func (cfg MeterConfig) InstrumentationVersion() string { + return cfg.instrumentationVersion +} + +// SchemaURL is the schema_url of the library providing instrumentation. +func (cfg MeterConfig) SchemaURL() string { + return cfg.schemaURL +} + +// MeterOption is an interface for applying Meter options. +type MeterOption interface { + // ApplyMeter is used to set a MeterOption value of a MeterConfig. + applyMeter(*MeterConfig) +} + +// NewMeterConfig creates a new MeterConfig and applies +// all the given options. +func NewMeterConfig(opts ...MeterOption) MeterConfig { + var config MeterConfig + for _, o := range opts { + o.applyMeter(&config) + } + return config +} + +type meterOptionFunc func(*MeterConfig) + +func (fn meterOptionFunc) applyMeter(cfg *MeterConfig) { + fn(cfg) +} + +// WithInstrumentationVersion sets the instrumentation version. +func WithInstrumentationVersion(version string) MeterOption { + return meterOptionFunc(func(config *MeterConfig) { + config.instrumentationVersion = version + }) +} + +// WithSchemaURL sets the schema URL. +func WithSchemaURL(schemaURL string) MeterOption { + return meterOptionFunc(func(config *MeterConfig) { + config.schemaURL = schemaURL + }) +} diff --git a/metric/doc.go b/metric/doc.go new file mode 100644 index 00000000000..bd6f4343720 --- /dev/null +++ b/metric/doc.go @@ -0,0 +1,23 @@ +// 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 metric provides an implementation of the metrics part of the +OpenTelemetry API. + +This package is currently in a pre-GA phase. Backwards incompatible changes +may be introduced in subsequent minor version releases as we work to track the +evolving OpenTelemetry specification and user feedback. +*/ +package metric // import "go.opentelemetry.io/otel/metric" diff --git a/metric/go.mod b/metric/go.mod new file mode 100644 index 00000000000..013bdad17aa --- /dev/null +++ b/metric/go.mod @@ -0,0 +1,69 @@ +module go.opentelemetry.io/otel/metric + +go 1.16 + +require go.opentelemetry.io/otel v1.3.0 + +replace go.opentelemetry.io/otel => ../ + +replace go.opentelemetry.io/otel/bridge/opencensus => ../bridge/opencensus + +replace go.opentelemetry.io/otel/bridge/opentracing => ../bridge/opentracing + +replace go.opentelemetry.io/otel/example/jaeger => ../example/jaeger + +replace go.opentelemetry.io/otel/example/namedtracer => ../example/namedtracer + +replace go.opentelemetry.io/otel/example/opencensus => ../example/opencensus + +replace go.opentelemetry.io/otel/example/otel-collector => ../example/otel-collector + +replace go.opentelemetry.io/otel/example/prom-collector => ../example/prom-collector + +replace go.opentelemetry.io/otel/example/prometheus => ../example/prometheus + +replace go.opentelemetry.io/otel/example/zipkin => ../example/zipkin + +replace go.opentelemetry.io/otel/exporters/prometheus => ../exporters/prometheus + +replace go.opentelemetry.io/otel/exporters/jaeger => ../exporters/jaeger + +replace go.opentelemetry.io/otel/exporters/zipkin => ../exporters/zipkin + +replace go.opentelemetry.io/otel/internal/tools => ../internal/tools + +replace go.opentelemetry.io/otel/metric => ./ + +replace go.opentelemetry.io/otel/sdk => ../sdk + +replace go.opentelemetry.io/otel/sdk/export/metric => ../sdk/export/metric + +replace go.opentelemetry.io/otel/sdk/metric => ../sdk/metric + +replace go.opentelemetry.io/otel/trace => ../trace + +replace go.opentelemetry.io/otel/example/passthrough => ../example/passthrough + +replace go.opentelemetry.io/otel/exporters/otlp/otlptrace => ../exporters/otlp/otlptrace + +replace go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc => ../exporters/otlp/otlptrace/otlptracegrpc + +replace go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp => ../exporters/otlp/otlptrace/otlptracehttp + +replace go.opentelemetry.io/otel/exporters/otlp/otlpmetric => ../exporters/otlp/otlpmetric + +replace go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc => ../exporters/otlp/otlpmetric/otlpmetricgrpc + +replace go.opentelemetry.io/otel/exporters/stdout/stdoutmetric => ../exporters/stdout/stdoutmetric + +replace go.opentelemetry.io/otel/exporters/stdout/stdouttrace => ../exporters/stdout/stdouttrace + +replace go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp => ../exporters/otlp/otlpmetric/otlpmetrichttp + +replace go.opentelemetry.io/otel/bridge/opencensus/test => ../bridge/opencensus/test + +replace go.opentelemetry.io/otel/example/fib => ../example/fib + +replace go.opentelemetry.io/otel/schema => ../schema + +replace go.opentelemetry.io/otel/exporters/otlp/internal/retry => ../exporters/otlp/internal/retry diff --git a/metric/go.sum b/metric/go.sum new file mode 100644 index 00000000000..5457c7626c5 --- /dev/null +++ b/metric/go.sum @@ -0,0 +1,15 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/metric/instrument/asyncfloat64/asyncfloat64.go b/metric/instrument/asyncfloat64/asyncfloat64.go new file mode 100644 index 00000000000..0e06b02c77a --- /dev/null +++ b/metric/instrument/asyncfloat64/asyncfloat64.go @@ -0,0 +1,70 @@ +// 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 asyncfloat64 // import "go.opentelemetry.io/otel/metric/instrument/asyncfloat64" + +import ( + "context" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric/instrument" +) + +// Instruments provides access to individual instruments. +type Instruments interface { + // Counter creates an instrument for recording increasing values. + Counter(name string, opts ...instrument.Option) (Counter, error) + + // UpDownCounter creates an instrument for recording changes of a value. + UpDownCounter(name string, opts ...instrument.Option) (UpDownCounter, error) + + // Gauge creates an instrument for recording the current value. + Gauge(name string, opts ...instrument.Option) (Gauge, error) +} + +// Counter is an instrument that records increasing values. +type Counter interface { + // Observe records the state of the instrument. + // + // It is only valid to call this within a callback. If called outside of the + // registered callback it should have no effect on the instrument, and an + // error will be reported via the error handeling + Observe(ctx context.Context, x float64, attrs ...attribute.KeyValue) + + instrument.Asynchronous +} + +// UpDownCounter is an instrument that records increasing or decresing values. +type UpDownCounter interface { + // Observe records the state of the instrument. + // + // It is only valid to call this within a callback. If called outside of the + // registered callback it should have no effect on the instrument, and an + // error will be reported via the error handeling + Observe(ctx context.Context, x float64, attrs ...attribute.KeyValue) + + instrument.Asynchronous +} + +// Gauge is an instrument that records independent readings. +type Gauge interface { + // Observe records the state of the instrument. + // + // It is only valid to call this within a callback. If called outside of the + // registered callback it should have no effect on the instrument, and an + // error will be reported via the error handeling + Observe(ctx context.Context, x float64, attrs ...attribute.KeyValue) + + instrument.Asynchronous +} diff --git a/metric/instrument/asyncint64/asyncint64.go b/metric/instrument/asyncint64/asyncint64.go new file mode 100644 index 00000000000..d965fe02910 --- /dev/null +++ b/metric/instrument/asyncint64/asyncint64.go @@ -0,0 +1,70 @@ +// 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 asyncint64 // import "go.opentelemetry.io/otel/metric/instrument/asyncint64" + +import ( + "context" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric/instrument" +) + +// Instruments provides access to individual instruments. +type Instruments interface { + // Counter creates an instrument for recording increasing values. + Counter(name string, opts ...instrument.Option) (Counter, error) + + // UpDownCounter creates an instrument for recording changes of a value. + UpDownCounter(name string, opts ...instrument.Option) (UpDownCounter, error) + + // Gauge creates an instrument for recording the current value. + Gauge(name string, opts ...instrument.Option) (Gauge, error) +} + +// Counter is an instrument that records increasing values. +type Counter interface { + // Observe records the state of the instrument. + // + // It is only valid to call this within a callback. If called outside of the + // registered callback it should have no effect on the instrument, and an + // error will be reported via the error handeling + Observe(ctx context.Context, x int64, attrs ...attribute.KeyValue) + + instrument.Asynchronous +} + +// UpDownCounter is an instrument that records increasing or decresing values. +type UpDownCounter interface { + // Observe records the state of the instrument. + // + // It is only valid to call this within a callback. If called outside of the + // registered callback it should have no effect on the instrument, and an + // error will be reported via the error handeling + Observe(ctx context.Context, x int64, attrs ...attribute.KeyValue) + + instrument.Asynchronous +} + +// Gauge is an instrument that records independent readings. +type Gauge interface { + // Observe records the state of the instrument. + // + // It is only valid to call this within a callback. If called outside of the + // registered callback it should have no effect on the instrument, and an + // error will be reported via the error handeling + Observe(ctx context.Context, x int64, attrs ...attribute.KeyValue) + + instrument.Asynchronous +} diff --git a/metric/instrument/config.go b/metric/instrument/config.go new file mode 100644 index 00000000000..b58a49fe866 --- /dev/null +++ b/metric/instrument/config.go @@ -0,0 +1,70 @@ +// 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 instrument // import "go.opentelemetry.io/otel/metric/instrument" + +import "go.opentelemetry.io/otel/metric/unit" + +// Config contains options for metric instrument descriptors. +type Config struct { + description string + unit unit.Unit +} + +// Description describes the instrument in human-readable terms. +func (cfg Config) Description() string { + return cfg.description +} + +// Unit describes the measurement unit for a instrument. +func (cfg Config) Unit() unit.Unit { + return cfg.unit +} + +// Option is an interface for applying metric instrument options. +type Option interface { + // ApplyMeter is used to set a Option value of a + // Config. + applyInstrument(*Config) +} + +// NewConfig creates a new Config +// and applies all the given options. +func NewConfig(opts ...Option) Config { + var config Config + for _, o := range opts { + o.applyInstrument(&config) + } + return config +} + +type optionFunc func(*Config) + +func (fn optionFunc) applyInstrument(cfg *Config) { + fn(cfg) +} + +// WithDescription applies provided description. +func WithDescription(desc string) Option { + return optionFunc(func(cfg *Config) { + cfg.description = desc + }) +} + +// WithUnit applies provided unit. +func WithUnit(unit unit.Unit) Option { + return optionFunc(func(cfg *Config) { + cfg.unit = unit + }) +} diff --git a/metric/instrument/instrument.go b/metric/instrument/instrument.go new file mode 100644 index 00000000000..e1bbb850d76 --- /dev/null +++ b/metric/instrument/instrument.go @@ -0,0 +1,30 @@ +// 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 instrument // import "go.opentelemetry.io/otel/metric/instrument" + +// Asynchronous instruments are instruments that are updated within a Callback. +// If an instrument is observed outside of it's callback it should be an error. +// +// This interface is used as a grouping mechanism. +type Asynchronous interface { + asynchronous() +} + +// Synchronous instruments are updated in line with application code. +// +// This interface is used as a grouping mechanism. +type Synchronous interface { + synchronous() +} diff --git a/metric/instrument/syncfloat64/syncfloat64.go b/metric/instrument/syncfloat64/syncfloat64.go new file mode 100644 index 00000000000..cd3d721535b --- /dev/null +++ b/metric/instrument/syncfloat64/syncfloat64.go @@ -0,0 +1,56 @@ +// 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 syncfloat64 // import "go.opentelemetry.io/otel/metric/instrument/syncfloat64" + +import ( + "context" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric/instrument" +) + +// Instruments provides access to individual instruments. +type Instruments interface { + // Counter creates an instrument for recording increasing values. + Counter(name string, opts ...instrument.Option) (Counter, error) + // UpDownCounter creates an instrument for recording changes of a value. + UpDownCounter(name string, opts ...instrument.Option) (UpDownCounter, error) + // Histogram creates an instrument for recording a distribution of values. + Histogram(name string, opts ...instrument.Option) (Histogram, error) +} + +// Counter is an instrument that records increasing values. +type Counter interface { + // Add records a change to the counter. + Add(ctx context.Context, incr float64, attrs ...attribute.KeyValue) + + instrument.Synchronous +} + +// UpDownCounter is an instrument that records increasing or decresing values. +type UpDownCounter interface { + // Add records a change to the counter. + Add(ctx context.Context, incr float64, attrs ...attribute.KeyValue) + + instrument.Synchronous +} + +// Histogram is an instrument that records a distribution of values. +type Histogram interface { + // Record adds an additional value to the distribution. + Record(ctx context.Context, incr float64, attrs ...attribute.KeyValue) + + instrument.Synchronous +} diff --git a/metric/instrument/syncint64/syncint64.go b/metric/instrument/syncint64/syncint64.go new file mode 100644 index 00000000000..96f99749b49 --- /dev/null +++ b/metric/instrument/syncint64/syncint64.go @@ -0,0 +1,56 @@ +// 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 syncint64 // import "go.opentelemetry.io/otel/metric/instrument/syncint64" + +import ( + "context" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric/instrument" +) + +// Instruments provides access to individual instruments. +type Instruments interface { + // Counter creates an instrument for recording increasing values. + Counter(name string, opts ...instrument.Option) (Counter, error) + // UpDownCounter creates an instrument for recording changes of a value. + UpDownCounter(name string, opts ...instrument.Option) (UpDownCounter, error) + // Histogram creates an instrument for recording a distribution of values. + Histogram(name string, opts ...instrument.Option) (Histogram, error) +} + +// Counter is an instrument that records increasing values. +type Counter interface { + // Add records a change to the counter. + Add(ctx context.Context, incr int64, attrs ...attribute.KeyValue) + + instrument.Synchronous +} + +// UpDownCounter is an instrument that records increasing or decresing values. +type UpDownCounter interface { + // Add records a change to the counter. + Add(ctx context.Context, incr int64, attrs ...attribute.KeyValue) + + instrument.Synchronous +} + +// Histogram is an instrument that records a distribution of values. +type Histogram interface { + // Record adds an additional value to the distribution. + Record(ctx context.Context, incr int64, attrs ...attribute.KeyValue) + + instrument.Synchronous +} diff --git a/metric/meter.go b/metric/meter.go new file mode 100644 index 00000000000..95da8ca6cd3 --- /dev/null +++ b/metric/meter.go @@ -0,0 +1,60 @@ +// 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 metric // import "go.opentelemetry.io/otel/metric" + +import ( + "context" + + "go.opentelemetry.io/otel/metric/instrument" + "go.opentelemetry.io/otel/metric/instrument/asyncfloat64" + "go.opentelemetry.io/otel/metric/instrument/asyncint64" + "go.opentelemetry.io/otel/metric/instrument/syncfloat64" + "go.opentelemetry.io/otel/metric/instrument/syncint64" +) + +// MeterProvider provides access to named Meter instances, for instrumenting +// an application or library. +type MeterProvider interface { + // Meter creates an instance of a `Meter` interface. The instrumentationName + // must be the name of the library providing instrumentation. This name may + // be the same as the instrumented code only if that code provides built-in + // instrumentation. If the instrumentationName is empty, then a + // implementation defined default name will be used instead. + Meter(instrumentationName string, opts ...MeterOption) Meter +} + +// Meter provides access to instrument instances for recording metrics. +type Meter interface { + // AsyncInt64 is the namespace for the Asynchronous Int instruments. + // + // To Observe data with instruments it must be registered in a callback. + AsyncInt64() asyncint64.Instruments + + // AsyncFloat64 is the namespace for the Asynchronous Float instruments + // + // To Observe data with instruments it must be registered in a callback. + AsyncFloat64() asyncfloat64.Instruments + + // RegisterCallback captures the function that will be called during Collect. + // + // It is only valid to call Observe within the soce of the passed function, + // and only on the instruments that were registered with this call. + RegisterCallback(insts []instrument.Asynchronous, function func(context.Context)) error + + // SyncInt64 is the namespace for the Synchronous Int instruments + SyncInt64() syncint64.Instruments + // SyncFloat64 is the namespace for the Synchronous Float instruments + SyncFloat64() syncfloat64.Instruments +} diff --git a/metric/unit/doc.go b/metric/unit/doc.go new file mode 100644 index 00000000000..f8e723593e6 --- /dev/null +++ b/metric/unit/doc.go @@ -0,0 +1,20 @@ +// 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 unit provides units. +// +// This package is currently in a pre-GA phase. Backwards incompatible changes +// may be introduced in subsequent minor version releases as we work to track +// the evolving OpenTelemetry specification and user feedback. +package unit // import "go.opentelemetry.io/otel/metric/unit" diff --git a/metric/unit/unit.go b/metric/unit/unit.go new file mode 100644 index 00000000000..4615eb16f69 --- /dev/null +++ b/metric/unit/unit.go @@ -0,0 +1,24 @@ +// 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 unit // import "go.opentelemetry.io/otel/metric/unit" + +type Unit string + +// Units defined by OpenTelemetry. +const ( + Dimensionless Unit = "1" + Bytes Unit = "By" + Milliseconds Unit = "ms" +) From 754d83c38037c8e1c7ade68361f3a03edb136104 Mon Sep 17 00:00:00 2001 From: Aaron Clawson Date: Wed, 26 Jan 2022 20:52:12 +0000 Subject: [PATCH 3/6] Add a NoOp implementation. --- metric/example_test.go | 113 +++++++++++++++++++++++++ metric/instrument/asyncfloat64/noop.go | 53 ++++++++++++ metric/instrument/asyncint64/noop.go | 52 ++++++++++++ metric/instrument/syncfloat64/noop.go | 57 +++++++++++++ metric/instrument/syncint64/noop.go | 54 ++++++++++++ metric/noop.go | 63 ++++++++++++++ 6 files changed, 392 insertions(+) create mode 100644 metric/example_test.go create mode 100644 metric/instrument/asyncfloat64/noop.go create mode 100644 metric/instrument/asyncint64/noop.go create mode 100644 metric/instrument/syncfloat64/noop.go create mode 100644 metric/instrument/syncint64/noop.go create mode 100644 metric/noop.go diff --git a/metric/example_test.go b/metric/example_test.go new file mode 100644 index 00000000000..11c0d637ca3 --- /dev/null +++ b/metric/example_test.go @@ -0,0 +1,113 @@ +// 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 metric_test + +import ( + "context" + "fmt" + "runtime" + "time" + + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/metric/instrument" + "go.opentelemetry.io/otel/metric/instrument/syncfloat64" + "go.opentelemetry.io/otel/metric/unit" +) + +func ExampleSyncInstrument() { + // In a library or program this would be provided by otel.GetMeterProvider(). + meterProvider := metric.NewNoopMeterProvider() + + workDuration, err := meterProvider.Meter("SyncExample").SyncInt64().Histogram( + "workDuration", + instrument.WithUnit(unit.Milliseconds)) + if err != nil { + fmt.Println("Failed to register instrument") + panic(err) + } + + startTime := time.Now() + ctx := context.Background() + // Do work + // ... + workDuration.Record(ctx, time.Now().Sub(startTime).Milliseconds()) + +} + +func ExampleAsyncInstrument() { + // In a library or program this would be provided by otel.GetMeterProvider(). + meterProvider := metric.NewNoopMeterProvider() + meter := meterProvider.Meter("AsyncExample") + + memoryUsage, err := meter.AsyncInt64().Gauge( + "MemoryUsage", + instrument.WithUnit(unit.Bytes), + ) + if err != nil { + fmt.Println("Failed to register instrument") + panic(err) + } + + err = meter.RegisterCallback([]instrument.Asynchronous{memoryUsage}, + func(ctx context.Context) { + // instrument.WithCallbackFunc(func(ctx context.Context) { + //Do Work to get the real memoryUsage + // mem := GatherMemory(ctx) + mem := 75000 + + memoryUsage.Observe(ctx, int64(mem)) + }) + if err != nil { + fmt.Println("Failed to register callback") + panic(err) + } +} + +func ExampleMultipleAsyncInstrument() { + meterProvider := metric.NewNoopMeterProvider() + meter := meterProvider.Meter("AsyncExample") + + // This is just a sample of memory stats to record from the Memstats + heapAlloc, _ := meter.AsyncInt64().UpDownCounter("heapAllocs") + gcCount, _ := meter.AsyncInt64().Counter("gcCount") + gcPause, _ := meter.SyncFloat64().Histogram("gcPause") + + err := meter.RegisterCallback([]instrument.Asynchronous{ + heapAlloc, + gcCount, + }, + func(ctx context.Context) { + memStats := &runtime.MemStats{} + // This call does work + runtime.ReadMemStats(memStats) + + heapAlloc.Observe(ctx, int64(memStats.HeapAlloc)) + gcCount.Observe(ctx, int64(memStats.NumGC)) + + // This function synchronously records the pauses + computeGCPauses(ctx, gcPause, memStats.PauseNs[:]) + }, + ) + + if err != nil { + fmt.Println("Failed to register callback") + panic(err) + } +} + +//This is just an example, see the the contrib runtime instrumentation for real implementation +func computeGCPauses(ctx context.Context, recorder syncfloat64.Histogram, pauseBuff []uint64) { + +} diff --git a/metric/instrument/asyncfloat64/noop.go b/metric/instrument/asyncfloat64/noop.go new file mode 100644 index 00000000000..2b6ce755085 --- /dev/null +++ b/metric/instrument/asyncfloat64/noop.go @@ -0,0 +1,53 @@ +// 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 asyncfloat64 // import "go.opentelemetry.io/otel/metric/instrument/asyncfloat64" + +import ( + "context" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric/instrument" +) + +func NewNoopInstruments() Instruments { + return nonrecordingInstrument{} +} + +type nonrecordingInstrument struct { + instrument.Asynchronous +} + +var ( + _ Instruments = nonrecordingInstrument{} + _ Counter = nonrecordingInstrument{} + _ UpDownCounter = nonrecordingInstrument{} + _ Gauge = nonrecordingInstrument{} +) + +func (n nonrecordingInstrument) Counter(name string, opts ...instrument.Option) (Counter, error) { + return n, nil +} + +func (n nonrecordingInstrument) UpDownCounter(name string, opts ...instrument.Option) (UpDownCounter, error) { + return n, nil +} + +func (n nonrecordingInstrument) Gauge(name string, opts ...instrument.Option) (Gauge, error) { + return n, nil +} + +func (nonrecordingInstrument) Observe(context.Context, float64, ...attribute.KeyValue) { + +} diff --git a/metric/instrument/asyncint64/noop.go b/metric/instrument/asyncint64/noop.go new file mode 100644 index 00000000000..d55bf48fd83 --- /dev/null +++ b/metric/instrument/asyncint64/noop.go @@ -0,0 +1,52 @@ +// 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 asyncint64 // import "go.opentelemetry.io/otel/metric/instrument/asyncint64" + +import ( + "context" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric/instrument" +) + +func NewNoopInstruments() Instruments { + return nonrecordingInstrument{} +} + +type nonrecordingInstrument struct { + instrument.Asynchronous +} + +var ( + _ Instruments = nonrecordingInstrument{} + _ Counter = nonrecordingInstrument{} + _ UpDownCounter = nonrecordingInstrument{} + _ Gauge = nonrecordingInstrument{} +) + +func (n nonrecordingInstrument) Counter(name string, opts ...instrument.Option) (Counter, error) { + return n, nil +} + +func (n nonrecordingInstrument) UpDownCounter(name string, opts ...instrument.Option) (UpDownCounter, error) { + return n, nil +} + +func (n nonrecordingInstrument) Gauge(name string, opts ...instrument.Option) (Gauge, error) { + return n, nil +} + +func (nonrecordingInstrument) Observe(context.Context, int64, ...attribute.KeyValue) { +} diff --git a/metric/instrument/syncfloat64/noop.go b/metric/instrument/syncfloat64/noop.go new file mode 100644 index 00000000000..2e7cfe56af9 --- /dev/null +++ b/metric/instrument/syncfloat64/noop.go @@ -0,0 +1,57 @@ +// 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 syncfloat64 // import "go.opentelemetry.io/otel/metric/instrument/syncfloat64" + +import ( + "context" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric/instrument" +) + +func NewNoopInstruments() Instruments { + return nonrecordingInstrument{} +} + +type nonrecordingInstrument struct { + instrument.Synchronous +} + +var ( + _ Instruments = nonrecordingInstrument{} + _ Counter = nonrecordingInstrument{} + _ UpDownCounter = nonrecordingInstrument{} + _ Histogram = nonrecordingInstrument{} +) + +func (n nonrecordingInstrument) Counter(name string, opts ...instrument.Option) (Counter, error) { + return n, nil +} + +func (n nonrecordingInstrument) UpDownCounter(name string, opts ...instrument.Option) (UpDownCounter, error) { + return n, nil +} + +func (n nonrecordingInstrument) Histogram(name string, opts ...instrument.Option) (Histogram, error) { + return n, nil +} + +func (nonrecordingInstrument) Add(context.Context, float64, ...attribute.KeyValue) { + +} + +func (nonrecordingInstrument) Record(context.Context, float64, ...attribute.KeyValue) { + +} diff --git a/metric/instrument/syncint64/noop.go b/metric/instrument/syncint64/noop.go new file mode 100644 index 00000000000..fc5d51c4f52 --- /dev/null +++ b/metric/instrument/syncint64/noop.go @@ -0,0 +1,54 @@ +// 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 syncint64 // import "go.opentelemetry.io/otel/metric/instrument/syncint64" + +import ( + "context" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric/instrument" +) + +func NewNoopInstruments() Instruments { + return nonrecordingInstrument{} +} + +type nonrecordingInstrument struct { + instrument.Synchronous +} + +var ( + _ Instruments = nonrecordingInstrument{} + _ Counter = nonrecordingInstrument{} + _ UpDownCounter = nonrecordingInstrument{} + _ Histogram = nonrecordingInstrument{} +) + +func (n nonrecordingInstrument) Counter(name string, opts ...instrument.Option) (Counter, error) { + return n, nil +} + +func (n nonrecordingInstrument) UpDownCounter(name string, opts ...instrument.Option) (UpDownCounter, error) { + return n, nil +} + +func (n nonrecordingInstrument) Histogram(name string, opts ...instrument.Option) (Histogram, error) { + return n, nil +} + +func (nonrecordingInstrument) Add(context.Context, int64, ...attribute.KeyValue) { +} +func (nonrecordingInstrument) Record(context.Context, int64, ...attribute.KeyValue) { +} diff --git a/metric/noop.go b/metric/noop.go new file mode 100644 index 00000000000..87ea2ad87aa --- /dev/null +++ b/metric/noop.go @@ -0,0 +1,63 @@ +// 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 metric // import "go.opentelemetry.io/otel/metric" + +import ( + "context" + + "go.opentelemetry.io/otel/metric/instrument" + "go.opentelemetry.io/otel/metric/instrument/asyncfloat64" + "go.opentelemetry.io/otel/metric/instrument/asyncint64" + "go.opentelemetry.io/otel/metric/instrument/syncfloat64" + "go.opentelemetry.io/otel/metric/instrument/syncint64" +) + +func NewNoopMeterProvider() MeterProvider { + return noopMeterProvider{} +} + +type noopMeterProvider struct{} + +var _ MeterProvider = noopMeterProvider{} + +func (noopMeterProvider) Meter(instrumentationName string, opts ...MeterOption) Meter { + return noopMeter{} +} + +type noopMeter struct{} + +var _ Meter = noopMeter{} + +func (noopMeter) AsyncInt64() asyncint64.Instruments { + return asyncint64.NewNoopInstruments() +} +func (noopMeter) AsyncFloat64() asyncfloat64.Instruments { + return asyncfloat64.NewNoopInstruments() +} +func (noopMeter) SyncInt64() syncint64.Instruments { + return syncint64.NewNoopInstruments() +} +func (noopMeter) SyncFloat64() syncfloat64.Instruments { + return syncfloat64.NewNoopInstruments() +} +func (noopMeter) RegisterCallback([]instrument.Asynchronous, func(context.Context)) error { + return nil +} + +type noopCallback struct{} + +func (noopCallback) Instruments() []instrument.Asynchronous { + return nil +} From b2dab0ccf5c124831485d928fcf0bab62eba5741 Mon Sep 17 00:00:00 2001 From: Aaron Clawson Date: Tue, 1 Feb 2022 21:56:27 +0000 Subject: [PATCH 4/6] Updated to the new config standard --- metric/config.go | 16 +++++++++------- metric/instrument/config.go | 16 +++++++++------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/metric/config.go b/metric/config.go index 9485217df2c..6049015cbe7 100644 --- a/metric/config.go +++ b/metric/config.go @@ -33,7 +33,7 @@ func (cfg MeterConfig) SchemaURL() string { // MeterOption is an interface for applying Meter options. type MeterOption interface { // ApplyMeter is used to set a MeterOption value of a MeterConfig. - applyMeter(*MeterConfig) + applyMeter(MeterConfig) MeterConfig } // NewMeterConfig creates a new MeterConfig and applies @@ -41,27 +41,29 @@ type MeterOption interface { func NewMeterConfig(opts ...MeterOption) MeterConfig { var config MeterConfig for _, o := range opts { - o.applyMeter(&config) + config = o.applyMeter(config) } return config } -type meterOptionFunc func(*MeterConfig) +type meterOptionFunc func(MeterConfig) MeterConfig -func (fn meterOptionFunc) applyMeter(cfg *MeterConfig) { - fn(cfg) +func (fn meterOptionFunc) applyMeter(cfg MeterConfig) MeterConfig { + return fn(cfg) } // WithInstrumentationVersion sets the instrumentation version. func WithInstrumentationVersion(version string) MeterOption { - return meterOptionFunc(func(config *MeterConfig) { + return meterOptionFunc(func(config MeterConfig) MeterConfig { config.instrumentationVersion = version + return config }) } // WithSchemaURL sets the schema URL. func WithSchemaURL(schemaURL string) MeterOption { - return meterOptionFunc(func(config *MeterConfig) { + return meterOptionFunc(func(config MeterConfig) MeterConfig { config.schemaURL = schemaURL + return config }) } diff --git a/metric/instrument/config.go b/metric/instrument/config.go index b58a49fe866..e486ce1c60d 100644 --- a/metric/instrument/config.go +++ b/metric/instrument/config.go @@ -36,7 +36,7 @@ func (cfg Config) Unit() unit.Unit { type Option interface { // ApplyMeter is used to set a Option value of a // Config. - applyInstrument(*Config) + applyInstrument(Config) Config } // NewConfig creates a new Config @@ -44,27 +44,29 @@ type Option interface { func NewConfig(opts ...Option) Config { var config Config for _, o := range opts { - o.applyInstrument(&config) + config = o.applyInstrument(config) } return config } -type optionFunc func(*Config) +type optionFunc func(Config) Config -func (fn optionFunc) applyInstrument(cfg *Config) { - fn(cfg) +func (fn optionFunc) applyInstrument(cfg Config) Config { + return fn(cfg) } // WithDescription applies provided description. func WithDescription(desc string) Option { - return optionFunc(func(cfg *Config) { + return optionFunc(func(cfg Config) Config { cfg.description = desc + return cfg }) } // WithUnit applies provided unit. func WithUnit(unit unit.Unit) Option { - return optionFunc(func(cfg *Config) { + return optionFunc(func(cfg Config) Config { cfg.unit = unit + return cfg }) } From a92285c38d568040efaf8eb41413115b7f3aad03 Mon Sep 17 00:00:00 2001 From: Aaron Clawson Date: Tue, 1 Feb 2022 22:00:46 +0000 Subject: [PATCH 5/6] fix grammer. --- metric/instrument/asyncfloat64/asyncfloat64.go | 6 +++--- metric/instrument/asyncint64/asyncint64.go | 6 +++--- metric/meter.go | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/metric/instrument/asyncfloat64/asyncfloat64.go b/metric/instrument/asyncfloat64/asyncfloat64.go index 0e06b02c77a..aae69b138c5 100644 --- a/metric/instrument/asyncfloat64/asyncfloat64.go +++ b/metric/instrument/asyncfloat64/asyncfloat64.go @@ -39,7 +39,7 @@ type Counter interface { // // It is only valid to call this within a callback. If called outside of the // registered callback it should have no effect on the instrument, and an - // error will be reported via the error handeling + // error will be reported via the error handler. Observe(ctx context.Context, x float64, attrs ...attribute.KeyValue) instrument.Asynchronous @@ -51,7 +51,7 @@ type UpDownCounter interface { // // It is only valid to call this within a callback. If called outside of the // registered callback it should have no effect on the instrument, and an - // error will be reported via the error handeling + // error will be reported via the error handler. Observe(ctx context.Context, x float64, attrs ...attribute.KeyValue) instrument.Asynchronous @@ -63,7 +63,7 @@ type Gauge interface { // // It is only valid to call this within a callback. If called outside of the // registered callback it should have no effect on the instrument, and an - // error will be reported via the error handeling + // error will be reported via the error handler. Observe(ctx context.Context, x float64, attrs ...attribute.KeyValue) instrument.Asynchronous diff --git a/metric/instrument/asyncint64/asyncint64.go b/metric/instrument/asyncint64/asyncint64.go index d965fe02910..ad3668e2183 100644 --- a/metric/instrument/asyncint64/asyncint64.go +++ b/metric/instrument/asyncint64/asyncint64.go @@ -39,7 +39,7 @@ type Counter interface { // // It is only valid to call this within a callback. If called outside of the // registered callback it should have no effect on the instrument, and an - // error will be reported via the error handeling + // error will be reported via the error handler. Observe(ctx context.Context, x int64, attrs ...attribute.KeyValue) instrument.Asynchronous @@ -51,7 +51,7 @@ type UpDownCounter interface { // // It is only valid to call this within a callback. If called outside of the // registered callback it should have no effect on the instrument, and an - // error will be reported via the error handeling + // error will be reported via the error handler. Observe(ctx context.Context, x int64, attrs ...attribute.KeyValue) instrument.Asynchronous @@ -63,7 +63,7 @@ type Gauge interface { // // It is only valid to call this within a callback. If called outside of the // registered callback it should have no effect on the instrument, and an - // error will be reported via the error handeling + // error will be reported via the error handler. Observe(ctx context.Context, x int64, attrs ...attribute.KeyValue) instrument.Asynchronous diff --git a/metric/meter.go b/metric/meter.go index 95da8ca6cd3..49a6b2a2d61 100644 --- a/metric/meter.go +++ b/metric/meter.go @@ -49,7 +49,7 @@ type Meter interface { // RegisterCallback captures the function that will be called during Collect. // - // It is only valid to call Observe within the soce of the passed function, + // It is only valid to call Observe within the scope of the passed function, // and only on the instruments that were registered with this call. RegisterCallback(insts []instrument.Asynchronous, function func(context.Context)) error From ad95b08ec4b9e26f23280512788b52fc46d39629 Mon Sep 17 00:00:00 2001 From: Aaron Clawson Date: Thu, 3 Feb 2022 20:48:47 +0000 Subject: [PATCH 6/6] Address PR comments --- metric/example_test.go | 6 +++--- metric/instrument/config.go | 5 +---- metric/meter.go | 4 ++-- metric/noop.go | 6 ------ 4 files changed, 6 insertions(+), 15 deletions(-) diff --git a/metric/example_test.go b/metric/example_test.go index 11c0d637ca3..573d7070dd4 100644 --- a/metric/example_test.go +++ b/metric/example_test.go @@ -30,7 +30,7 @@ func ExampleSyncInstrument() { // In a library or program this would be provided by otel.GetMeterProvider(). meterProvider := metric.NewNoopMeterProvider() - workDuration, err := meterProvider.Meter("SyncExample").SyncInt64().Histogram( + workDuration, err := meterProvider.Meter("go.opentelemetry.io/otel/metric#SyncExample").SyncInt64().Histogram( "workDuration", instrument.WithUnit(unit.Milliseconds)) if err != nil { @@ -49,7 +49,7 @@ func ExampleSyncInstrument() { func ExampleAsyncInstrument() { // In a library or program this would be provided by otel.GetMeterProvider(). meterProvider := metric.NewNoopMeterProvider() - meter := meterProvider.Meter("AsyncExample") + meter := meterProvider.Meter("go.opentelemetry.io/otel/metric#AsyncExample") memoryUsage, err := meter.AsyncInt64().Gauge( "MemoryUsage", @@ -77,7 +77,7 @@ func ExampleAsyncInstrument() { func ExampleMultipleAsyncInstrument() { meterProvider := metric.NewNoopMeterProvider() - meter := meterProvider.Meter("AsyncExample") + meter := meterProvider.Meter("go.opentelemetry.io/otel/metric#MultiAsyncExample") // This is just a sample of memory stats to record from the Memstats heapAlloc, _ := meter.AsyncInt64().UpDownCounter("heapAllocs") diff --git a/metric/instrument/config.go b/metric/instrument/config.go index e486ce1c60d..d6ea25a8da2 100644 --- a/metric/instrument/config.go +++ b/metric/instrument/config.go @@ -34,13 +34,10 @@ func (cfg Config) Unit() unit.Unit { // Option is an interface for applying metric instrument options. type Option interface { - // ApplyMeter is used to set a Option value of a - // Config. applyInstrument(Config) Config } -// NewConfig creates a new Config -// and applies all the given options. +// NewConfig creates a new Config and applies all the given options. func NewConfig(opts ...Option) Config { var config Config for _, o := range opts { diff --git a/metric/meter.go b/metric/meter.go index 49a6b2a2d61..b79e6433db1 100644 --- a/metric/meter.go +++ b/metric/meter.go @@ -37,7 +37,7 @@ type MeterProvider interface { // Meter provides access to instrument instances for recording metrics. type Meter interface { - // AsyncInt64 is the namespace for the Asynchronous Int instruments. + // AsyncInt64 is the namespace for the Asynchronous Integer instruments. // // To Observe data with instruments it must be registered in a callback. AsyncInt64() asyncint64.Instruments @@ -53,7 +53,7 @@ type Meter interface { // and only on the instruments that were registered with this call. RegisterCallback(insts []instrument.Asynchronous, function func(context.Context)) error - // SyncInt64 is the namespace for the Synchronous Int instruments + // SyncInt64 is the namespace for the Synchronous Integer instruments SyncInt64() syncint64.Instruments // SyncFloat64 is the namespace for the Synchronous Float instruments SyncFloat64() syncfloat64.Instruments diff --git a/metric/noop.go b/metric/noop.go index 87ea2ad87aa..975c0236012 100644 --- a/metric/noop.go +++ b/metric/noop.go @@ -55,9 +55,3 @@ func (noopMeter) SyncFloat64() syncfloat64.Instruments { func (noopMeter) RegisterCallback([]instrument.Asynchronous, func(context.Context)) error { return nil } - -type noopCallback struct{} - -func (noopCallback) Instruments() []instrument.Asynchronous { - return nil -}