mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-03-21 21:17:35 +02:00
[API EPIC 4/4] Fix tests and examples (#2587)
* Empty All of the metrics dir * Add instrument api with documentation * Add a NoOp implementation. * Updated to the new config standard * Address PR comments * This change moves components to sdk/metrics The Moved components are: - metric/metrictest - metric/number - metric/internal/registry - metric/sdkapi * The SDK changes necessary to satasify the new api * This fixes the remaing tests. * Update changelog * refactor the Noop meter and instruments into one package. * Renamed pkg.Instruments to pkg.InstrumentProvider Co-authored-by: Aaron Clawson <MadVikingGod@users.noreply.github.com>
This commit is contained in:
parent
b66c902777
commit
18f4cb85ec
9
.github/dependabot.yml
vendored
9
.github/dependabot.yml
vendored
@ -227,15 +227,6 @@ updates:
|
||||
schedule:
|
||||
day: sunday
|
||||
interval: weekly
|
||||
- package-ecosystem: gomod
|
||||
directory: /internal/metric
|
||||
labels:
|
||||
- dependencies
|
||||
- go
|
||||
- "Skip Changelog"
|
||||
schedule:
|
||||
day: sunday
|
||||
interval: weekly
|
||||
- package-ecosystem: gomod
|
||||
directory: /internal/tools
|
||||
labels:
|
||||
|
@ -8,6 +8,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### ⚠️ Notice ⚠️
|
||||
|
||||
This update is a breaking change of the unstable Metrics API. Code instrumented with the `go.opentelemetry.io/otel/metric` <= v0.27.0 will need to be modified.
|
||||
|
||||
### Added
|
||||
|
||||
- Added support to configure the span limits with environment variables.
|
||||
@ -24,6 +28,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
||||
|
||||
- For tracestate's members, prepend the new element and remove the oldest one, which is over capacity (#2592)
|
||||
- Add event and link drop counts to the exported data from the `oltptrace` exporter. (#2601)
|
||||
- The metrics API has been significantly changed. (#2587)
|
||||
- Unify path cleaning functionally in the `otlpmetric` and `otlptrace` config. (#2639)
|
||||
- Change the debug message from the `sdk/trace.BatchSpanProcessor` to reflect the count is cumulative. (#2640)
|
||||
|
||||
|
@ -21,8 +21,8 @@ import (
|
||||
|
||||
"go.opencensus.io/metric/metricdata"
|
||||
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -27,13 +27,13 @@ import (
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/metric/instrument"
|
||||
"go.opentelemetry.io/otel/metric/unit"
|
||||
"go.opentelemetry.io/otel/sdk/instrumentation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
)
|
||||
|
||||
@ -170,17 +170,17 @@ func convertDescriptor(ocDescriptor metricdata.Descriptor) (sdkapi.Descriptor, e
|
||||
// Includes TypeGaugeDistribution, TypeCumulativeDistribution, TypeSummary
|
||||
return sdkapi.Descriptor{}, fmt.Errorf("%w; descriptor type: %v", errConversion, ocDescriptor.Type)
|
||||
}
|
||||
opts := []metric.InstrumentOption{
|
||||
metric.WithDescription(ocDescriptor.Description),
|
||||
opts := []instrument.Option{
|
||||
instrument.WithDescription(ocDescriptor.Description),
|
||||
}
|
||||
switch ocDescriptor.Unit {
|
||||
case metricdata.UnitDimensionless:
|
||||
opts = append(opts, metric.WithUnit(unit.Dimensionless))
|
||||
opts = append(opts, instrument.WithUnit(unit.Dimensionless))
|
||||
case metricdata.UnitBytes:
|
||||
opts = append(opts, metric.WithUnit(unit.Bytes))
|
||||
opts = append(opts, instrument.WithUnit(unit.Bytes))
|
||||
case metricdata.UnitMilliseconds:
|
||||
opts = append(opts, metric.WithUnit(unit.Milliseconds))
|
||||
opts = append(opts, instrument.WithUnit(unit.Milliseconds))
|
||||
}
|
||||
cfg := metric.NewInstrumentConfig(opts...)
|
||||
cfg := instrument.NewConfig(opts...)
|
||||
return sdkapi.NewDescriptor(ocDescriptor.Name, ikind, nkind, cfg.Description(), cfg.Unit()), nil
|
||||
}
|
||||
|
@ -26,15 +26,15 @@ import (
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
"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/instrument"
|
||||
"go.opentelemetry.io/otel/metric/unit"
|
||||
"go.opentelemetry.io/otel/sdk/instrumentation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/controller/controllertest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/metrictest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
)
|
||||
|
||||
@ -400,8 +400,8 @@ func TestConvertDescriptor(t *testing.T) {
|
||||
"foo",
|
||||
sdkapi.GaugeObserverInstrumentKind,
|
||||
number.Int64Kind,
|
||||
metric.WithDescription("bar"),
|
||||
metric.WithUnit(unit.Bytes),
|
||||
instrument.WithDescription("bar"),
|
||||
instrument.WithUnit(unit.Bytes),
|
||||
),
|
||||
},
|
||||
{
|
||||
@ -416,8 +416,8 @@ func TestConvertDescriptor(t *testing.T) {
|
||||
"foo",
|
||||
sdkapi.GaugeObserverInstrumentKind,
|
||||
number.Float64Kind,
|
||||
metric.WithDescription("bar"),
|
||||
metric.WithUnit(unit.Milliseconds),
|
||||
instrument.WithDescription("bar"),
|
||||
instrument.WithUnit(unit.Milliseconds),
|
||||
),
|
||||
},
|
||||
{
|
||||
@ -432,8 +432,8 @@ func TestConvertDescriptor(t *testing.T) {
|
||||
"foo",
|
||||
sdkapi.CounterObserverInstrumentKind,
|
||||
number.Int64Kind,
|
||||
metric.WithDescription("bar"),
|
||||
metric.WithUnit(unit.Dimensionless),
|
||||
instrument.WithDescription("bar"),
|
||||
instrument.WithUnit(unit.Dimensionless),
|
||||
),
|
||||
},
|
||||
{
|
||||
@ -448,8 +448,8 @@ func TestConvertDescriptor(t *testing.T) {
|
||||
"foo",
|
||||
sdkapi.CounterObserverInstrumentKind,
|
||||
number.Float64Kind,
|
||||
metric.WithDescription("bar"),
|
||||
metric.WithUnit(unit.Dimensionless),
|
||||
instrument.WithDescription("bar"),
|
||||
instrument.WithUnit(unit.Dimensionless),
|
||||
),
|
||||
},
|
||||
{
|
||||
|
@ -25,7 +25,7 @@ import (
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/exporters/prometheus"
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
"go.opentelemetry.io/otel/metric/global"
|
||||
"go.opentelemetry.io/otel/metric/instrument"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator/histogram"
|
||||
controller "go.opentelemetry.io/otel/sdk/metric/controller/basic"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
@ -35,6 +35,9 @@ import (
|
||||
|
||||
var (
|
||||
lemonsKey = attribute.Key("ex.com/lemons")
|
||||
|
||||
// TODO Bring back Global package
|
||||
meterProvider metric.MeterProvider
|
||||
)
|
||||
|
||||
func initMeter() {
|
||||
@ -54,7 +57,9 @@ func initMeter() {
|
||||
if err != nil {
|
||||
log.Panicf("failed to initialize prometheus exporter %v", err)
|
||||
}
|
||||
global.SetMeterProvider(exporter.MeterProvider())
|
||||
// TODO Bring back Global package
|
||||
// global.SetMeterProvider(exporter.MeterProvider())
|
||||
meterProvider = exporter.MeterProvider()
|
||||
|
||||
http.HandleFunc("/", exporter.ServeHTTP)
|
||||
go func() {
|
||||
@ -67,23 +72,33 @@ func initMeter() {
|
||||
func main() {
|
||||
initMeter()
|
||||
|
||||
meter := global.Meter("ex.com/basic")
|
||||
// TODO Bring back Global package
|
||||
// meter := global.Meter("ex.com/basic")
|
||||
meter := meterProvider.Meter("ex.com/basic")
|
||||
observerLock := new(sync.RWMutex)
|
||||
observerValueToReport := new(float64)
|
||||
observerLabelsToReport := new([]attribute.KeyValue)
|
||||
cb := func(_ context.Context, result metric.Float64ObserverResult) {
|
||||
|
||||
gaugeObserver, err := meter.AsyncFloat64().Gauge("ex.com.one")
|
||||
if err != nil {
|
||||
log.Panicf("failed to initialize instrument: %v", err)
|
||||
}
|
||||
_ = meter.RegisterCallback([]instrument.Asynchronous{gaugeObserver}, func(ctx context.Context) {
|
||||
(*observerLock).RLock()
|
||||
value := *observerValueToReport
|
||||
labels := *observerLabelsToReport
|
||||
(*observerLock).RUnlock()
|
||||
result.Observe(value, labels...)
|
||||
}
|
||||
_ = metric.Must(meter).NewFloat64GaugeObserver("ex.com.one", cb,
|
||||
metric.WithDescription("A GaugeObserver set to 1.0"),
|
||||
)
|
||||
gaugeObserver.Observe(ctx, value, labels...)
|
||||
})
|
||||
|
||||
histogram := metric.Must(meter).NewFloat64Histogram("ex.com.two")
|
||||
counter := metric.Must(meter).NewFloat64Counter("ex.com.three")
|
||||
histogram, err := meter.SyncFloat64().Histogram("ex.com.two")
|
||||
if err != nil {
|
||||
log.Panicf("failed to initialize instrument: %v", err)
|
||||
}
|
||||
counter, err := meter.SyncFloat64().Counter("ex.com.three")
|
||||
if err != nil {
|
||||
log.Panicf("failed to initialize instrument: %v", err)
|
||||
}
|
||||
|
||||
commonLabels := []attribute.KeyValue{lemonsKey.Int(10), attribute.String("A", "1"), attribute.String("B", "2"), attribute.String("C", "3")}
|
||||
notSoCommonLabels := []attribute.KeyValue{lemonsKey.Int(13)}
|
||||
@ -94,12 +109,9 @@ func main() {
|
||||
*observerValueToReport = 1.0
|
||||
*observerLabelsToReport = commonLabels
|
||||
(*observerLock).Unlock()
|
||||
meter.RecordBatch(
|
||||
ctx,
|
||||
commonLabels,
|
||||
histogram.Measurement(2.0),
|
||||
counter.Measurement(12.0),
|
||||
)
|
||||
|
||||
histogram.Record(ctx, 2.0, commonLabels...)
|
||||
counter.Add(ctx, 12.0, commonLabels...)
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
@ -107,12 +119,8 @@ func main() {
|
||||
*observerValueToReport = 1.0
|
||||
*observerLabelsToReport = notSoCommonLabels
|
||||
(*observerLock).Unlock()
|
||||
meter.RecordBatch(
|
||||
ctx,
|
||||
notSoCommonLabels,
|
||||
histogram.Measurement(2.0),
|
||||
counter.Measurement(22.0),
|
||||
)
|
||||
histogram.Record(ctx, 2.0, notSoCommonLabels...)
|
||||
counter.Add(ctx, 22.0, notSoCommonLabels...)
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
@ -120,12 +128,8 @@ func main() {
|
||||
*observerValueToReport = 13.0
|
||||
*observerLabelsToReport = commonLabels
|
||||
(*observerLock).Unlock()
|
||||
meter.RecordBatch(
|
||||
ctx,
|
||||
commonLabels,
|
||||
histogram.Measurement(12.0),
|
||||
counter.Measurement(13.0),
|
||||
)
|
||||
histogram.Record(ctx, 12.0, commonLabels...)
|
||||
counter.Add(ctx, 13.0, commonLabels...)
|
||||
|
||||
fmt.Println("Example finished updating, please visit :2222")
|
||||
|
||||
|
@ -20,9 +20,9 @@ import (
|
||||
"sync"
|
||||
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/internal/metrictransform"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
)
|
||||
|
||||
|
@ -29,16 +29,16 @@ import (
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/internal/metrictransform"
|
||||
"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/sdk/instrumentation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator/histogram"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator/sum"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/metrictest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/processor/processortest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
commonpb "go.opentelemetry.io/proto/otlp/common/v1"
|
||||
metricpb "go.opentelemetry.io/proto/otlp/metrics/v1"
|
||||
|
@ -24,10 +24,10 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/instrumentation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
commonpb "go.opentelemetry.io/proto/otlp/common/v1"
|
||||
metricpb "go.opentelemetry.io/proto/otlp/metrics/v1"
|
||||
|
@ -25,14 +25,14 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/metric/metrictest"
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator/lastvalue"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator/sum"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/metrictest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
commonpb "go.opentelemetry.io/proto/otlp/common/v1"
|
||||
metricpb "go.opentelemetry.io/proto/otlp/metrics/v1"
|
||||
)
|
||||
|
@ -20,13 +20,13 @@ import (
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/metric/metrictest"
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/instrumentation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator/sum"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export"
|
||||
"go.opentelemetry.io/otel/sdk/metric/metrictest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/processor/processortest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
// OneRecordReader is a Reader that returns just one
|
||||
|
@ -25,12 +25,12 @@ import (
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric"
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/metric/instrument"
|
||||
controller "go.opentelemetry.io/otel/sdk/metric/controller/basic"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
processor "go.opentelemetry.io/otel/sdk/metric/processor/basic"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/metric/selector/simple"
|
||||
metricpb "go.opentelemetry.io/proto/otlp/metrics/v1"
|
||||
)
|
||||
@ -63,34 +63,37 @@ func RunEndToEndTest(ctx context.Context, t *testing.T, exp *otlpmetric.Exporter
|
||||
case sdkapi.CounterInstrumentKind:
|
||||
switch data.nKind {
|
||||
case number.Int64Kind:
|
||||
metric.Must(meter).NewInt64Counter(name).Add(ctx, data.val, labels...)
|
||||
c, _ := meter.SyncInt64().Counter(name)
|
||||
c.Add(ctx, data.val, labels...)
|
||||
case number.Float64Kind:
|
||||
metric.Must(meter).NewFloat64Counter(name).Add(ctx, float64(data.val), labels...)
|
||||
c, _ := meter.SyncFloat64().Counter(name)
|
||||
c.Add(ctx, float64(data.val), labels...)
|
||||
default:
|
||||
assert.Failf(t, "unsupported number testing kind", data.nKind.String())
|
||||
}
|
||||
case sdkapi.HistogramInstrumentKind:
|
||||
switch data.nKind {
|
||||
case number.Int64Kind:
|
||||
metric.Must(meter).NewInt64Histogram(name).Record(ctx, data.val, labels...)
|
||||
c, _ := meter.SyncInt64().Histogram(name)
|
||||
c.Record(ctx, data.val, labels...)
|
||||
case number.Float64Kind:
|
||||
metric.Must(meter).NewFloat64Histogram(name).Record(ctx, float64(data.val), labels...)
|
||||
c, _ := meter.SyncFloat64().Histogram(name)
|
||||
c.Record(ctx, float64(data.val), labels...)
|
||||
default:
|
||||
assert.Failf(t, "unsupported number testing kind", data.nKind.String())
|
||||
}
|
||||
case sdkapi.GaugeObserverInstrumentKind:
|
||||
switch data.nKind {
|
||||
case number.Int64Kind:
|
||||
metric.Must(meter).NewInt64GaugeObserver(name,
|
||||
func(_ context.Context, result metric.Int64ObserverResult) {
|
||||
result.Observe(data.val, labels...)
|
||||
},
|
||||
)
|
||||
g, _ := meter.AsyncInt64().Gauge(name)
|
||||
_ = meter.RegisterCallback([]instrument.Asynchronous{g}, func(ctx context.Context) {
|
||||
g.Observe(ctx, data.val, labels...)
|
||||
})
|
||||
case number.Float64Kind:
|
||||
callback := func(v float64) metric.Float64ObserverFunc {
|
||||
return metric.Float64ObserverFunc(func(_ context.Context, result metric.Float64ObserverResult) { result.Observe(v, labels...) })
|
||||
}(float64(data.val))
|
||||
metric.Must(meter).NewFloat64GaugeObserver(name, callback)
|
||||
g, _ := meter.AsyncFloat64().Gauge(name)
|
||||
_ = meter.RegisterCallback([]instrument.Asynchronous{g}, func(ctx context.Context) {
|
||||
g.Observe(ctx, float64(data.val), labels...)
|
||||
})
|
||||
default:
|
||||
assert.Failf(t, "unsupported number testing kind", data.nKind.String())
|
||||
}
|
||||
|
@ -24,8 +24,7 @@ import (
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
"go.opentelemetry.io/otel/metric/global"
|
||||
"go.opentelemetry.io/otel/metric/instrument"
|
||||
controller "go.opentelemetry.io/otel/sdk/metric/controller/basic"
|
||||
processor "go.opentelemetry.io/otel/sdk/metric/processor/basic"
|
||||
"go.opentelemetry.io/otel/sdk/metric/selector/simple"
|
||||
@ -54,7 +53,8 @@ func Example_insecure() {
|
||||
controller.WithExporter(exp),
|
||||
controller.WithCollectPeriod(2*time.Second),
|
||||
)
|
||||
global.SetMeterProvider(pusher)
|
||||
// TODO Bring back Global package
|
||||
// global.SetMeterProvider(pusher)
|
||||
|
||||
if err := pusher.Start(ctx); err != nil {
|
||||
log.Fatalf("could not start metric controoler: %v", err)
|
||||
@ -68,14 +68,16 @@ func Example_insecure() {
|
||||
}
|
||||
}()
|
||||
|
||||
meter := global.Meter("test-meter")
|
||||
// TODO Bring Back Global package
|
||||
// meter := global.Meter("go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc_test")
|
||||
meter := pusher.Meter("go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc_test")
|
||||
|
||||
// Recorder metric example
|
||||
counter := metric.Must(meter).
|
||||
NewFloat64Counter(
|
||||
"an_important_metric",
|
||||
metric.WithDescription("Measures the cumulative epicness of the app"),
|
||||
)
|
||||
|
||||
counter, err := meter.SyncFloat64().Counter("an_important_metric", instrument.WithDescription("Measures the cumulative epicness of the app"))
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create the instrument: %v", err)
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
log.Printf("Doing really hard work (%d / 10)\n", i+1)
|
||||
@ -113,7 +115,8 @@ func Example_withTLS() {
|
||||
controller.WithExporter(exp),
|
||||
controller.WithCollectPeriod(2*time.Second),
|
||||
)
|
||||
global.SetMeterProvider(pusher)
|
||||
// TODO Bring back Global package
|
||||
// global.SetMeterProvider(pusher)
|
||||
|
||||
if err := pusher.Start(ctx); err != nil {
|
||||
log.Fatalf("could not start metric controoler: %v", err)
|
||||
@ -128,14 +131,15 @@ func Example_withTLS() {
|
||||
}
|
||||
}()
|
||||
|
||||
meter := global.Meter("test-meter")
|
||||
// TODO Bring back Global package
|
||||
// meter := global.Meter("go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc_test")
|
||||
meter := pusher.Meter("go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc_test")
|
||||
|
||||
// Recorder metric example
|
||||
counter := metric.Must(meter).
|
||||
NewFloat64Counter(
|
||||
"an_important_metric",
|
||||
metric.WithDescription("Measures the cumulative epicness of the app"),
|
||||
)
|
||||
counter, err := meter.SyncFloat64().Counter("an_important_metric", instrument.WithDescription("Measures the cumulative epicness of the app"))
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create the instrument: %v", err)
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
log.Printf("Doing really hard work (%d / 10)\n", i+1)
|
||||
@ -170,7 +174,8 @@ func Example_withDifferentSignalCollectors() {
|
||||
controller.WithExporter(exp),
|
||||
controller.WithCollectPeriod(2*time.Second),
|
||||
)
|
||||
global.SetMeterProvider(pusher)
|
||||
// TODO Bring back Global package
|
||||
// global.SetMeterProvider(pusher)
|
||||
|
||||
if err := pusher.Start(ctx); err != nil {
|
||||
log.Fatalf("could not start metric controoler: %v", err)
|
||||
@ -184,14 +189,15 @@ func Example_withDifferentSignalCollectors() {
|
||||
}
|
||||
}()
|
||||
|
||||
meter := global.Meter("test-meter")
|
||||
// TODO Bring back Global package
|
||||
// meter := global.Meter("go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc_test")
|
||||
meter := pusher.Meter("go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc_test")
|
||||
|
||||
// Recorder metric example
|
||||
counter := metric.Must(meter).
|
||||
NewFloat64Counter(
|
||||
"an_important_metric",
|
||||
metric.WithDescription("Measures the cumulative epicness of the app"),
|
||||
)
|
||||
counter, err := meter.SyncFloat64().Counter("an_important_metric", instrument.WithDescription("Measures the cumulative epicness of the app"))
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create the instrument: %v", err)
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
log.Printf("Doing really hard work (%d / 10)\n", i+1)
|
||||
|
@ -29,12 +29,12 @@ import (
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/instrumentation"
|
||||
controller "go.opentelemetry.io/otel/sdk/metric/controller/basic"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
)
|
||||
|
||||
|
@ -26,7 +26,7 @@ import (
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/exporters/prometheus"
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
"go.opentelemetry.io/otel/metric/instrument"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator/histogram"
|
||||
controller "go.opentelemetry.io/otel/sdk/metric/controller/basic"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
@ -107,9 +107,12 @@ func TestPrometheusExporter(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
meter := exporter.MeterProvider().Meter("test")
|
||||
upDownCounter := metric.Must(meter).NewFloat64UpDownCounter("updowncounter")
|
||||
counter := metric.Must(meter).NewFloat64Counter("counter")
|
||||
histogram := metric.Must(meter).NewFloat64Histogram("histogram")
|
||||
upDownCounter, err := meter.SyncFloat64().UpDownCounter("updowncounter")
|
||||
require.NoError(t, err)
|
||||
counter, err := meter.SyncFloat64().Counter("counter")
|
||||
require.NoError(t, err)
|
||||
histogram, err := meter.SyncFloat64().Histogram("histogram")
|
||||
require.NoError(t, err)
|
||||
|
||||
labels := []attribute.KeyValue{
|
||||
attribute.Key("A").String("B"),
|
||||
@ -124,9 +127,13 @@ func TestPrometheusExporter(t *testing.T) {
|
||||
|
||||
expected = append(expected, expectCounter("counter", `counter{A="B",C="D",R="V"} 15.3`))
|
||||
|
||||
_ = metric.Must(meter).NewInt64GaugeObserver("intgaugeobserver", func(_ context.Context, result metric.Int64ObserverResult) {
|
||||
result.Observe(1, labels...)
|
||||
gaugeObserver, err := meter.AsyncInt64().Gauge("intgaugeobserver")
|
||||
require.NoError(t, err)
|
||||
|
||||
err = meter.RegisterCallback([]instrument.Asynchronous{gaugeObserver}, func(ctx context.Context) {
|
||||
gaugeObserver.Observe(ctx, 1, labels...)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
expected = append(expected, expectGauge("intgaugeobserver", `intgaugeobserver{A="B",C="D",R="V"} 1`))
|
||||
|
||||
@ -148,15 +155,23 @@ func TestPrometheusExporter(t *testing.T) {
|
||||
|
||||
expected = append(expected, expectGauge("updowncounter", `updowncounter{A="B",C="D",R="V"} 6.8`))
|
||||
|
||||
_ = metric.Must(meter).NewFloat64CounterObserver("floatcounterobserver", func(_ context.Context, result metric.Float64ObserverResult) {
|
||||
result.Observe(7.7, labels...)
|
||||
counterObserver, err := meter.AsyncFloat64().Counter("floatcounterobserver")
|
||||
require.NoError(t, err)
|
||||
|
||||
err = meter.RegisterCallback([]instrument.Asynchronous{counterObserver}, func(ctx context.Context) {
|
||||
counterObserver.Observe(ctx, 7.7, labels...)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
expected = append(expected, expectCounter("floatcounterobserver", `floatcounterobserver{A="B",C="D",R="V"} 7.7`))
|
||||
|
||||
_ = metric.Must(meter).NewFloat64UpDownCounterObserver("floatupdowncounterobserver", func(_ context.Context, result metric.Float64ObserverResult) {
|
||||
result.Observe(-7.7, labels...)
|
||||
upDownCounterObserver, err := meter.AsyncFloat64().UpDownCounter("floatupdowncounterobserver")
|
||||
require.NoError(t, err)
|
||||
|
||||
err = meter.RegisterCallback([]instrument.Asynchronous{upDownCounterObserver}, func(ctx context.Context) {
|
||||
upDownCounterObserver.Observe(ctx, -7.7, labels...)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
expected = append(expected, expectGauge("floatupdowncounterobserver", `floatupdowncounterobserver{A="B",C="D",R="V"} -7.7`))
|
||||
|
||||
@ -196,10 +211,8 @@ func TestPrometheusStatefulness(t *testing.T) {
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
counter := metric.Must(meter).NewInt64Counter(
|
||||
"a.counter",
|
||||
metric.WithDescription("Counts things"),
|
||||
)
|
||||
counter, err := meter.SyncInt64().Counter("a.counter", instrument.WithDescription("Counts things"))
|
||||
require.NoError(t, err)
|
||||
|
||||
counter.Add(ctx, 100, attribute.String("key", "value"))
|
||||
|
||||
|
@ -21,7 +21,7 @@ import (
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/exporters/stdout/stdoutmetric"
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
"go.opentelemetry.io/otel/metric/global"
|
||||
"go.opentelemetry.io/otel/metric/instrument/syncint64"
|
||||
controller "go.opentelemetry.io/otel/sdk/metric/controller/basic"
|
||||
processor "go.opentelemetry.io/otel/sdk/metric/processor/basic"
|
||||
"go.opentelemetry.io/otel/sdk/metric/selector/simple"
|
||||
@ -33,13 +33,15 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
meter = global.GetMeterProvider().Meter(
|
||||
instrumentationName,
|
||||
metric.WithInstrumentationVersion(instrumentationVersion),
|
||||
)
|
||||
// TODO Bring back Global package
|
||||
// meter = global.GetMeterProvider().Meter(
|
||||
// instrumentationName,
|
||||
// metric.WithInstrumentationVersion(instrumentationVersion),
|
||||
// )
|
||||
meter metric.Meter
|
||||
|
||||
loopCounter = metric.Must(meter).NewInt64Counter("function.loops")
|
||||
paramValue = metric.Must(meter).NewInt64Histogram("function.param")
|
||||
loopCounter syncint64.Counter
|
||||
paramValue syncint64.Histogram
|
||||
|
||||
nameKey = attribute.Key("function.name")
|
||||
)
|
||||
@ -80,7 +82,18 @@ func InstallExportPipeline(ctx context.Context) func() {
|
||||
if err = pusher.Start(ctx); err != nil {
|
||||
log.Fatalf("starting push controller: %v", err)
|
||||
}
|
||||
global.SetMeterProvider(pusher)
|
||||
// TODO Bring back Global package
|
||||
// global.SetMeterProvider(pusher)
|
||||
meter = pusher.Meter(instrumentationName, metric.WithInstrumentationVersion(instrumentationVersion))
|
||||
|
||||
loopCounter, err = meter.SyncInt64().Counter("function.loops")
|
||||
if err != nil {
|
||||
log.Fatalf("creating instrument: %v", err)
|
||||
}
|
||||
paramValue, err = meter.SyncInt64().Histogram("function.param")
|
||||
if err != nil {
|
||||
log.Fatalf("creating instrument: %v", err)
|
||||
}
|
||||
|
||||
return func() {
|
||||
if err := pusher.Stop(ctx); err != nil {
|
||||
@ -92,7 +105,7 @@ func InstallExportPipeline(ctx context.Context) func() {
|
||||
func Example() {
|
||||
ctx := context.Background()
|
||||
|
||||
// Registers a meter Provider globally.
|
||||
// TODO: Registers a meter Provider globally.
|
||||
cleanup := InstallExportPipeline(ctx)
|
||||
defer cleanup()
|
||||
|
||||
|
@ -22,10 +22,10 @@ import (
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/instrumentation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
)
|
||||
|
||||
|
@ -101,7 +101,8 @@ func TestStdoutTimestamp(t *testing.T) {
|
||||
|
||||
require.NoError(t, cont.Start(ctx))
|
||||
meter := cont.Meter("test")
|
||||
counter := metric.Must(meter).NewInt64Counter("name.lastvalue")
|
||||
counter, err := meter.SyncInt64().Counter("name.lastvalue")
|
||||
require.NoError(t, err)
|
||||
|
||||
before := time.Now()
|
||||
// Ensure the timestamp is after before.
|
||||
@ -137,7 +138,8 @@ func TestStdoutTimestamp(t *testing.T) {
|
||||
func TestStdoutCounterFormat(t *testing.T) {
|
||||
fix := newFixture(t)
|
||||
|
||||
counter := metric.Must(fix.meter).NewInt64Counter("name.sum")
|
||||
counter, err := fix.meter.SyncInt64().Counter("name.sum")
|
||||
require.NoError(t, err)
|
||||
counter.Add(fix.ctx, 123, attribute.String("A", "B"), attribute.String("C", "D"))
|
||||
|
||||
require.NoError(t, fix.cont.Stop(fix.ctx))
|
||||
@ -148,7 +150,8 @@ func TestStdoutCounterFormat(t *testing.T) {
|
||||
func TestStdoutLastValueFormat(t *testing.T) {
|
||||
fix := newFixture(t)
|
||||
|
||||
counter := metric.Must(fix.meter).NewFloat64Counter("name.lastvalue")
|
||||
counter, err := fix.meter.SyncFloat64().Counter("name.lastvalue")
|
||||
require.NoError(t, err)
|
||||
counter.Add(fix.ctx, 123.456, attribute.String("A", "B"), attribute.String("C", "D"))
|
||||
|
||||
require.NoError(t, fix.cont.Stop(fix.ctx))
|
||||
@ -159,7 +162,8 @@ func TestStdoutLastValueFormat(t *testing.T) {
|
||||
func TestStdoutHistogramFormat(t *testing.T) {
|
||||
fix := newFixture(t, stdoutmetric.WithPrettyPrint())
|
||||
|
||||
inst := metric.Must(fix.meter).NewFloat64Histogram("name.histogram")
|
||||
inst, err := fix.meter.SyncFloat64().Histogram("name.histogram")
|
||||
require.NoError(t, err)
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
inst.Record(fix.ctx, float64(i)+0.5, attribute.String("A", "B"), attribute.String("C", "D"))
|
||||
@ -181,7 +185,8 @@ func TestStdoutNoData(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fix := newFixture(t)
|
||||
_ = metric.Must(fix.meter).NewFloat64Counter(fmt.Sprint("name.", aggName))
|
||||
_, err := fix.meter.SyncFloat64().Counter(fmt.Sprint("name.", aggName))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, fix.cont.Stop(fix.ctx))
|
||||
|
||||
require.Equal(t, "", fix.Output())
|
||||
@ -243,7 +248,8 @@ func TestStdoutResource(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
fix := newFixtureWithResource(t, tc.res)
|
||||
|
||||
counter := metric.Must(fix.meter).NewFloat64Counter("name.lastvalue")
|
||||
counter, err := fix.meter.SyncFloat64().Counter("name.lastvalue")
|
||||
require.NoError(t, err)
|
||||
counter.Add(ctx, 123.456, tc.attrs...)
|
||||
|
||||
require.NoError(t, fix.cont.Stop(fix.ctx))
|
||||
|
@ -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))
|
||||
})
|
||||
}
|
||||
}
|
@ -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...)
|
||||
}
|
||||
}
|
@ -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())
|
||||
}
|
@ -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),
|
||||
}
|
||||
}
|
@ -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))
|
||||
}
|
@ -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{}
|
||||
}
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
module go.opentelemetry.io/otel/internal/metric
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/stretchr/testify v1.7.0
|
||||
go.opentelemetry.io/otel v1.4.1
|
||||
go.opentelemetry.io/otel/metric v0.27.0
|
||||
)
|
||||
|
||||
replace go.opentelemetry.io/otel => ../..
|
||||
|
||||
replace go.opentelemetry.io/otel/metric => ../../metric
|
||||
|
||||
replace go.opentelemetry.io/otel/internal/metric => ./
|
||||
|
||||
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/passthrough => ../../example/passthrough
|
||||
|
||||
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/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/jaeger => ../../exporters/jaeger
|
||||
|
||||
replace go.opentelemetry.io/otel/exporters/zipkin => ../../exporters/zipkin
|
||||
|
||||
replace go.opentelemetry.io/otel/internal/tools => ../tools
|
||||
|
||||
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/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
|
@ -1,18 +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/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=
|
@ -14,65 +14,6 @@
|
||||
|
||||
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) InstrumentConfig
|
||||
}
|
||||
|
||||
// NewInstrumentConfig creates a new InstrumentConfig
|
||||
// and applies all the given options.
|
||||
func NewInstrumentConfig(opts ...InstrumentOption) InstrumentConfig {
|
||||
var config InstrumentConfig
|
||||
for _, o := range opts {
|
||||
config = o.applyInstrument(config)
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
type instrumentOptionFunc func(InstrumentConfig) InstrumentConfig
|
||||
|
||||
func (fn instrumentOptionFunc) applyInstrument(cfg InstrumentConfig) InstrumentConfig {
|
||||
return fn(cfg)
|
||||
}
|
||||
|
||||
// WithDescription applies provided description.
|
||||
func WithDescription(desc string) InstrumentOption {
|
||||
return instrumentOptionFunc(func(cfg InstrumentConfig) InstrumentConfig {
|
||||
cfg.description = desc
|
||||
return cfg
|
||||
})
|
||||
}
|
||||
|
||||
// WithUnit applies provided unit.
|
||||
func WithUnit(unit unit.Unit) InstrumentOption {
|
||||
return instrumentOptionFunc(func(cfg InstrumentConfig) InstrumentConfig {
|
||||
cfg.unit = unit
|
||||
return cfg
|
||||
})
|
||||
}
|
||||
|
||||
// MeterConfig contains options for Meters.
|
||||
type MeterConfig struct {
|
||||
instrumentationVersion string
|
||||
@ -80,18 +21,18 @@ type MeterConfig struct {
|
||||
}
|
||||
|
||||
// InstrumentationVersion is the version of the library providing instrumentation.
|
||||
func (cfg *MeterConfig) InstrumentationVersion() string {
|
||||
func (cfg MeterConfig) InstrumentationVersion() string {
|
||||
return cfg.instrumentationVersion
|
||||
}
|
||||
|
||||
// SchemaURL is the schema_url of the library providing instrumentation.
|
||||
func (cfg *MeterConfig) SchemaURL() string {
|
||||
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 is used to set a MeterOption value of a MeterConfig.
|
||||
applyMeter(MeterConfig) MeterConfig
|
||||
}
|
||||
|
||||
|
@ -19,49 +19,5 @@ 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"
|
||||
|
116
metric/example_test.go
Normal file
116
metric/example_test.go
Normal file
@ -0,0 +1,116 @@
|
||||
// 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/instrument"
|
||||
"go.opentelemetry.io/otel/metric/instrument/syncfloat64"
|
||||
"go.opentelemetry.io/otel/metric/nonrecording"
|
||||
"go.opentelemetry.io/otel/metric/unit"
|
||||
)
|
||||
|
||||
//nolint:govet // Meter doesn't register for go vet
|
||||
func ExampleMeter_synchronous() {
|
||||
// In a library or program this would be provided by otel.GetMeterProvider().
|
||||
meterProvider := nonrecording.NewNoopMeterProvider()
|
||||
|
||||
workDuration, err := meterProvider.Meter("go.opentelemetry.io/otel/metric#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.Since(startTime).Milliseconds())
|
||||
|
||||
}
|
||||
|
||||
//nolint:govet // Meter doesn't register for go vet
|
||||
func ExampleMeter_asynchronous_single() {
|
||||
// In a library or program this would be provided by otel.GetMeterProvider().
|
||||
meterProvider := nonrecording.NewNoopMeterProvider()
|
||||
meter := meterProvider.Meter("go.opentelemetry.io/otel/metric#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)
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:govet // Meter doesn't register for go vet
|
||||
func ExampleMeter_asynchronous_multiple() {
|
||||
meterProvider := nonrecording.NewNoopMeterProvider()
|
||||
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")
|
||||
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) {
|
||||
|
||||
}
|
@ -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)
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -2,6 +2,8 @@ module go.opentelemetry.io/otel/metric
|
||||
|
||||
go 1.16
|
||||
|
||||
require go.opentelemetry.io/otel v1.4.1
|
||||
|
||||
replace go.opentelemetry.io/otel => ../
|
||||
|
||||
replace go.opentelemetry.io/otel/bridge/opencensus => ../bridge/opencensus
|
||||
@ -38,13 +40,6 @@ 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.4.1
|
||||
go.opentelemetry.io/otel/internal/metric v0.27.0
|
||||
)
|
||||
|
||||
replace go.opentelemetry.io/otel/example/passthrough => ../example/passthrough
|
||||
|
||||
replace go.opentelemetry.io/otel/exporters/otlp/otlptrace => ../exporters/otlp/otlptrace
|
||||
@ -53,8 +48,6 @@ replace go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc => ../ex
|
||||
|
||||
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
|
||||
|
@ -1,8 +1,6 @@
|
||||
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=
|
||||
@ -11,9 +9,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
||||
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=
|
||||
|
70
metric/instrument/asyncfloat64/asyncfloat64.go
Normal file
70
metric/instrument/asyncfloat64/asyncfloat64.go
Normal file
@ -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"
|
||||
)
|
||||
|
||||
// InstrumentProvider provides access to individual instruments.
|
||||
type InstrumentProvider 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 handler.
|
||||
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 handler.
|
||||
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 handler.
|
||||
Observe(ctx context.Context, x float64, attrs ...attribute.KeyValue)
|
||||
|
||||
instrument.Asynchronous
|
||||
}
|
70
metric/instrument/asyncint64/asyncint64.go
Normal file
70
metric/instrument/asyncint64/asyncint64.go
Normal file
@ -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"
|
||||
)
|
||||
|
||||
// InstrumentProvider provides access to individual instruments.
|
||||
type InstrumentProvider 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 handler.
|
||||
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 handler.
|
||||
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 handler.
|
||||
Observe(ctx context.Context, x int64, attrs ...attribute.KeyValue)
|
||||
|
||||
instrument.Asynchronous
|
||||
}
|
69
metric/instrument/config.go
Normal file
69
metric/instrument/config.go
Normal file
@ -0,0 +1,69 @@
|
||||
// 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 {
|
||||
applyInstrument(Config) Config
|
||||
}
|
||||
|
||||
// NewConfig creates a new Config and applies all the given options.
|
||||
func NewConfig(opts ...Option) Config {
|
||||
var config Config
|
||||
for _, o := range opts {
|
||||
config = o.applyInstrument(config)
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
type optionFunc func(Config) Config
|
||||
|
||||
func (fn optionFunc) applyInstrument(cfg Config) Config {
|
||||
return fn(cfg)
|
||||
}
|
||||
|
||||
// WithDescription applies provided description.
|
||||
func WithDescription(desc string) Option {
|
||||
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) Config {
|
||||
cfg.unit = unit
|
||||
return cfg
|
||||
})
|
||||
}
|
@ -12,23 +12,19 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package metric
|
||||
package instrument // import "go.opentelemetry.io/otel/metric/instrument"
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewNoopMeterProvider(t *testing.T) {
|
||||
got, want := NewNoopMeterProvider(), noopMeterProvider{}
|
||||
if got != want {
|
||||
t.Errorf("NewNoopMeterProvider() returned %#v, want %#v", got, want)
|
||||
}
|
||||
// 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()
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
// Synchronous instruments are updated in line with application code.
|
||||
//
|
||||
// This interface is used as a grouping mechanism.
|
||||
type Synchronous interface {
|
||||
synchronous()
|
||||
}
|
56
metric/instrument/syncfloat64/syncfloat64.go
Normal file
56
metric/instrument/syncfloat64/syncfloat64.go
Normal file
@ -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"
|
||||
)
|
||||
|
||||
// InstrumentProvider provides access to individual instruments.
|
||||
type InstrumentProvider 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
|
||||
}
|
56
metric/instrument/syncint64/syncint64.go
Normal file
56
metric/instrument/syncint64/syncint64.go
Normal file
@ -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"
|
||||
)
|
||||
|
||||
// InstrumentProvider provides access to individual instruments.
|
||||
type InstrumentProvider 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
|
||||
}
|
60
metric/meter.go
Normal file
60
metric/meter.go
Normal file
@ -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 Integer instruments.
|
||||
//
|
||||
// To Observe data with instruments it must be registered in a callback.
|
||||
AsyncInt64() asyncint64.InstrumentProvider
|
||||
|
||||
// AsyncFloat64 is the namespace for the Asynchronous Float instruments
|
||||
//
|
||||
// To Observe data with instruments it must be registered in a callback.
|
||||
AsyncFloat64() asyncfloat64.InstrumentProvider
|
||||
|
||||
// RegisterCallback captures the function that will be called during Collect.
|
||||
//
|
||||
// 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
|
||||
|
||||
// SyncInt64 is the namespace for the Synchronous Integer instruments
|
||||
SyncInt64() syncint64.InstrumentProvider
|
||||
// SyncFloat64 is the namespace for the Synchronous Float instruments
|
||||
SyncFloat64() syncfloat64.InstrumentProvider
|
||||
}
|
538
metric/metric.go
538
metric/metric.go
@ -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
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
@ -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())
|
||||
}
|
@ -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")
|
||||
}
|
138
metric/nonrecording/instruments.go
Normal file
138
metric/nonrecording/instruments.go
Normal file
@ -0,0 +1,138 @@
|
||||
// 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 nonrecording // import "go.opentelemetry.io/otel/metric/nonrecording"
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"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"
|
||||
)
|
||||
|
||||
type nonrecordingAsyncFloat64Instrument struct {
|
||||
instrument.Asynchronous
|
||||
}
|
||||
|
||||
var (
|
||||
_ asyncfloat64.InstrumentProvider = nonrecordingAsyncFloat64Instrument{}
|
||||
_ asyncfloat64.Counter = nonrecordingAsyncFloat64Instrument{}
|
||||
_ asyncfloat64.UpDownCounter = nonrecordingAsyncFloat64Instrument{}
|
||||
_ asyncfloat64.Gauge = nonrecordingAsyncFloat64Instrument{}
|
||||
)
|
||||
|
||||
func (n nonrecordingAsyncFloat64Instrument) Counter(name string, opts ...instrument.Option) (asyncfloat64.Counter, error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (n nonrecordingAsyncFloat64Instrument) UpDownCounter(name string, opts ...instrument.Option) (asyncfloat64.UpDownCounter, error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (n nonrecordingAsyncFloat64Instrument) Gauge(name string, opts ...instrument.Option) (asyncfloat64.Gauge, error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (nonrecordingAsyncFloat64Instrument) Observe(context.Context, float64, ...attribute.KeyValue) {
|
||||
|
||||
}
|
||||
|
||||
type nonrecordingAsyncInt64Instrument struct {
|
||||
instrument.Asynchronous
|
||||
}
|
||||
|
||||
var (
|
||||
_ asyncint64.InstrumentProvider = nonrecordingAsyncInt64Instrument{}
|
||||
_ asyncint64.Counter = nonrecordingAsyncInt64Instrument{}
|
||||
_ asyncint64.UpDownCounter = nonrecordingAsyncInt64Instrument{}
|
||||
_ asyncint64.Gauge = nonrecordingAsyncInt64Instrument{}
|
||||
)
|
||||
|
||||
func (n nonrecordingAsyncInt64Instrument) Counter(name string, opts ...instrument.Option) (asyncint64.Counter, error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (n nonrecordingAsyncInt64Instrument) UpDownCounter(name string, opts ...instrument.Option) (asyncint64.UpDownCounter, error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (n nonrecordingAsyncInt64Instrument) Gauge(name string, opts ...instrument.Option) (asyncint64.Gauge, error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (nonrecordingAsyncInt64Instrument) Observe(context.Context, int64, ...attribute.KeyValue) {
|
||||
}
|
||||
|
||||
type nonrecordingSyncFloat64Instrument struct {
|
||||
instrument.Synchronous
|
||||
}
|
||||
|
||||
var (
|
||||
_ syncfloat64.InstrumentProvider = nonrecordingSyncFloat64Instrument{}
|
||||
_ syncfloat64.Counter = nonrecordingSyncFloat64Instrument{}
|
||||
_ syncfloat64.UpDownCounter = nonrecordingSyncFloat64Instrument{}
|
||||
_ syncfloat64.Histogram = nonrecordingSyncFloat64Instrument{}
|
||||
)
|
||||
|
||||
func (n nonrecordingSyncFloat64Instrument) Counter(name string, opts ...instrument.Option) (syncfloat64.Counter, error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (n nonrecordingSyncFloat64Instrument) UpDownCounter(name string, opts ...instrument.Option) (syncfloat64.UpDownCounter, error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (n nonrecordingSyncFloat64Instrument) Histogram(name string, opts ...instrument.Option) (syncfloat64.Histogram, error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (nonrecordingSyncFloat64Instrument) Add(context.Context, float64, ...attribute.KeyValue) {
|
||||
|
||||
}
|
||||
|
||||
func (nonrecordingSyncFloat64Instrument) Record(context.Context, float64, ...attribute.KeyValue) {
|
||||
|
||||
}
|
||||
|
||||
type nonrecordingSyncInt64Instrument struct {
|
||||
instrument.Synchronous
|
||||
}
|
||||
|
||||
var (
|
||||
_ syncint64.InstrumentProvider = nonrecordingSyncInt64Instrument{}
|
||||
_ syncint64.Counter = nonrecordingSyncInt64Instrument{}
|
||||
_ syncint64.UpDownCounter = nonrecordingSyncInt64Instrument{}
|
||||
_ syncint64.Histogram = nonrecordingSyncInt64Instrument{}
|
||||
)
|
||||
|
||||
func (n nonrecordingSyncInt64Instrument) Counter(name string, opts ...instrument.Option) (syncint64.Counter, error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (n nonrecordingSyncInt64Instrument) UpDownCounter(name string, opts ...instrument.Option) (syncint64.UpDownCounter, error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (n nonrecordingSyncInt64Instrument) Histogram(name string, opts ...instrument.Option) (syncint64.Histogram, error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (nonrecordingSyncInt64Instrument) Add(context.Context, int64, ...attribute.KeyValue) {
|
||||
}
|
||||
func (nonrecordingSyncInt64Instrument) Record(context.Context, int64, ...attribute.KeyValue) {
|
||||
}
|
64
metric/nonrecording/meter.go
Normal file
64
metric/nonrecording/meter.go
Normal file
@ -0,0 +1,64 @@
|
||||
// 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 nonrecording // import "go.opentelemetry.io/otel/metric/nonrecording"
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
"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"
|
||||
)
|
||||
|
||||
// NewNoopMeterProvider creates a MeterProvider that does not record any metrics.
|
||||
func NewNoopMeterProvider() metric.MeterProvider {
|
||||
return noopMeterProvider{}
|
||||
}
|
||||
|
||||
type noopMeterProvider struct{}
|
||||
|
||||
var _ metric.MeterProvider = noopMeterProvider{}
|
||||
|
||||
func (noopMeterProvider) Meter(instrumentationName string, opts ...metric.MeterOption) metric.Meter {
|
||||
return noopMeter{}
|
||||
}
|
||||
|
||||
// NewNoopMeter creates a Meter that does not record any metrics.
|
||||
func NewNoopMeter() metric.Meter {
|
||||
return noopMeter{}
|
||||
}
|
||||
|
||||
type noopMeter struct{}
|
||||
|
||||
var _ metric.Meter = noopMeter{}
|
||||
|
||||
func (noopMeter) AsyncInt64() asyncint64.InstrumentProvider {
|
||||
return nonrecordingAsyncInt64Instrument{}
|
||||
}
|
||||
func (noopMeter) AsyncFloat64() asyncfloat64.InstrumentProvider {
|
||||
return nonrecordingAsyncFloat64Instrument{}
|
||||
}
|
||||
func (noopMeter) SyncInt64() syncint64.InstrumentProvider {
|
||||
return nonrecordingSyncInt64Instrument{}
|
||||
}
|
||||
func (noopMeter) SyncFloat64() syncfloat64.InstrumentProvider {
|
||||
return nonrecordingSyncFloat64Instrument{}
|
||||
}
|
||||
func (noopMeter) RegisterCallback([]instrument.Asynchronous, func(context.Context)) error {
|
||||
return nil
|
||||
}
|
@ -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{}
|
||||
}
|
@ -15,8 +15,8 @@
|
||||
package aggregation // import "go.opentelemetry.io/otel/sdk/export/metric/aggregation"
|
||||
|
||||
import (
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
)
|
||||
|
||||
// Deprecated: use module "go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
|
@ -41,7 +41,6 @@ replace go.opentelemetry.io/otel/trace => ../../../trace
|
||||
|
||||
require (
|
||||
go.opentelemetry.io/otel v1.4.1
|
||||
go.opentelemetry.io/otel/metric v0.27.0
|
||||
go.opentelemetry.io/otel/sdk/metric v0.27.0
|
||||
)
|
||||
|
||||
|
@ -18,10 +18,10 @@ import (
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
// Deprecated: use module "go.opentelemetry.io/otel/sdk/metric/export"
|
||||
|
@ -19,9 +19,9 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
// Aggregator implements a specific aggregation behavior, e.g., a
|
||||
|
@ -21,13 +21,13 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"go.opentelemetry.io/otel/metric/metrictest"
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator/lastvalue"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator/sum"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/metrictest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
func TestInconsistentAggregatorErr(t *testing.T) {
|
||||
|
@ -26,11 +26,11 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
ottest "go.opentelemetry.io/otel/internal/internaltest"
|
||||
"go.opentelemetry.io/otel/metric/metrictest"
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/metrictest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
const Magnitude = 1000
|
||||
|
@ -19,10 +19,10 @@ import (
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator/aggregatortest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator/histogram"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
const inputRange = 1e6
|
||||
|
@ -19,10 +19,10 @@ import (
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
// Note: This code uses a Mutex to govern access to the exclusive
|
||||
|
@ -23,11 +23,11 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator/aggregatortest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator/histogram"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
const count = 100
|
||||
|
@ -20,10 +20,10 @@ import (
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
type (
|
||||
|
@ -25,11 +25,11 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
ottest "go.opentelemetry.io/otel/internal/internaltest"
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator/aggregatortest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
const count = 100
|
||||
|
@ -17,10 +17,10 @@ package sum // import "go.opentelemetry.io/otel/sdk/metric/aggregator/sum"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
// Aggregator aggregates counter events.
|
||||
|
@ -22,10 +22,10 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
ottest "go.opentelemetry.io/otel/internal/internaltest"
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator/aggregatortest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
const count = 100
|
||||
|
@ -22,11 +22,13 @@ import (
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
"go.opentelemetry.io/otel/metric/global"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/metric/instrument"
|
||||
"go.opentelemetry.io/otel/metric/instrument/syncfloat64"
|
||||
"go.opentelemetry.io/otel/metric/instrument/syncint64"
|
||||
sdk "go.opentelemetry.io/otel/sdk/metric"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export"
|
||||
"go.opentelemetry.io/otel/sdk/metric/processor/processortest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
type benchFixture struct {
|
||||
@ -44,7 +46,7 @@ func newFixture(b *testing.B) *benchFixture {
|
||||
}
|
||||
|
||||
bf.accumulator = sdk.NewAccumulator(bf)
|
||||
bf.meter = metric.WrapMeterImpl(bf.accumulator)
|
||||
bf.meter = sdkapi.WrapMeterImpl(bf.accumulator)
|
||||
return bf
|
||||
}
|
||||
|
||||
@ -56,8 +58,33 @@ func (f *benchFixture) Meter(_ string, _ ...metric.MeterOption) metric.Meter {
|
||||
return f.meter
|
||||
}
|
||||
|
||||
func (f *benchFixture) meterMust() metric.MeterMust {
|
||||
return metric.Must(f.meter)
|
||||
func (f *benchFixture) iCounter(name string) syncint64.Counter {
|
||||
ctr, err := f.meter.SyncInt64().Counter(name)
|
||||
if err != nil {
|
||||
f.B.Error(err)
|
||||
}
|
||||
return ctr
|
||||
}
|
||||
func (f *benchFixture) fCounter(name string) syncfloat64.Counter {
|
||||
ctr, err := f.meter.SyncFloat64().Counter(name)
|
||||
if err != nil {
|
||||
f.B.Error(err)
|
||||
}
|
||||
return ctr
|
||||
}
|
||||
func (f *benchFixture) iHistogram(name string) syncint64.Histogram {
|
||||
ctr, err := f.meter.SyncInt64().Histogram(name)
|
||||
if err != nil {
|
||||
f.B.Error(err)
|
||||
}
|
||||
return ctr
|
||||
}
|
||||
func (f *benchFixture) fHistogram(name string) syncfloat64.Histogram {
|
||||
ctr, err := f.meter.SyncFloat64().Histogram(name)
|
||||
if err != nil {
|
||||
f.B.Error(err)
|
||||
}
|
||||
return ctr
|
||||
}
|
||||
|
||||
func makeLabels(n int) []attribute.KeyValue {
|
||||
@ -81,7 +108,7 @@ func benchmarkLabels(b *testing.B, n int) {
|
||||
ctx := context.Background()
|
||||
fix := newFixture(b)
|
||||
labs := makeLabels(n)
|
||||
cnt := fix.meterMust().NewInt64Counter("int64.sum")
|
||||
cnt := fix.iCounter("int64.sum")
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
@ -154,31 +181,33 @@ func BenchmarkIterator_16(b *testing.B) {
|
||||
|
||||
// Counters
|
||||
|
||||
func BenchmarkGlobalInt64CounterAddWithSDK(b *testing.B) {
|
||||
// Compare with BenchmarkInt64CounterAdd() to see overhead of global
|
||||
// package. This is in the SDK to avoid the API from depending on the
|
||||
// SDK.
|
||||
ctx := context.Background()
|
||||
fix := newFixture(b)
|
||||
// TODO readd global
|
||||
|
||||
sdk := global.Meter("test")
|
||||
global.SetMeterProvider(fix)
|
||||
// func BenchmarkGlobalInt64CounterAddWithSDK(b *testing.B) {
|
||||
// // Compare with BenchmarkInt64CounterAdd() to see overhead of global
|
||||
// // package. This is in the SDK to avoid the API from depending on the
|
||||
// // SDK.
|
||||
// ctx := context.Background()
|
||||
// fix := newFixture(b)
|
||||
|
||||
labs := []attribute.KeyValue{attribute.String("A", "B")}
|
||||
cnt := Must(sdk).NewInt64Counter("int64.sum")
|
||||
// sdk := global.Meter("test")
|
||||
// global.SetMeterProvider(fix)
|
||||
|
||||
b.ResetTimer()
|
||||
// labs := []attribute.KeyValue{attribute.String("A", "B")}
|
||||
// cnt := Must(sdk).NewInt64Counter("int64.sum")
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
cnt.Add(ctx, 1, labs...)
|
||||
}
|
||||
}
|
||||
// b.ResetTimer()
|
||||
|
||||
// for i := 0; i < b.N; i++ {
|
||||
// cnt.Add(ctx, 1, labs...)
|
||||
// }
|
||||
// }
|
||||
|
||||
func BenchmarkInt64CounterAdd(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
fix := newFixture(b)
|
||||
labs := makeLabels(1)
|
||||
cnt := fix.meterMust().NewInt64Counter("int64.sum")
|
||||
cnt := fix.iCounter("int64.sum")
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
@ -191,7 +220,7 @@ func BenchmarkFloat64CounterAdd(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
fix := newFixture(b)
|
||||
labs := makeLabels(1)
|
||||
cnt := fix.meterMust().NewFloat64Counter("float64.sum")
|
||||
cnt := fix.fCounter("float64.sum")
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
@ -206,7 +235,7 @@ func BenchmarkInt64LastValueAdd(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
fix := newFixture(b)
|
||||
labs := makeLabels(1)
|
||||
mea := fix.meterMust().NewInt64Histogram("int64.lastvalue")
|
||||
mea := fix.iHistogram("int64.lastvalue")
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
@ -219,7 +248,7 @@ func BenchmarkFloat64LastValueAdd(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
fix := newFixture(b)
|
||||
labs := makeLabels(1)
|
||||
mea := fix.meterMust().NewFloat64Histogram("float64.lastvalue")
|
||||
mea := fix.fHistogram("float64.lastvalue")
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
@ -234,7 +263,7 @@ func BenchmarkInt64HistogramAdd(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
fix := newFixture(b)
|
||||
labs := makeLabels(1)
|
||||
mea := fix.meterMust().NewInt64Histogram("int64.histogram")
|
||||
mea := fix.iHistogram("int64.histogram")
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
@ -247,7 +276,7 @@ func BenchmarkFloat64HistogramAdd(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
fix := newFixture(b)
|
||||
labs := makeLabels(1)
|
||||
mea := fix.meterMust().NewFloat64Histogram("float64.histogram")
|
||||
mea := fix.fHistogram("float64.histogram")
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
@ -264,12 +293,12 @@ func BenchmarkObserverRegistration(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
names = append(names, fmt.Sprintf("test.%d.lastvalue", i))
|
||||
}
|
||||
cb := func(_ context.Context, result metric.Int64ObserverResult) {}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
fix.meterMust().NewInt64GaugeObserver(names[i], cb)
|
||||
ctr, _ := fix.meter.AsyncInt64().Counter(names[i])
|
||||
_ = fix.meter.RegisterCallback([]instrument.Asynchronous{ctr}, func(context.Context) {})
|
||||
}
|
||||
}
|
||||
|
||||
@ -277,11 +306,16 @@ func BenchmarkGaugeObserverObservationInt64(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
fix := newFixture(b)
|
||||
labs := makeLabels(1)
|
||||
_ = fix.meterMust().NewInt64GaugeObserver("test.lastvalue", func(_ context.Context, result metric.Int64ObserverResult) {
|
||||
ctr, _ := fix.meter.AsyncInt64().Counter("test.lastvalue")
|
||||
err := fix.meter.RegisterCallback([]instrument.Asynchronous{ctr}, func(ctx context.Context) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
result.Observe((int64)(i), labs...)
|
||||
ctr.Observe(ctx, (int64)(i), labs...)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
b.Errorf("could not register callback: %v", err)
|
||||
b.FailNow()
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
@ -292,11 +326,16 @@ func BenchmarkGaugeObserverObservationFloat64(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
fix := newFixture(b)
|
||||
labs := makeLabels(1)
|
||||
_ = fix.meterMust().NewFloat64GaugeObserver("test.lastvalue", func(_ context.Context, result metric.Float64ObserverResult) {
|
||||
ctr, _ := fix.meter.AsyncFloat64().Counter("test.lastvalue")
|
||||
err := fix.meter.RegisterCallback([]instrument.Asynchronous{ctr}, func(ctx context.Context) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
result.Observe((float64)(i), labs...)
|
||||
ctr.Observe(ctx, (float64)(i), labs...)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
b.Errorf("could not register callback: %v", err)
|
||||
b.FailNow()
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
@ -310,17 +349,18 @@ func benchmarkBatchRecord8Labels(b *testing.B, numInst int) {
|
||||
ctx := context.Background()
|
||||
fix := newFixture(b)
|
||||
labs := makeLabels(numLabels)
|
||||
var meas []sdkapi.Measurement
|
||||
var meas []syncint64.Counter
|
||||
|
||||
for i := 0; i < numInst; i++ {
|
||||
inst := fix.meterMust().NewInt64Counter(fmt.Sprintf("int64.%d.sum", i))
|
||||
meas = append(meas, inst.Measurement(1))
|
||||
meas = append(meas, fix.iCounter(fmt.Sprintf("int64.%d.sum", i)))
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
fix.accumulator.RecordBatch(ctx, labs, meas...)
|
||||
for _, ctr := range meas {
|
||||
ctr.Add(ctx, 1, labs...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -346,7 +386,7 @@ func BenchmarkRepeatedDirectCalls(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
fix := newFixture(b)
|
||||
|
||||
c := fix.meterMust().NewInt64Counter("int64.sum")
|
||||
c := fix.iCounter("int64.sum")
|
||||
k := attribute.String("bench", "true")
|
||||
|
||||
b.ResetTimer()
|
||||
|
@ -21,12 +21,13 @@ import (
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/internal/metric/registry"
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
"go.opentelemetry.io/otel/sdk/instrumentation"
|
||||
sdk "go.opentelemetry.io/otel/sdk/metric"
|
||||
controllerTime "go.opentelemetry.io/otel/sdk/metric/controller/time"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export"
|
||||
"go.opentelemetry.io/otel/sdk/metric/registry"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
)
|
||||
|
||||
@ -99,7 +100,7 @@ func (c *Controller) Meter(instrumentationName string, opts ...metric.MeterOptio
|
||||
library: library,
|
||||
}))
|
||||
}
|
||||
return metric.WrapMeterImpl(m.(*registry.UniqueInstrumentMeterImpl))
|
||||
return sdkapi.WrapMeterImpl(m.(*registry.UniqueInstrumentMeterImpl))
|
||||
}
|
||||
|
||||
type accumulatorCheckpointer struct {
|
||||
@ -108,6 +109,8 @@ type accumulatorCheckpointer struct {
|
||||
library instrumentation.Library
|
||||
}
|
||||
|
||||
var _ sdkapi.MeterImpl = &accumulatorCheckpointer{}
|
||||
|
||||
// New constructs a Controller using the provided checkpointer factory
|
||||
// and options (including optional exporter) to configure a metric
|
||||
// export pipeline.
|
||||
|
@ -25,8 +25,7 @@ import (
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
ottest "go.opentelemetry.io/otel/internal/internaltest"
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/metric/instrument"
|
||||
"go.opentelemetry.io/otel/sdk/instrumentation"
|
||||
controller "go.opentelemetry.io/otel/sdk/metric/controller/basic"
|
||||
"go.opentelemetry.io/otel/sdk/metric/controller/controllertest"
|
||||
@ -34,6 +33,7 @@ import (
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
processor "go.opentelemetry.io/otel/sdk/metric/processor/basic"
|
||||
"go.opentelemetry.io/otel/sdk/metric/processor/processortest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
)
|
||||
|
||||
@ -127,7 +127,7 @@ func TestControllerUsesResource(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
require.NoError(t, cont.Start(ctx))
|
||||
|
||||
ctr := metric.Must(cont.Meter("named")).NewFloat64Counter("calls.sum")
|
||||
ctr, _ := cont.Meter("named").SyncFloat64().Counter("calls.sum")
|
||||
ctr.Add(context.Background(), 1.)
|
||||
|
||||
// Collect once
|
||||
@ -152,16 +152,19 @@ func TestStartNoExporter(t *testing.T) {
|
||||
)
|
||||
mock := controllertest.NewMockClock()
|
||||
cont.SetClock(mock)
|
||||
meter := cont.Meter("go.opentelemetry.io/otel/sdk/metric/controller/basic_test#StartNoExporter")
|
||||
|
||||
calls := int64(0)
|
||||
|
||||
_ = metric.Must(cont.Meter("named")).NewInt64CounterObserver("calls.lastvalue",
|
||||
func(ctx context.Context, result metric.Int64ObserverResult) {
|
||||
counterObserver, err := meter.AsyncInt64().Counter("calls.lastvalue")
|
||||
require.NoError(t, err)
|
||||
|
||||
err = meter.RegisterCallback([]instrument.Asynchronous{counterObserver}, func(ctx context.Context) {
|
||||
calls++
|
||||
checkTestContext(t, ctx)
|
||||
result.Observe(calls, attribute.String("A", "B"))
|
||||
},
|
||||
)
|
||||
counterObserver.Observe(ctx, calls, attribute.String("A", "B"))
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Collect() has not been called. The controller is unstarted.
|
||||
expect := map[string]float64{}
|
||||
@ -220,18 +223,22 @@ func TestObserverCanceled(t *testing.T) {
|
||||
controller.WithCollectTimeout(time.Millisecond),
|
||||
controller.WithResource(resource.Empty()),
|
||||
)
|
||||
meter := cont.Meter("go.opentelemetry.io/otel/sdk/metric/controller/basic_test#ObserverCanceled")
|
||||
|
||||
calls := int64(0)
|
||||
|
||||
_ = metric.Must(cont.Meter("named")).NewInt64CounterObserver("done.lastvalue",
|
||||
func(ctx context.Context, result metric.Int64ObserverResult) {
|
||||
counterObserver, err := meter.AsyncInt64().Counter("done.lastvalue")
|
||||
require.NoError(t, err)
|
||||
|
||||
err = meter.RegisterCallback([]instrument.Asynchronous{counterObserver}, func(ctx context.Context) {
|
||||
<-ctx.Done()
|
||||
calls++
|
||||
result.Observe(calls)
|
||||
},
|
||||
)
|
||||
counterObserver.Observe(ctx, calls)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// This relies on the context timing out
|
||||
err := cont.Collect(context.Background())
|
||||
err = cont.Collect(context.Background())
|
||||
require.Error(t, err)
|
||||
require.True(t, errors.Is(err, context.DeadlineExceeded))
|
||||
|
||||
@ -251,14 +258,18 @@ func TestObserverContext(t *testing.T) {
|
||||
controller.WithCollectTimeout(0),
|
||||
controller.WithResource(resource.Empty()),
|
||||
)
|
||||
meter := cont.Meter("go.opentelemetry.io/otel/sdk/metric/controller/basic_test#ObserverContext")
|
||||
|
||||
_ = metric.Must(cont.Meter("named")).NewInt64CounterObserver("done.lastvalue",
|
||||
func(ctx context.Context, result metric.Int64ObserverResult) {
|
||||
counterObserver, err := meter.AsyncInt64().Counter("done.lastvalue")
|
||||
require.NoError(t, err)
|
||||
|
||||
err = meter.RegisterCallback([]instrument.Asynchronous{counterObserver}, func(ctx context.Context) {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
checkTestContext(t, ctx)
|
||||
result.Observe(1)
|
||||
},
|
||||
)
|
||||
counterObserver.Observe(ctx, 1)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := testContext()
|
||||
|
||||
require.NoError(t, cont.Collect(ctx))
|
||||
@ -314,14 +325,17 @@ func TestExportTimeout(t *testing.T) {
|
||||
)
|
||||
mock := controllertest.NewMockClock()
|
||||
cont.SetClock(mock)
|
||||
meter := cont.Meter("go.opentelemetry.io/otel/sdk/metric/controller/basic_test#ExportTimeout")
|
||||
|
||||
calls := int64(0)
|
||||
_ = metric.Must(cont.Meter("named")).NewInt64CounterObserver("one.lastvalue",
|
||||
func(ctx context.Context, result metric.Int64ObserverResult) {
|
||||
counterObserver, err := meter.AsyncInt64().Counter("one.lastvalue")
|
||||
require.NoError(t, err)
|
||||
|
||||
err = meter.RegisterCallback([]instrument.Asynchronous{counterObserver}, func(ctx context.Context) {
|
||||
calls++
|
||||
result.Observe(calls)
|
||||
},
|
||||
)
|
||||
counterObserver.Observe(ctx, calls)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, cont.Start(context.Background()))
|
||||
|
||||
@ -332,7 +346,7 @@ func TestExportTimeout(t *testing.T) {
|
||||
// Collect after 1s, timeout
|
||||
mock.Add(time.Second)
|
||||
|
||||
err := testHandler.Flush()
|
||||
err = testHandler.Flush()
|
||||
require.Error(t, err)
|
||||
require.True(t, errors.Is(err, context.DeadlineExceeded))
|
||||
|
||||
@ -369,13 +383,17 @@ func TestCollectAfterStopThenStartAgain(t *testing.T) {
|
||||
mock := controllertest.NewMockClock()
|
||||
cont.SetClock(mock)
|
||||
|
||||
meter := cont.Meter("go.opentelemetry.io/otel/sdk/metric/controller/basic_test#CollectAfterStopThenStartAgain")
|
||||
|
||||
calls := 0
|
||||
_ = metric.Must(cont.Meter("named")).NewInt64CounterObserver("one.lastvalue",
|
||||
func(ctx context.Context, result metric.Int64ObserverResult) {
|
||||
counterObserver, err := meter.AsyncInt64().Counter("one.lastvalue")
|
||||
require.NoError(t, err)
|
||||
|
||||
err = meter.RegisterCallback([]instrument.Asynchronous{counterObserver}, func(ctx context.Context) {
|
||||
calls++
|
||||
result.Observe(int64(calls))
|
||||
},
|
||||
)
|
||||
counterObserver.Observe(ctx, int64(calls))
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// No collections happen (because mock clock does not advance):
|
||||
require.NoError(t, cont.Start(context.Background()))
|
||||
@ -403,7 +421,7 @@ func TestCollectAfterStopThenStartAgain(t *testing.T) {
|
||||
// explicit collection should still fail.
|
||||
require.NoError(t, cont.Start(context.Background()))
|
||||
require.True(t, cont.IsRunning())
|
||||
err := cont.Collect(context.Background())
|
||||
err = cont.Collect(context.Background())
|
||||
require.Error(t, err)
|
||||
require.Equal(t, controller.ErrControllerStarted, err)
|
||||
|
||||
@ -452,10 +470,10 @@ func TestRegistryFunction(t *testing.T) {
|
||||
require.NotNil(t, m1)
|
||||
require.Equal(t, m1, m2)
|
||||
|
||||
c1, err := m1.NewInt64Counter("counter.sum")
|
||||
c1, err := m1.SyncInt64().Counter("counter.sum")
|
||||
require.NoError(t, err)
|
||||
|
||||
c2, err := m1.NewInt64Counter("counter.sum")
|
||||
c2, err := m1.SyncInt64().Counter("counter.sum")
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, c1, c2)
|
||||
|
@ -23,7 +23,6 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
controller "go.opentelemetry.io/otel/sdk/metric/controller/basic"
|
||||
"go.opentelemetry.io/otel/sdk/metric/controller/controllertest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
@ -45,7 +44,8 @@ func TestPullNoCollect(t *testing.T) {
|
||||
|
||||
ctx := context.Background()
|
||||
meter := puller.Meter("nocache")
|
||||
counter := metric.Must(meter).NewInt64Counter("counter.sum")
|
||||
counter, err := meter.SyncInt64().Counter("counter.sum")
|
||||
require.NoError(t, err)
|
||||
|
||||
counter.Add(ctx, 10, attribute.String("A", "B"))
|
||||
|
||||
@ -83,7 +83,8 @@ func TestPullWithCollect(t *testing.T) {
|
||||
|
||||
ctx := context.Background()
|
||||
meter := puller.Meter("nocache")
|
||||
counter := metric.Must(meter).NewInt64Counter("counter.sum")
|
||||
counter, err := meter.SyncInt64().Counter("counter.sum")
|
||||
require.NoError(t, err)
|
||||
|
||||
counter.Add(ctx, 10, attribute.String("A", "B"))
|
||||
|
||||
|
@ -27,7 +27,6 @@ import (
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
controller "go.opentelemetry.io/otel/sdk/metric/controller/basic"
|
||||
"go.opentelemetry.io/otel/sdk/metric/controller/controllertest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export"
|
||||
@ -117,7 +116,8 @@ func TestPushTicker(t *testing.T) {
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
counter := metric.Must(meter).NewInt64Counter("counter.sum")
|
||||
counter, err := meter.SyncInt64().Counter("counter.sum")
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, p.Start(ctx))
|
||||
|
||||
@ -197,8 +197,10 @@ func TestPushExportError(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
meter := p.Meter("name")
|
||||
counter1 := metric.Must(meter).NewInt64Counter("counter1.sum")
|
||||
counter2 := metric.Must(meter).NewInt64Counter("counter2.sum")
|
||||
counter1, err := meter.SyncInt64().Counter("counter1.sum")
|
||||
require.NoError(t, err)
|
||||
counter2, err := meter.SyncInt64().Counter("counter2.sum")
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, p.Start(ctx))
|
||||
runtime.Gosched()
|
||||
|
@ -26,16 +26,17 @@ import (
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/metric/instrument"
|
||||
"go.opentelemetry.io/otel/metric/instrument/asyncint64"
|
||||
"go.opentelemetry.io/otel/metric/nonrecording"
|
||||
metricsdk "go.opentelemetry.io/otel/sdk/metric"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/processor/processortest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
var Must = metric.Must
|
||||
|
||||
type handler struct {
|
||||
sync.Mutex
|
||||
err error
|
||||
@ -88,7 +89,7 @@ func newSDK(t *testing.T) (metric.Meter, *metricsdk.Accumulator, *testSelector,
|
||||
accum := metricsdk.NewAccumulator(
|
||||
processor,
|
||||
)
|
||||
meter := metric.WrapMeterImpl(accum)
|
||||
meter := sdkapi.WrapMeterImpl(accum)
|
||||
return meter, accum, testSelector, processor
|
||||
}
|
||||
|
||||
@ -96,7 +97,8 @@ func TestInputRangeCounter(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
meter, sdk, _, processor := newSDK(t)
|
||||
|
||||
counter := Must(meter).NewInt64Counter("name.sum")
|
||||
counter, err := meter.SyncInt64().Counter("name.sum")
|
||||
require.NoError(t, err)
|
||||
|
||||
counter.Add(ctx, -1)
|
||||
require.Equal(t, aggregation.ErrNegativeInput, testHandler.Flush())
|
||||
@ -118,7 +120,8 @@ func TestInputRangeUpDownCounter(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
meter, sdk, _, processor := newSDK(t)
|
||||
|
||||
counter := Must(meter).NewInt64UpDownCounter("name.sum")
|
||||
counter, err := meter.SyncInt64().UpDownCounter("name.sum")
|
||||
require.NoError(t, err)
|
||||
|
||||
counter.Add(ctx, -1)
|
||||
counter.Add(ctx, -1)
|
||||
@ -137,7 +140,8 @@ func TestInputRangeHistogram(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
meter, sdk, _, processor := newSDK(t)
|
||||
|
||||
histogram := Must(meter).NewFloat64Histogram("name.histogram")
|
||||
histogram, err := meter.SyncFloat64().Histogram("name.histogram")
|
||||
require.NoError(t, err)
|
||||
|
||||
histogram.Record(ctx, math.NaN())
|
||||
require.Equal(t, aggregation.ErrNaNInput, testHandler.Flush())
|
||||
@ -162,7 +166,8 @@ func TestDisabledInstrument(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
meter, sdk, _, processor := newSDK(t)
|
||||
|
||||
histogram := Must(meter).NewFloat64Histogram("name.disabled")
|
||||
histogram, err := meter.SyncFloat64().Histogram("name.disabled")
|
||||
require.NoError(t, err)
|
||||
|
||||
histogram.Record(ctx, -1)
|
||||
checkpointed := sdk.Collect(ctx)
|
||||
@ -175,7 +180,8 @@ func TestRecordNaN(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
meter, _, _, _ := newSDK(t)
|
||||
|
||||
c := Must(meter).NewFloat64Counter("name.sum")
|
||||
c, err := meter.SyncFloat64().Counter("name.sum")
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Nil(t, testHandler.Flush())
|
||||
c.Add(ctx, math.NaN())
|
||||
@ -186,7 +192,8 @@ func TestSDKLabelsDeduplication(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
meter, sdk, _, processor := newSDK(t)
|
||||
|
||||
counter := Must(meter).NewInt64Counter("name.sum")
|
||||
counter, err := meter.SyncInt64().Counter("name.sum")
|
||||
require.NoError(t, err)
|
||||
|
||||
const (
|
||||
maxKeys = 21
|
||||
@ -277,48 +284,86 @@ func TestObserverCollection(t *testing.T) {
|
||||
meter, sdk, _, processor := newSDK(t)
|
||||
mult := 1
|
||||
|
||||
_ = Must(meter).NewFloat64GaugeObserver("float.gauge.lastvalue", func(_ context.Context, result metric.Float64ObserverResult) {
|
||||
result.Observe(float64(mult), attribute.String("A", "B"))
|
||||
gaugeF, err := meter.AsyncFloat64().Gauge("float.gauge.lastvalue")
|
||||
require.NoError(t, err)
|
||||
err = meter.RegisterCallback([]instrument.Asynchronous{
|
||||
gaugeF,
|
||||
}, func(ctx context.Context) {
|
||||
gaugeF.Observe(ctx, float64(mult), attribute.String("A", "B"))
|
||||
// last value wins
|
||||
result.Observe(float64(-mult), attribute.String("A", "B"))
|
||||
result.Observe(float64(-mult), attribute.String("C", "D"))
|
||||
})
|
||||
_ = Must(meter).NewInt64GaugeObserver("int.gauge.lastvalue", func(_ context.Context, result metric.Int64ObserverResult) {
|
||||
result.Observe(int64(-mult), attribute.String("A", "B"))
|
||||
result.Observe(int64(mult))
|
||||
// last value wins
|
||||
result.Observe(int64(mult), attribute.String("A", "B"))
|
||||
result.Observe(int64(mult))
|
||||
gaugeF.Observe(ctx, float64(-mult), attribute.String("A", "B"))
|
||||
gaugeF.Observe(ctx, float64(-mult), attribute.String("C", "D"))
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_ = Must(meter).NewFloat64CounterObserver("float.counterobserver.sum", func(_ context.Context, result metric.Float64ObserverResult) {
|
||||
result.Observe(float64(mult), attribute.String("A", "B"))
|
||||
result.Observe(float64(2*mult), attribute.String("A", "B"))
|
||||
result.Observe(float64(mult), attribute.String("C", "D"))
|
||||
})
|
||||
_ = Must(meter).NewInt64CounterObserver("int.counterobserver.sum", func(_ context.Context, result metric.Int64ObserverResult) {
|
||||
result.Observe(int64(2*mult), attribute.String("A", "B"))
|
||||
result.Observe(int64(mult))
|
||||
gaugeI, err := meter.AsyncInt64().Gauge("int.gauge.lastvalue")
|
||||
require.NoError(t, err)
|
||||
err = meter.RegisterCallback([]instrument.Asynchronous{
|
||||
gaugeI,
|
||||
}, func(ctx context.Context) {
|
||||
gaugeI.Observe(ctx, int64(-mult), attribute.String("A", "B"))
|
||||
gaugeI.Observe(ctx, int64(mult))
|
||||
// last value wins
|
||||
result.Observe(int64(mult), attribute.String("A", "B"))
|
||||
result.Observe(int64(mult))
|
||||
gaugeI.Observe(ctx, int64(mult), attribute.String("A", "B"))
|
||||
gaugeI.Observe(ctx, int64(mult))
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_ = Must(meter).NewFloat64UpDownCounterObserver("float.updowncounterobserver.sum", func(_ context.Context, result metric.Float64ObserverResult) {
|
||||
result.Observe(float64(mult), attribute.String("A", "B"))
|
||||
result.Observe(float64(-2*mult), attribute.String("A", "B"))
|
||||
result.Observe(float64(mult), attribute.String("C", "D"))
|
||||
counterF, err := meter.AsyncFloat64().Counter("float.counterobserver.sum")
|
||||
require.NoError(t, err)
|
||||
err = meter.RegisterCallback([]instrument.Asynchronous{
|
||||
counterF,
|
||||
}, func(ctx context.Context) {
|
||||
counterF.Observe(ctx, float64(mult), attribute.String("A", "B"))
|
||||
counterF.Observe(ctx, float64(2*mult), attribute.String("A", "B"))
|
||||
counterF.Observe(ctx, float64(mult), attribute.String("C", "D"))
|
||||
})
|
||||
_ = Must(meter).NewInt64UpDownCounterObserver("int.updowncounterobserver.sum", func(_ context.Context, result metric.Int64ObserverResult) {
|
||||
result.Observe(int64(2*mult), attribute.String("A", "B"))
|
||||
result.Observe(int64(mult))
|
||||
require.NoError(t, err)
|
||||
|
||||
counterI, err := meter.AsyncInt64().Counter("int.counterobserver.sum")
|
||||
require.NoError(t, err)
|
||||
err = meter.RegisterCallback([]instrument.Asynchronous{
|
||||
counterI,
|
||||
}, func(ctx context.Context) {
|
||||
counterI.Observe(ctx, int64(2*mult), attribute.String("A", "B"))
|
||||
counterI.Observe(ctx, int64(mult))
|
||||
// last value wins
|
||||
result.Observe(int64(mult), attribute.String("A", "B"))
|
||||
result.Observe(int64(-mult))
|
||||
counterI.Observe(ctx, int64(mult), attribute.String("A", "B"))
|
||||
counterI.Observe(ctx, int64(mult))
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_ = Must(meter).NewInt64GaugeObserver("empty.gauge.sum", func(_ context.Context, result metric.Int64ObserverResult) {
|
||||
updowncounterF, err := meter.AsyncFloat64().UpDownCounter("float.updowncounterobserver.sum")
|
||||
require.NoError(t, err)
|
||||
err = meter.RegisterCallback([]instrument.Asynchronous{
|
||||
updowncounterF,
|
||||
}, func(ctx context.Context) {
|
||||
updowncounterF.Observe(ctx, float64(mult), attribute.String("A", "B"))
|
||||
updowncounterF.Observe(ctx, float64(-2*mult), attribute.String("A", "B"))
|
||||
updowncounterF.Observe(ctx, float64(mult), attribute.String("C", "D"))
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
updowncounterI, err := meter.AsyncInt64().UpDownCounter("int.updowncounterobserver.sum")
|
||||
require.NoError(t, err)
|
||||
err = meter.RegisterCallback([]instrument.Asynchronous{
|
||||
updowncounterI,
|
||||
}, func(ctx context.Context) {
|
||||
updowncounterI.Observe(ctx, int64(2*mult), attribute.String("A", "B"))
|
||||
updowncounterI.Observe(ctx, int64(mult))
|
||||
// last value wins
|
||||
updowncounterI.Observe(ctx, int64(mult), attribute.String("A", "B"))
|
||||
updowncounterI.Observe(ctx, int64(-mult))
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
unused, err := meter.AsyncInt64().Gauge("empty.gauge.sum")
|
||||
require.NoError(t, err)
|
||||
err = meter.RegisterCallback([]instrument.Asynchronous{
|
||||
unused,
|
||||
}, func(ctx context.Context) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
for mult = 0; mult < 3; mult++ {
|
||||
processor.Reset()
|
||||
@ -333,15 +378,15 @@ func TestObserverCollection(t *testing.T) {
|
||||
"int.gauge.lastvalue//": mult,
|
||||
"int.gauge.lastvalue/A=B/": mult,
|
||||
|
||||
"float.counterobserver.sum/A=B/": 2 * mult,
|
||||
"float.counterobserver.sum/A=B/": 3 * mult,
|
||||
"float.counterobserver.sum/C=D/": mult,
|
||||
"int.counterobserver.sum//": mult,
|
||||
"int.counterobserver.sum/A=B/": mult,
|
||||
"int.counterobserver.sum//": 2 * mult,
|
||||
"int.counterobserver.sum/A=B/": 3 * mult,
|
||||
|
||||
"float.updowncounterobserver.sum/A=B/": -2 * mult,
|
||||
"float.updowncounterobserver.sum/A=B/": -mult,
|
||||
"float.updowncounterobserver.sum/C=D/": mult,
|
||||
"int.updowncounterobserver.sum//": -mult,
|
||||
"int.updowncounterobserver.sum/A=B/": mult,
|
||||
"int.updowncounterobserver.sum//": 0,
|
||||
"int.updowncounterobserver.sum/A=B/": 3 * mult,
|
||||
}, processor.Values())
|
||||
}
|
||||
}
|
||||
@ -351,18 +396,26 @@ func TestCounterObserverInputRange(t *testing.T) {
|
||||
meter, sdk, _, processor := newSDK(t)
|
||||
|
||||
// TODO: these tests are testing for negative values, not for _descending values_. Fix.
|
||||
_ = Must(meter).NewFloat64CounterObserver("float.counterobserver.sum", func(_ context.Context, result metric.Float64ObserverResult) {
|
||||
result.Observe(-2, attribute.String("A", "B"))
|
||||
counterF, _ := meter.AsyncFloat64().Counter("float.counterobserver.sum")
|
||||
err := meter.RegisterCallback([]instrument.Asynchronous{
|
||||
counterF,
|
||||
}, func(ctx context.Context) {
|
||||
counterF.Observe(ctx, -2, attribute.String("A", "B"))
|
||||
require.Equal(t, aggregation.ErrNegativeInput, testHandler.Flush())
|
||||
result.Observe(-1, attribute.String("C", "D"))
|
||||
counterF.Observe(ctx, -1, attribute.String("C", "D"))
|
||||
require.Equal(t, aggregation.ErrNegativeInput, testHandler.Flush())
|
||||
})
|
||||
_ = Must(meter).NewInt64CounterObserver("int.counterobserver.sum", func(_ context.Context, result metric.Int64ObserverResult) {
|
||||
result.Observe(-1, attribute.String("A", "B"))
|
||||
require.NoError(t, err)
|
||||
counterI, _ := meter.AsyncInt64().Counter("int.counterobserver.sum")
|
||||
err = meter.RegisterCallback([]instrument.Asynchronous{
|
||||
counterI,
|
||||
}, func(ctx context.Context) {
|
||||
counterI.Observe(ctx, -1, attribute.String("A", "B"))
|
||||
require.Equal(t, aggregation.ErrNegativeInput, testHandler.Flush())
|
||||
result.Observe(-1)
|
||||
counterI.Observe(ctx, -1)
|
||||
require.Equal(t, aggregation.ErrNegativeInput, testHandler.Flush())
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
collected := sdk.Collect(ctx)
|
||||
|
||||
@ -377,51 +430,43 @@ func TestObserverBatch(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
meter, sdk, _, processor := newSDK(t)
|
||||
|
||||
var floatGaugeObs metric.Float64GaugeObserver
|
||||
var intGaugeObs metric.Int64GaugeObserver
|
||||
var floatCounterObs metric.Float64CounterObserver
|
||||
var intCounterObs metric.Int64CounterObserver
|
||||
var floatUpDownCounterObs metric.Float64UpDownCounterObserver
|
||||
var intUpDownCounterObs metric.Int64UpDownCounterObserver
|
||||
floatGaugeObs, _ := meter.AsyncFloat64().Gauge("float.gauge.lastvalue")
|
||||
intGaugeObs, _ := meter.AsyncInt64().Gauge("int.gauge.lastvalue")
|
||||
floatCounterObs, _ := meter.AsyncFloat64().Counter("float.counterobserver.sum")
|
||||
intCounterObs, _ := meter.AsyncInt64().Counter("int.counterobserver.sum")
|
||||
floatUpDownCounterObs, _ := meter.AsyncFloat64().UpDownCounter("float.updowncounterobserver.sum")
|
||||
intUpDownCounterObs, _ := meter.AsyncInt64().UpDownCounter("int.updowncounterobserver.sum")
|
||||
|
||||
var batch = Must(meter).NewBatchObserver(
|
||||
func(_ context.Context, result metric.BatchObserverResult) {
|
||||
result.Observe(
|
||||
[]attribute.KeyValue{
|
||||
attribute.String("A", "B"),
|
||||
},
|
||||
floatGaugeObs.Observation(1),
|
||||
floatGaugeObs.Observation(-1),
|
||||
intGaugeObs.Observation(-1),
|
||||
intGaugeObs.Observation(1),
|
||||
floatCounterObs.Observation(1000),
|
||||
intCounterObs.Observation(100),
|
||||
floatUpDownCounterObs.Observation(-1000),
|
||||
intUpDownCounterObs.Observation(-100),
|
||||
)
|
||||
result.Observe(
|
||||
[]attribute.KeyValue{
|
||||
attribute.String("C", "D"),
|
||||
},
|
||||
floatGaugeObs.Observation(-1),
|
||||
floatCounterObs.Observation(-1),
|
||||
floatUpDownCounterObs.Observation(-1),
|
||||
)
|
||||
result.Observe(
|
||||
nil,
|
||||
intGaugeObs.Observation(1),
|
||||
intGaugeObs.Observation(1),
|
||||
intCounterObs.Observation(10),
|
||||
floatCounterObs.Observation(1.1),
|
||||
intUpDownCounterObs.Observation(10),
|
||||
)
|
||||
err := meter.RegisterCallback([]instrument.Asynchronous{
|
||||
floatGaugeObs,
|
||||
intGaugeObs,
|
||||
floatCounterObs,
|
||||
intCounterObs,
|
||||
floatUpDownCounterObs,
|
||||
intUpDownCounterObs,
|
||||
}, func(ctx context.Context) {
|
||||
ab := attribute.String("A", "B")
|
||||
floatGaugeObs.Observe(ctx, 1, ab)
|
||||
floatGaugeObs.Observe(ctx, -1, ab)
|
||||
intGaugeObs.Observe(ctx, -1, ab)
|
||||
intGaugeObs.Observe(ctx, 1, ab)
|
||||
floatCounterObs.Observe(ctx, 1000, ab)
|
||||
intCounterObs.Observe(ctx, 100, ab)
|
||||
floatUpDownCounterObs.Observe(ctx, -1000, ab)
|
||||
intUpDownCounterObs.Observe(ctx, -100, ab)
|
||||
|
||||
cd := attribute.String("C", "D")
|
||||
floatGaugeObs.Observe(ctx, -1, cd)
|
||||
floatCounterObs.Observe(ctx, -1, cd)
|
||||
floatUpDownCounterObs.Observe(ctx, -1, cd)
|
||||
|
||||
intGaugeObs.Observe(ctx, 1)
|
||||
intGaugeObs.Observe(ctx, 1)
|
||||
intCounterObs.Observe(ctx, 10)
|
||||
floatCounterObs.Observe(ctx, 1.1)
|
||||
intUpDownCounterObs.Observe(ctx, 10)
|
||||
})
|
||||
floatGaugeObs = batch.NewFloat64GaugeObserver("float.gauge.lastvalue")
|
||||
intGaugeObs = batch.NewInt64GaugeObserver("int.gauge.lastvalue")
|
||||
floatCounterObs = batch.NewFloat64CounterObserver("float.counterobserver.sum")
|
||||
intCounterObs = batch.NewInt64CounterObserver("int.counterobserver.sum")
|
||||
floatUpDownCounterObs = batch.NewFloat64UpDownCounterObserver("float.updowncounterobserver.sum")
|
||||
intUpDownCounterObs = batch.NewInt64UpDownCounterObserver("int.updowncounterobserver.sum")
|
||||
require.NoError(t, err)
|
||||
|
||||
collected := sdk.Collect(ctx)
|
||||
|
||||
@ -445,37 +490,6 @@ func TestObserverBatch(t *testing.T) {
|
||||
}, processor.Values())
|
||||
}
|
||||
|
||||
func TestRecordBatch(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
meter, sdk, _, processor := newSDK(t)
|
||||
|
||||
counter1 := Must(meter).NewInt64Counter("int64.sum")
|
||||
counter2 := Must(meter).NewFloat64Counter("float64.sum")
|
||||
histogram1 := Must(meter).NewInt64Histogram("int64.histogram")
|
||||
histogram2 := Must(meter).NewFloat64Histogram("float64.histogram")
|
||||
|
||||
sdk.RecordBatch(
|
||||
ctx,
|
||||
[]attribute.KeyValue{
|
||||
attribute.String("A", "B"),
|
||||
attribute.String("C", "D"),
|
||||
},
|
||||
counter1.Measurement(1),
|
||||
counter2.Measurement(2),
|
||||
histogram1.Measurement(3),
|
||||
histogram2.Measurement(4),
|
||||
)
|
||||
|
||||
sdk.Collect(ctx)
|
||||
|
||||
require.EqualValues(t, map[string]float64{
|
||||
"int64.sum/A=B,C=D/": 1,
|
||||
"float64.sum/A=B,C=D/": 2,
|
||||
"int64.histogram/A=B,C=D/": 3,
|
||||
"float64.histogram/A=B,C=D/": 4,
|
||||
}, processor.Values())
|
||||
}
|
||||
|
||||
// TestRecordPersistence ensures that a direct-called instrument that
|
||||
// is repeatedly used each interval results in a persistent record, so
|
||||
// that its encoded labels will be cached across collection intervals.
|
||||
@ -483,7 +497,9 @@ func TestRecordPersistence(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
meter, sdk, selector, _ := newSDK(t)
|
||||
|
||||
c := Must(meter).NewFloat64Counter("name.sum")
|
||||
c, err := meter.SyncFloat64().Counter("name.sum")
|
||||
require.NoError(t, err)
|
||||
|
||||
uk := attribute.String("bound", "false")
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
@ -497,51 +513,58 @@ func TestRecordPersistence(t *testing.T) {
|
||||
func TestIncorrectInstruments(t *testing.T) {
|
||||
// The Batch observe/record APIs are susceptible to
|
||||
// uninitialized instruments.
|
||||
var counter metric.Int64Counter
|
||||
var observer metric.Int64GaugeObserver
|
||||
var observer asyncint64.Gauge
|
||||
|
||||
ctx := context.Background()
|
||||
meter, sdk, _, processor := newSDK(t)
|
||||
|
||||
// Now try with uninitialized instruments.
|
||||
meter.RecordBatch(ctx, nil, counter.Measurement(1))
|
||||
meter.NewBatchObserver(func(_ context.Context, result metric.BatchObserverResult) {
|
||||
result.Observe(nil, observer.Observation(1))
|
||||
err := meter.RegisterCallback([]instrument.Asynchronous{
|
||||
observer,
|
||||
}, func(ctx context.Context) {
|
||||
observer.Observe(ctx, 1)
|
||||
})
|
||||
require.ErrorIs(t, err, metricsdk.ErrBadInstrument)
|
||||
|
||||
collected := sdk.Collect(ctx)
|
||||
require.Equal(t, metricsdk.ErrUninitializedInstrument, testHandler.Flush())
|
||||
err = testHandler.Flush()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, collected)
|
||||
|
||||
// Now try with instruments from another SDK.
|
||||
var noopMeter metric.Meter
|
||||
counter = metric.Must(noopMeter).NewInt64Counter("name.sum")
|
||||
observer = metric.Must(noopMeter).NewBatchObserver(
|
||||
func(context.Context, metric.BatchObserverResult) {},
|
||||
).NewInt64GaugeObserver("observer")
|
||||
noopMeter := nonrecording.NewNoopMeter()
|
||||
observer, _ = noopMeter.AsyncInt64().Gauge("observer")
|
||||
|
||||
meter.RecordBatch(ctx, nil, counter.Measurement(1))
|
||||
meter.NewBatchObserver(func(_ context.Context, result metric.BatchObserverResult) {
|
||||
result.Observe(nil, observer.Observation(1))
|
||||
})
|
||||
err = meter.RegisterCallback(
|
||||
[]instrument.Asynchronous{observer},
|
||||
func(ctx context.Context) {
|
||||
observer.Observe(ctx, 1)
|
||||
},
|
||||
)
|
||||
require.ErrorIs(t, err, metricsdk.ErrBadInstrument)
|
||||
|
||||
collected = sdk.Collect(ctx)
|
||||
require.Equal(t, 0, collected)
|
||||
require.EqualValues(t, map[string]float64{}, processor.Values())
|
||||
require.Equal(t, metricsdk.ErrUninitializedInstrument, testHandler.Flush())
|
||||
|
||||
err = testHandler.Flush()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestSyncInAsync(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
meter, sdk, _, processor := newSDK(t)
|
||||
|
||||
counter := Must(meter).NewFloat64Counter("counter.sum")
|
||||
_ = Must(meter).NewInt64GaugeObserver("observer.lastvalue",
|
||||
func(ctx context.Context, result metric.Int64ObserverResult) {
|
||||
result.Observe(10)
|
||||
counter, _ := meter.SyncFloat64().Counter("counter.sum")
|
||||
gauge, _ := meter.AsyncInt64().Gauge("observer.lastvalue")
|
||||
|
||||
err := meter.RegisterCallback([]instrument.Asynchronous{
|
||||
gauge,
|
||||
}, func(ctx context.Context) {
|
||||
gauge.Observe(ctx, 10)
|
||||
counter.Add(ctx, 100)
|
||||
},
|
||||
)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
sdk.Collect(ctx)
|
||||
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
)
|
||||
|
||||
// These interfaces describe the various ways to access state from an
|
||||
|
@ -17,7 +17,7 @@
|
||||
package aggregation // import "go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
|
||||
import (
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
// Temporality indicates the temporal aggregation exported by an exporter.
|
||||
|
@ -19,9 +19,9 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"go.opentelemetry.io/otel/metric/metrictest"
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/metric/metrictest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
func TestTemporalityIncludes(t *testing.T) {
|
||||
|
@ -20,10 +20,10 @@ import (
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/instrumentation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
)
|
||||
|
||||
|
@ -42,7 +42,6 @@ require (
|
||||
github.com/benbjohnson/clock v1.3.0
|
||||
github.com/stretchr/testify v1.7.0
|
||||
go.opentelemetry.io/otel v1.4.1
|
||||
go.opentelemetry.io/otel/internal/metric v0.27.0
|
||||
go.opentelemetry.io/otel/metric v0.27.0
|
||||
go.opentelemetry.io/otel/sdk v1.4.1
|
||||
)
|
||||
@ -55,8 +54,6 @@ replace go.opentelemetry.io/otel/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
|
||||
|
@ -22,10 +22,10 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"go.opentelemetry.io/otel/metric/metrictest"
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator/histogram"
|
||||
"go.opentelemetry.io/otel/sdk/metric/metrictest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
func TestStressInt64Histogram(t *testing.T) {
|
||||
|
56
sdk/metric/metrictest/meter.go
Normal file
56
sdk/metric/metrictest/meter.go
Normal file
@ -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 metrictest // import "go.opentelemetry.io/otel/sdk/metric/metrictest"
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/metric/instrument"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
Measurement struct {
|
||||
// Number needs to be aligned for 64-bit atomic operations.
|
||||
Number number.Number
|
||||
Instrument sdkapi.InstrumentImpl
|
||||
}
|
||||
)
|
||||
|
||||
// NewDescriptor is a test helper for constructing test metric
|
||||
// descriptors using standard options.
|
||||
func NewDescriptor(name string, ikind sdkapi.InstrumentKind, nkind number.Kind, opts ...instrument.Option) sdkapi.Descriptor {
|
||||
cfg := instrument.NewConfig(opts...)
|
||||
return sdkapi.NewDescriptor(name, ikind, nkind, cfg.Description(), cfg.Unit())
|
||||
}
|
@ -20,4 +20,4 @@ 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"
|
||||
package number // import "go.opentelemetry.io/otel/sdk/metric/number"
|
@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package number // import "go.opentelemetry.io/otel/metric/number"
|
||||
package number // import "go.opentelemetry.io/otel/sdk/metric/number"
|
||||
|
||||
//go:generate stringer -type=Kind
|
||||
|
@ -21,10 +21,10 @@ import (
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
type (
|
||||
|
@ -25,19 +25,19 @@ import (
|
||||
"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/instrument"
|
||||
"go.opentelemetry.io/otel/sdk/instrumentation"
|
||||
sdk "go.opentelemetry.io/otel/sdk/metric"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator/aggregatortest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/metrictest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/processor/basic"
|
||||
"go.opentelemetry.io/otel/sdk/metric/processor/processortest"
|
||||
processorTest "go.opentelemetry.io/otel/sdk/metric/processor/processortest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
)
|
||||
|
||||
@ -450,15 +450,16 @@ func TestCounterObserverEndToEnd(t *testing.T) {
|
||||
eselector,
|
||||
)
|
||||
accum := sdk.NewAccumulator(proc)
|
||||
meter := metric.WrapMeterImpl(accum)
|
||||
meter := sdkapi.WrapMeterImpl(accum)
|
||||
|
||||
var calls int64
|
||||
metric.Must(meter).NewInt64CounterObserver("observer.sum",
|
||||
func(_ context.Context, result metric.Int64ObserverResult) {
|
||||
ctr, err := meter.AsyncInt64().Counter("observer.sum")
|
||||
require.NoError(t, err)
|
||||
err = meter.RegisterCallback([]instrument.Asynchronous{ctr}, func(ctx context.Context) {
|
||||
calls++
|
||||
result.Observe(calls)
|
||||
},
|
||||
)
|
||||
ctr.Observe(ctx, calls)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
reader := proc.Reader()
|
||||
|
||||
var startTime [3]time.Time
|
||||
|
@ -22,7 +22,6 @@ import (
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/instrumentation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator/histogram"
|
||||
@ -30,6 +29,7 @@ import (
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator/sum"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
)
|
||||
|
||||
|
@ -21,33 +21,37 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
"go.opentelemetry.io/otel/metric/instrument"
|
||||
"go.opentelemetry.io/otel/sdk/instrumentation"
|
||||
metricsdk "go.opentelemetry.io/otel/sdk/metric"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/processor/processortest"
|
||||
processorTest "go.opentelemetry.io/otel/sdk/metric/processor/processortest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
)
|
||||
|
||||
func generateTestData(proc export.Processor) {
|
||||
func generateTestData(t *testing.T, proc export.Processor) {
|
||||
ctx := context.Background()
|
||||
accum := metricsdk.NewAccumulator(proc)
|
||||
meter := metric.WrapMeterImpl(accum)
|
||||
meter := sdkapi.WrapMeterImpl(accum)
|
||||
|
||||
counter := metric.Must(meter).NewFloat64Counter("counter.sum")
|
||||
|
||||
_ = metric.Must(meter).NewInt64CounterObserver("observer.sum",
|
||||
func(_ context.Context, result metric.Int64ObserverResult) {
|
||||
result.Observe(10, attribute.String("K1", "V1"))
|
||||
result.Observe(11, attribute.String("K1", "V2"))
|
||||
},
|
||||
)
|
||||
counter, err := meter.SyncFloat64().Counter("counter.sum")
|
||||
require.NoError(t, err)
|
||||
|
||||
counter.Add(ctx, 100, attribute.String("K1", "V1"))
|
||||
counter.Add(ctx, 101, attribute.String("K1", "V2"))
|
||||
|
||||
counterObserver, err := meter.AsyncInt64().Counter("observer.sum")
|
||||
require.NoError(t, err)
|
||||
|
||||
err = meter.RegisterCallback([]instrument.Asynchronous{counterObserver}, func(ctx context.Context) {
|
||||
counterObserver.Observe(ctx, 10, attribute.String("K1", "V1"))
|
||||
counterObserver.Observe(ctx, 11, attribute.String("K1", "V2"))
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
accum.Collect(ctx)
|
||||
}
|
||||
|
||||
@ -60,7 +64,7 @@ func TestProcessorTesting(t *testing.T) {
|
||||
attribute.DefaultEncoder(),
|
||||
),
|
||||
)
|
||||
generateTestData(checkpointer)
|
||||
generateTestData(t, checkpointer)
|
||||
|
||||
res := resource.NewSchemaless(attribute.String("R", "V"))
|
||||
expect := map[string]float64{
|
||||
|
@ -16,8 +16,8 @@ package reducer // import "go.opentelemetry.io/otel/sdk/metric/processor/reducer
|
||||
|
||||
import (
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
type (
|
||||
|
@ -21,8 +21,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/metric/instrument"
|
||||
"go.opentelemetry.io/otel/sdk/instrumentation"
|
||||
metricsdk "go.opentelemetry.io/otel/sdk/metric"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
|
||||
@ -30,6 +29,7 @@ import (
|
||||
"go.opentelemetry.io/otel/sdk/metric/processor/processortest"
|
||||
processorTest "go.opentelemetry.io/otel/sdk/metric/processor/processortest"
|
||||
"go.opentelemetry.io/otel/sdk/metric/processor/reducer"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
)
|
||||
|
||||
@ -54,21 +54,22 @@ func (testFilter) LabelFilterFor(_ *sdkapi.Descriptor) attribute.Filter {
|
||||
}
|
||||
}
|
||||
|
||||
func generateData(impl sdkapi.MeterImpl) {
|
||||
func generateData(t *testing.T, impl sdkapi.MeterImpl) {
|
||||
ctx := context.Background()
|
||||
meter := metric.WrapMeterImpl(impl)
|
||||
|
||||
counter := metric.Must(meter).NewFloat64Counter("counter.sum")
|
||||
|
||||
_ = metric.Must(meter).NewInt64CounterObserver("observer.sum",
|
||||
func(_ context.Context, result metric.Int64ObserverResult) {
|
||||
result.Observe(10, kvs1...)
|
||||
result.Observe(10, kvs2...)
|
||||
},
|
||||
)
|
||||
meter := sdkapi.WrapMeterImpl(impl)
|
||||
|
||||
counter, err := meter.SyncFloat64().Counter("counter.sum")
|
||||
require.NoError(t, err)
|
||||
counter.Add(ctx, 100, kvs1...)
|
||||
counter.Add(ctx, 100, kvs2...)
|
||||
|
||||
counterObserver, err := meter.AsyncInt64().Counter("observer.sum")
|
||||
require.NoError(t, err)
|
||||
err = meter.RegisterCallback([]instrument.Asynchronous{counterObserver}, func(ctx context.Context) {
|
||||
counterObserver.Observe(ctx, 10, kvs1...)
|
||||
counterObserver.Observe(ctx, 10, kvs2...)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestFilterProcessor(t *testing.T) {
|
||||
@ -79,7 +80,7 @@ func TestFilterProcessor(t *testing.T) {
|
||||
accum := metricsdk.NewAccumulator(
|
||||
reducer.New(testFilter{}, processorTest.NewCheckpointer(testProc)),
|
||||
)
|
||||
generateData(accum)
|
||||
generateData(t, accum)
|
||||
|
||||
accum.Collect(context.Background())
|
||||
|
||||
@ -97,7 +98,7 @@ func TestFilterBasicProcessor(t *testing.T) {
|
||||
)
|
||||
exporter := processorTest.New(basicProc, attribute.DefaultEncoder())
|
||||
|
||||
generateData(accum)
|
||||
generateData(t, accum)
|
||||
|
||||
basicProc.StartCollection()
|
||||
accum.Collect(context.Background())
|
||||
|
@ -21,4 +21,4 @@ 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"
|
||||
package registry // import "go.opentelemetry.io/otel/sdk/metric/registry"
|
@ -12,15 +12,15 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package registry // import "go.opentelemetry.io/otel/internal/metric/registry"
|
||||
package registry // import "go.opentelemetry.io/otel/sdk/metric/registry"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/metric/instrument"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
// UniqueInstrumentMeterImpl implements the metric.MeterImpl interface, adding
|
||||
@ -53,11 +53,6 @@ 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 {
|
||||
@ -115,10 +110,7 @@ func (u *UniqueInstrumentMeterImpl) NewSyncInstrument(descriptor sdkapi.Descript
|
||||
}
|
||||
|
||||
// NewAsyncInstrument implements sdkapi.MeterImpl.
|
||||
func (u *UniqueInstrumentMeterImpl) NewAsyncInstrument(
|
||||
descriptor sdkapi.Descriptor,
|
||||
runner sdkapi.AsyncRunner,
|
||||
) (sdkapi.AsyncImpl, error) {
|
||||
func (u *UniqueInstrumentMeterImpl) NewAsyncInstrument(descriptor sdkapi.Descriptor) (sdkapi.AsyncImpl, error) {
|
||||
u.lock.Lock()
|
||||
defer u.lock.Unlock()
|
||||
|
||||
@ -130,10 +122,17 @@ func (u *UniqueInstrumentMeterImpl) NewAsyncInstrument(
|
||||
return impl.(sdkapi.AsyncImpl), nil
|
||||
}
|
||||
|
||||
asyncInst, err := u.impl.NewAsyncInstrument(descriptor, runner)
|
||||
asyncInst, err := u.impl.NewAsyncInstrument(descriptor)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u.state[descriptor.Name()] = asyncInst
|
||||
return asyncInst, nil
|
||||
}
|
||||
|
||||
func (u *UniqueInstrumentMeterImpl) RegisterCallback(insts []instrument.Asynchronous, callback func(context.Context)) error {
|
||||
u.lock.Lock()
|
||||
defer u.lock.Unlock()
|
||||
|
||||
return u.impl.RegisterCallback(insts, callback)
|
||||
}
|
@ -15,16 +15,15 @@
|
||||
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"
|
||||
metricsdk "go.opentelemetry.io/otel/sdk/metric"
|
||||
"go.opentelemetry.io/otel/sdk/metric/registry"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
type (
|
||||
@ -34,22 +33,22 @@ type (
|
||||
var (
|
||||
allNew = map[string]newFunc{
|
||||
"counter.int64": func(m metric.Meter, name string) (sdkapi.InstrumentImpl, error) {
|
||||
return unwrap(m.NewInt64Counter(name))
|
||||
return unwrap(m.SyncInt64().Counter(name))
|
||||
},
|
||||
"counter.float64": func(m metric.Meter, name string) (sdkapi.InstrumentImpl, error) {
|
||||
return unwrap(m.NewFloat64Counter(name))
|
||||
return unwrap(m.SyncFloat64().Counter(name))
|
||||
},
|
||||
"histogram.int64": func(m metric.Meter, name string) (sdkapi.InstrumentImpl, error) {
|
||||
return unwrap(m.NewInt64Histogram(name))
|
||||
return unwrap(m.SyncInt64().Histogram(name))
|
||||
},
|
||||
"histogram.float64": func(m metric.Meter, name string) (sdkapi.InstrumentImpl, error) {
|
||||
return unwrap(m.NewFloat64Histogram(name))
|
||||
return unwrap(m.SyncFloat64().Histogram(name))
|
||||
},
|
||||
"gaugeobserver.int64": func(m metric.Meter, name string) (sdkapi.InstrumentImpl, error) {
|
||||
return unwrap(m.NewInt64GaugeObserver(name, func(context.Context, metric.Int64ObserverResult) {}))
|
||||
return unwrap(m.AsyncInt64().Gauge(name))
|
||||
},
|
||||
"gaugeobserver.float64": func(m metric.Meter, name string) (sdkapi.InstrumentImpl, error) {
|
||||
return unwrap(m.NewFloat64GaugeObserver(name, func(context.Context, metric.Float64ObserverResult) {}))
|
||||
return unwrap(m.AsyncFloat64().Gauge(name))
|
||||
},
|
||||
}
|
||||
)
|
||||
@ -71,10 +70,11 @@ func unwrap(impl interface{}, err error) (sdkapi.InstrumentImpl, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO Replace with controller
|
||||
func testMeterWithRegistry(name string) metric.Meter {
|
||||
return metric.WrapMeterImpl(
|
||||
return sdkapi.WrapMeterImpl(
|
||||
registry.NewUniqueInstrumentMeterImpl(
|
||||
metrictest.NewMeterProvider().Meter(name).MeterImpl(),
|
||||
metricsdk.NewAccumulator(nil),
|
||||
),
|
||||
)
|
||||
}
|
||||
@ -91,21 +91,6 @@ func TestRegistrySameInstruments(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
@ -120,7 +105,7 @@ func TestRegistryDiffInstruments(t *testing.T) {
|
||||
|
||||
other, err := nf(meter, "this")
|
||||
require.Error(t, err)
|
||||
require.NotNil(t, other)
|
||||
require.Nil(t, other)
|
||||
require.True(t, errors.Is(err, registry.ErrMetricKindMismatch))
|
||||
}
|
||||
}
|
@ -23,11 +23,11 @@ import (
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
internal "go.opentelemetry.io/otel/internal/metric"
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/metric/instrument"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
type (
|
||||
@ -44,10 +44,8 @@ type (
|
||||
// current maps `mapkey` to *record.
|
||||
current sync.Map
|
||||
|
||||
// asyncInstruments is a set of
|
||||
// `*asyncInstrument` instances
|
||||
asyncLock sync.Mutex
|
||||
asyncInstruments *internal.AsyncInstrumentState
|
||||
callbackLock sync.Mutex
|
||||
callbacks map[*callback]struct{}
|
||||
|
||||
// currentEpoch is the current epoch number. It is
|
||||
// incremented in `Collect()`.
|
||||
@ -58,15 +56,23 @@ type (
|
||||
|
||||
// collectLock prevents simultaneous calls to Collect().
|
||||
collectLock sync.Mutex
|
||||
}
|
||||
|
||||
// asyncSortSlice has a single purpose - as a temporary
|
||||
// place for sorting during labels creation to avoid
|
||||
// allocation. It is cleared after use.
|
||||
asyncSortSlice attribute.Sortable
|
||||
callback struct {
|
||||
insts map[*asyncInstrument]struct{}
|
||||
f func(context.Context)
|
||||
}
|
||||
|
||||
asyncContextKey struct{}
|
||||
|
||||
asyncInstrument struct {
|
||||
baseInstrument
|
||||
instrument.Asynchronous
|
||||
}
|
||||
|
||||
syncInstrument struct {
|
||||
instrument
|
||||
baseInstrument
|
||||
instrument.Synchronous
|
||||
}
|
||||
|
||||
// mapkey uniquely describes a metric instrument in terms of
|
||||
@ -92,16 +98,10 @@ type (
|
||||
// supports checking for no updates during a round.
|
||||
collectedCount int64
|
||||
|
||||
// storage is the stored label set for this record,
|
||||
// labels is the stored label set for this record,
|
||||
// except in cases where a label set is shared due to
|
||||
// batch recording.
|
||||
storage attribute.Set
|
||||
|
||||
// labels is the processed label set for this record.
|
||||
// this may refer to the `storage` field in another
|
||||
// record if this label set is shared resulting from
|
||||
// `RecordBatch`.
|
||||
labels *attribute.Set
|
||||
labels attribute.Set
|
||||
|
||||
// sortSlice has a single purpose - as a temporary
|
||||
// place for sorting during labels creation to avoid
|
||||
@ -109,7 +109,7 @@ type (
|
||||
sortSlice attribute.Sortable
|
||||
|
||||
// inst is a pointer to the corresponding instrument.
|
||||
inst *syncInstrument
|
||||
inst *baseInstrument
|
||||
|
||||
// current implements the actual RecordOne() API,
|
||||
// depending on the type of aggregation. If nil, the
|
||||
@ -118,36 +118,23 @@ type (
|
||||
checkpoint aggregator.Aggregator
|
||||
}
|
||||
|
||||
instrument struct {
|
||||
baseInstrument struct {
|
||||
meter *Accumulator
|
||||
descriptor sdkapi.Descriptor
|
||||
}
|
||||
|
||||
asyncInstrument struct {
|
||||
instrument
|
||||
// recorders maps ordered labels to the pair of
|
||||
// labelset and recorder
|
||||
recorders map[attribute.Distinct]*labeledRecorder
|
||||
}
|
||||
|
||||
labeledRecorder struct {
|
||||
observedEpoch int64
|
||||
labels *attribute.Set
|
||||
observed aggregator.Aggregator
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
_ sdkapi.MeterImpl = &Accumulator{}
|
||||
_ sdkapi.AsyncImpl = &asyncInstrument{}
|
||||
_ sdkapi.SyncImpl = &syncInstrument{}
|
||||
|
||||
// ErrUninitializedInstrument is returned when an instrument is used when uninitialized.
|
||||
ErrUninitializedInstrument = fmt.Errorf("use of an uninitialized instrument")
|
||||
|
||||
ErrBadInstrument = fmt.Errorf("use of a instrument from another SDK")
|
||||
)
|
||||
|
||||
func (inst *instrument) Descriptor() sdkapi.Descriptor {
|
||||
return inst.descriptor
|
||||
func (b *baseInstrument) Descriptor() sdkapi.Descriptor {
|
||||
return b.descriptor
|
||||
}
|
||||
|
||||
func (a *asyncInstrument) Implementation() interface{} {
|
||||
@ -158,77 +145,24 @@ func (s *syncInstrument) Implementation() interface{} {
|
||||
return s
|
||||
}
|
||||
|
||||
func (a *asyncInstrument) observe(num number.Number, labels *attribute.Set) {
|
||||
if err := aggregator.RangeTest(num, &a.descriptor); err != nil {
|
||||
otel.Handle(err)
|
||||
return
|
||||
}
|
||||
recorder := a.getRecorder(labels)
|
||||
if recorder == nil {
|
||||
// The instrument is disabled according to the
|
||||
// AggregatorSelector.
|
||||
return
|
||||
}
|
||||
if err := recorder.Update(context.Background(), num, &a.descriptor); err != nil {
|
||||
otel.Handle(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (a *asyncInstrument) getRecorder(labels *attribute.Set) aggregator.Aggregator {
|
||||
lrec, ok := a.recorders[labels.Equivalent()]
|
||||
if ok {
|
||||
// Note: SynchronizedMove(nil) can't return an error
|
||||
_ = lrec.observed.SynchronizedMove(nil, &a.descriptor)
|
||||
lrec.observedEpoch = a.meter.currentEpoch
|
||||
a.recorders[labels.Equivalent()] = lrec
|
||||
return lrec.observed
|
||||
}
|
||||
var rec aggregator.Aggregator
|
||||
a.meter.processor.AggregatorFor(&a.descriptor, &rec)
|
||||
if a.recorders == nil {
|
||||
a.recorders = make(map[attribute.Distinct]*labeledRecorder)
|
||||
}
|
||||
// This may store nil recorder in the map, thus disabling the
|
||||
// asyncInstrument for the labelset for good. This is intentional,
|
||||
// but will be revisited later.
|
||||
a.recorders[labels.Equivalent()] = &labeledRecorder{
|
||||
observed: rec,
|
||||
labels: labels,
|
||||
observedEpoch: a.meter.currentEpoch,
|
||||
}
|
||||
return rec
|
||||
}
|
||||
|
||||
// acquireHandle gets or creates a `*record` corresponding to `kvs`,
|
||||
// the input labels. The second argument `labels` is passed in to
|
||||
// support re-use of the orderedLabels computed by a previous
|
||||
// measurement in the same batch. This performs two allocations
|
||||
// in the common case.
|
||||
func (s *syncInstrument) acquireHandle(kvs []attribute.KeyValue, labelPtr *attribute.Set) *record {
|
||||
var rec *record
|
||||
var equiv attribute.Distinct
|
||||
// the input labels.
|
||||
func (b *baseInstrument) acquireHandle(kvs []attribute.KeyValue) *record {
|
||||
|
||||
if labelPtr == nil {
|
||||
// This memory allocation may not be used, but it's
|
||||
// needed for the `sortSlice` field, to avoid an
|
||||
// allocation while sorting.
|
||||
rec = &record{}
|
||||
rec.storage = attribute.NewSetWithSortable(kvs, &rec.sortSlice)
|
||||
rec.labels = &rec.storage
|
||||
equiv = rec.storage.Equivalent()
|
||||
} else {
|
||||
equiv = labelPtr.Equivalent()
|
||||
}
|
||||
rec := &record{}
|
||||
rec.labels = attribute.NewSetWithSortable(kvs, &rec.sortSlice)
|
||||
|
||||
// Create lookup key for sync.Map (one allocation, as this
|
||||
// passes through an interface{})
|
||||
mk := mapkey{
|
||||
descriptor: &s.descriptor,
|
||||
ordered: equiv,
|
||||
descriptor: &b.descriptor,
|
||||
ordered: rec.labels.Equivalent(),
|
||||
}
|
||||
|
||||
if actual, ok := s.meter.current.Load(mk); ok {
|
||||
if actual, ok := b.meter.current.Load(mk); ok {
|
||||
// Existing record case.
|
||||
existingRec := actual.(*record)
|
||||
if existingRec.refMapped.ref() {
|
||||
@ -239,19 +173,15 @@ func (s *syncInstrument) acquireHandle(kvs []attribute.KeyValue, labelPtr *attri
|
||||
// This entry is no longer mapped, try to add a new entry.
|
||||
}
|
||||
|
||||
if rec == nil {
|
||||
rec = &record{}
|
||||
rec.labels = labelPtr
|
||||
}
|
||||
rec.refMapped = refcountMapped{value: 2}
|
||||
rec.inst = s
|
||||
rec.inst = b
|
||||
|
||||
s.meter.processor.AggregatorFor(&s.descriptor, &rec.current, &rec.checkpoint)
|
||||
b.meter.processor.AggregatorFor(&b.descriptor, &rec.current, &rec.checkpoint)
|
||||
|
||||
for {
|
||||
// Load/Store: there's a memory allocation to place `mk` into
|
||||
// an interface here.
|
||||
if actual, loaded := s.meter.current.LoadOrStore(mk, rec); loaded {
|
||||
if actual, loaded := b.meter.current.LoadOrStore(mk, rec); loaded {
|
||||
// Existing record case. Cannot change rec here because if fail
|
||||
// will try to add rec again to avoid new allocations.
|
||||
oldRec := actual.(*record)
|
||||
@ -278,11 +208,22 @@ func (s *syncInstrument) acquireHandle(kvs []attribute.KeyValue, labelPtr *attri
|
||||
}
|
||||
}
|
||||
|
||||
// RecordOne captures a single synchronous metric event.
|
||||
//
|
||||
// The order of the input array `kvs` may be sorted after the function is called.
|
||||
func (s *syncInstrument) RecordOne(ctx context.Context, num number.Number, kvs []attribute.KeyValue) {
|
||||
h := s.acquireHandle(kvs, nil)
|
||||
h := s.acquireHandle(kvs)
|
||||
defer h.unbind()
|
||||
h.RecordOne(ctx, num)
|
||||
h.captureOne(ctx, num)
|
||||
}
|
||||
|
||||
// ObserveOne captures a single asynchronous metric event.
|
||||
|
||||
// The order of the input array `kvs` may be sorted after the function is called.
|
||||
func (a *asyncInstrument) ObserveOne(ctx context.Context, num number.Number, attrs []attribute.KeyValue) {
|
||||
h := a.acquireHandle(attrs)
|
||||
defer h.unbind()
|
||||
h.captureOne(ctx, num)
|
||||
}
|
||||
|
||||
// NewAccumulator constructs a new Accumulator for the given
|
||||
@ -297,14 +238,16 @@ func (s *syncInstrument) RecordOne(ctx context.Context, num number.Number, kvs [
|
||||
func NewAccumulator(processor export.Processor) *Accumulator {
|
||||
return &Accumulator{
|
||||
processor: processor,
|
||||
asyncInstruments: internal.NewAsyncInstrumentState(),
|
||||
callbacks: map[*callback]struct{}{},
|
||||
}
|
||||
}
|
||||
|
||||
var _ sdkapi.MeterImpl = &Accumulator{}
|
||||
|
||||
// NewSyncInstrument implements sdkapi.MetricImpl.
|
||||
func (m *Accumulator) NewSyncInstrument(descriptor sdkapi.Descriptor) (sdkapi.SyncImpl, error) {
|
||||
return &syncInstrument{
|
||||
instrument: instrument{
|
||||
baseInstrument: baseInstrument{
|
||||
descriptor: descriptor,
|
||||
meter: m,
|
||||
},
|
||||
@ -312,19 +255,40 @@ func (m *Accumulator) NewSyncInstrument(descriptor sdkapi.Descriptor) (sdkapi.Sy
|
||||
}
|
||||
|
||||
// NewAsyncInstrument implements sdkapi.MetricImpl.
|
||||
func (m *Accumulator) NewAsyncInstrument(descriptor sdkapi.Descriptor, runner sdkapi.AsyncRunner) (sdkapi.AsyncImpl, error) {
|
||||
func (m *Accumulator) NewAsyncInstrument(descriptor sdkapi.Descriptor) (sdkapi.AsyncImpl, error) {
|
||||
a := &asyncInstrument{
|
||||
instrument: instrument{
|
||||
baseInstrument: baseInstrument{
|
||||
descriptor: descriptor,
|
||||
meter: m,
|
||||
},
|
||||
}
|
||||
m.asyncLock.Lock()
|
||||
defer m.asyncLock.Unlock()
|
||||
m.asyncInstruments.Register(a, runner)
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func (m *Accumulator) RegisterCallback(insts []instrument.Asynchronous, f func(context.Context)) error {
|
||||
cb := &callback{
|
||||
insts: map[*asyncInstrument]struct{}{},
|
||||
f: f,
|
||||
}
|
||||
for _, inst := range insts {
|
||||
impl, ok := inst.(sdkapi.AsyncImpl)
|
||||
if !ok {
|
||||
return ErrBadInstrument
|
||||
}
|
||||
|
||||
ai, err := m.fromAsync(impl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cb.insts[ai] = struct{}{}
|
||||
}
|
||||
|
||||
m.callbackLock.Lock()
|
||||
defer m.callbackLock.Unlock()
|
||||
m.callbacks[cb] = struct{}{}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Collect traverses the list of active records and observers and
|
||||
// exports data for each active instrument. Collect() may not be
|
||||
// called concurrently.
|
||||
@ -337,14 +301,14 @@ func (m *Accumulator) Collect(ctx context.Context) int {
|
||||
m.collectLock.Lock()
|
||||
defer m.collectLock.Unlock()
|
||||
|
||||
checkpointed := m.observeAsyncInstruments(ctx)
|
||||
checkpointed += m.collectSyncInstruments()
|
||||
m.runAsyncCallbacks(ctx)
|
||||
checkpointed := m.collectInstruments()
|
||||
m.currentEpoch++
|
||||
|
||||
return checkpointed
|
||||
}
|
||||
|
||||
func (m *Accumulator) collectSyncInstruments() int {
|
||||
func (m *Accumulator) collectInstruments() int {
|
||||
checkpointed := 0
|
||||
|
||||
m.current.Range(func(key interface{}, value interface{}) bool {
|
||||
@ -387,33 +351,15 @@ func (m *Accumulator) collectSyncInstruments() int {
|
||||
return checkpointed
|
||||
}
|
||||
|
||||
// CollectAsync implements internal.AsyncCollector.
|
||||
// The order of the input array `kvs` may be sorted after the function is called.
|
||||
func (m *Accumulator) CollectAsync(kv []attribute.KeyValue, obs ...sdkapi.Observation) {
|
||||
labels := attribute.NewSetWithSortable(kv, &m.asyncSortSlice)
|
||||
func (m *Accumulator) runAsyncCallbacks(ctx context.Context) {
|
||||
m.callbackLock.Lock()
|
||||
defer m.callbackLock.Unlock()
|
||||
|
||||
for _, ob := range obs {
|
||||
if a := m.fromAsync(ob.AsyncImpl()); a != nil {
|
||||
a.observe(ob.Number(), &labels)
|
||||
ctx = context.WithValue(ctx, asyncContextKey{}, m)
|
||||
|
||||
for cb := range m.callbacks {
|
||||
cb.f(ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Accumulator) observeAsyncInstruments(ctx context.Context) int {
|
||||
m.asyncLock.Lock()
|
||||
defer m.asyncLock.Unlock()
|
||||
|
||||
asyncCollected := 0
|
||||
|
||||
m.asyncInstruments.Run(ctx, m)
|
||||
|
||||
for _, inst := range m.asyncInstruments.Instruments() {
|
||||
if a := m.fromAsync(inst); a != nil {
|
||||
asyncCollected += m.checkpointAsync(a)
|
||||
}
|
||||
}
|
||||
|
||||
return asyncCollected
|
||||
}
|
||||
|
||||
func (m *Accumulator) checkpointRecord(r *record) int {
|
||||
@ -426,7 +372,7 @@ func (m *Accumulator) checkpointRecord(r *record) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
a := export.NewAccumulation(&r.inst.descriptor, r.labels, r.checkpoint)
|
||||
a := export.NewAccumulation(&r.inst.descriptor, &r.labels, r.checkpoint)
|
||||
err = m.processor.Process(a)
|
||||
if err != nil {
|
||||
otel.Handle(err)
|
||||
@ -434,63 +380,7 @@ func (m *Accumulator) checkpointRecord(r *record) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func (m *Accumulator) checkpointAsync(a *asyncInstrument) int {
|
||||
if len(a.recorders) == 0 {
|
||||
return 0
|
||||
}
|
||||
checkpointed := 0
|
||||
for encodedLabels, lrec := range a.recorders {
|
||||
lrec := lrec
|
||||
epochDiff := m.currentEpoch - lrec.observedEpoch
|
||||
if epochDiff == 0 {
|
||||
if lrec.observed != nil {
|
||||
a := export.NewAccumulation(&a.descriptor, lrec.labels, lrec.observed)
|
||||
err := m.processor.Process(a)
|
||||
if err != nil {
|
||||
otel.Handle(err)
|
||||
}
|
||||
checkpointed++
|
||||
}
|
||||
} else if epochDiff > 1 {
|
||||
// This is second collection cycle with no
|
||||
// observations for this labelset. Remove the
|
||||
// recorder.
|
||||
delete(a.recorders, encodedLabels)
|
||||
}
|
||||
}
|
||||
if len(a.recorders) == 0 {
|
||||
a.recorders = nil
|
||||
}
|
||||
return checkpointed
|
||||
}
|
||||
|
||||
// RecordBatch enters a batch of metric events.
|
||||
// The order of the input array `kvs` may be sorted after the function is called.
|
||||
func (m *Accumulator) RecordBatch(ctx context.Context, kvs []attribute.KeyValue, measurements ...sdkapi.Measurement) {
|
||||
// Labels will be computed the first time acquireHandle is
|
||||
// called. Subsequent calls to acquireHandle will re-use the
|
||||
// previously computed value instead of recomputing the
|
||||
// ordered labels.
|
||||
var labelsPtr *attribute.Set
|
||||
for i, meas := range measurements {
|
||||
s := m.fromSync(meas.SyncImpl())
|
||||
if s == nil {
|
||||
continue
|
||||
}
|
||||
h := s.acquireHandle(kvs, labelsPtr)
|
||||
|
||||
// Re-use labels for the next measurement.
|
||||
if i == 0 {
|
||||
labelsPtr = h.labels
|
||||
}
|
||||
|
||||
defer h.unbind()
|
||||
h.RecordOne(ctx, meas.Number())
|
||||
}
|
||||
}
|
||||
|
||||
// RecordOne implements sdkapi.SyncImpl.
|
||||
func (r *record) RecordOne(ctx context.Context, num number.Number) {
|
||||
func (r *record) captureOne(ctx context.Context, num number.Number) {
|
||||
if r.current == nil {
|
||||
// The instrument is disabled according to the AggregatorSelector.
|
||||
return
|
||||
@ -519,26 +409,16 @@ func (r *record) mapkey() mapkey {
|
||||
}
|
||||
}
|
||||
|
||||
// fromSync gets a sync implementation object, checking for
|
||||
// uninitialized instruments and instruments created by another SDK.
|
||||
func (m *Accumulator) fromSync(sync sdkapi.SyncImpl) *syncInstrument {
|
||||
if sync != nil {
|
||||
if inst, ok := sync.Implementation().(*syncInstrument); ok {
|
||||
return inst
|
||||
}
|
||||
}
|
||||
otel.Handle(ErrUninitializedInstrument)
|
||||
return nil
|
||||
}
|
||||
|
||||
// fromSync gets an async implementation object, checking for
|
||||
// uninitialized instruments and instruments created by another SDK.
|
||||
func (m *Accumulator) fromAsync(async sdkapi.AsyncImpl) *asyncInstrument {
|
||||
if async != nil {
|
||||
if inst, ok := async.Implementation().(*asyncInstrument); ok {
|
||||
return inst
|
||||
func (m *Accumulator) fromAsync(async sdkapi.AsyncImpl) (*asyncInstrument, error) {
|
||||
if async == nil {
|
||||
return nil, ErrUninitializedInstrument
|
||||
}
|
||||
inst, ok := async.Implementation().(*asyncInstrument)
|
||||
if !ok {
|
||||
return nil, ErrBadInstrument
|
||||
}
|
||||
otel.Handle(ErrUninitializedInstrument)
|
||||
return nil
|
||||
return inst, nil
|
||||
|
||||
}
|
||||
|
@ -12,11 +12,11 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package sdkapi // import "go.opentelemetry.io/otel/metric/sdkapi"
|
||||
package sdkapi // import "go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
|
||||
import (
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/metric/unit"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
)
|
||||
|
||||
// Descriptor contains all the settings that describe an instrument,
|
@ -19,8 +19,8 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/metric/unit"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
)
|
||||
|
||||
func TestDescriptorGetters(t *testing.T) {
|
@ -14,7 +14,7 @@
|
||||
|
||||
//go:generate stringer -type=InstrumentKind
|
||||
|
||||
package sdkapi // import "go.opentelemetry.io/otel/metric/sdkapi"
|
||||
package sdkapi // import "go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
|
||||
// InstrumentKind describes the kind of instrument.
|
||||
type InstrumentKind int8
|
@ -19,7 +19,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
func TestInstrumentKinds(t *testing.T) {
|
@ -12,20 +12,34 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package sdkapi // import "go.opentelemetry.io/otel/metric/sdkapi"
|
||||
package sdkapi // import "go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
)
|
||||
"go.opentelemetry.io/otel/metric/instrument"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
) // import (
|
||||
// "context"
|
||||
|
||||
// "go.opentelemetry.io/otel/attribute"
|
||||
// "go.opentelemetry.io/otel/sdk/metric/number"
|
||||
// )
|
||||
|
||||
type noopInstrument struct {
|
||||
descriptor Descriptor
|
||||
}
|
||||
type noopSyncInstrument struct{ noopInstrument }
|
||||
type noopAsyncInstrument struct{ noopInstrument }
|
||||
type noopSyncInstrument struct {
|
||||
noopInstrument
|
||||
|
||||
instrument.Synchronous
|
||||
}
|
||||
type noopAsyncInstrument struct {
|
||||
noopInstrument
|
||||
|
||||
instrument.Asynchronous
|
||||
}
|
||||
|
||||
var _ SyncImpl = noopSyncInstrument{}
|
||||
var _ AsyncImpl = noopAsyncInstrument{}
|
||||
@ -34,7 +48,7 @@ var _ AsyncImpl = noopAsyncInstrument{}
|
||||
// synchronous instrument interface.
|
||||
func NewNoopSyncInstrument() SyncImpl {
|
||||
return noopSyncInstrument{
|
||||
noopInstrument{
|
||||
noopInstrument: noopInstrument{
|
||||
descriptor: Descriptor{
|
||||
instrumentKind: CounterInstrumentKind,
|
||||
},
|
||||
@ -46,7 +60,7 @@ func NewNoopSyncInstrument() SyncImpl {
|
||||
// asynchronous instrument interface.
|
||||
func NewNoopAsyncInstrument() AsyncImpl {
|
||||
return noopAsyncInstrument{
|
||||
noopInstrument{
|
||||
noopInstrument: noopInstrument{
|
||||
descriptor: Descriptor{
|
||||
instrumentKind: CounterObserverInstrumentKind,
|
||||
},
|
||||
@ -64,3 +78,6 @@ func (n noopInstrument) Descriptor() Descriptor {
|
||||
|
||||
func (noopSyncInstrument) RecordOne(context.Context, number.Number, []attribute.KeyValue) {
|
||||
}
|
||||
|
||||
func (noopAsyncInstrument) ObserveOne(ctx context.Context, number number.Number, labels []attribute.KeyValue) {
|
||||
}
|
@ -12,21 +12,19 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package sdkapi // import "go.opentelemetry.io/otel/metric/sdkapi"
|
||||
package sdkapi // import "go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/metric/instrument"
|
||||
"go.opentelemetry.io/otel/sdk/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.
|
||||
@ -35,10 +33,10 @@ type MeterImpl interface {
|
||||
// NewAsyncInstrument returns a newly constructed
|
||||
// asynchronous instrument implementation or an error, should
|
||||
// one occur.
|
||||
NewAsyncInstrument(
|
||||
descriptor Descriptor,
|
||||
runner AsyncRunner,
|
||||
) (AsyncImpl, error)
|
||||
NewAsyncInstrument(descriptor Descriptor) (AsyncImpl, error)
|
||||
|
||||
// Etc.
|
||||
RegisterCallback(insts []instrument.Asynchronous, callback func(context.Context)) error
|
||||
}
|
||||
|
||||
// InstrumentImpl is a common interface for synchronous and
|
||||
@ -57,6 +55,7 @@ type InstrumentImpl interface {
|
||||
// synchronous instrument (e.g., Histogram and Counter instruments).
|
||||
type SyncImpl interface {
|
||||
InstrumentImpl
|
||||
instrument.Synchronous
|
||||
|
||||
// RecordOne captures a single synchronous metric event.
|
||||
RecordOne(ctx context.Context, number number.Number, labels []attribute.KeyValue)
|
||||
@ -66,6 +65,10 @@ type SyncImpl interface {
|
||||
// asynchronous instrument (e.g., Observer instruments).
|
||||
type AsyncImpl interface {
|
||||
InstrumentImpl
|
||||
instrument.Asynchronous
|
||||
|
||||
// ObserveOne captures a single synchronous metric event.
|
||||
ObserveOne(ctx context.Context, number number.Number, labels []attribute.KeyValue)
|
||||
}
|
||||
|
||||
// AsyncRunner is expected to convert into an AsyncSingleRunner or an
|
@ -19,7 +19,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"go.opentelemetry.io/otel/metric/number"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
)
|
||||
|
||||
func TestMeasurementGetters(t *testing.T) {
|
181
sdk/metric/sdkapi/wrap.go
Normal file
181
sdk/metric/sdkapi/wrap.go
Normal file
@ -0,0 +1,181 @@
|
||||
// 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/sdk/metric/sdkapi"
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
"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"
|
||||
"go.opentelemetry.io/otel/sdk/metric/number"
|
||||
)
|
||||
|
||||
type (
|
||||
meter struct{ MeterImpl }
|
||||
sfMeter struct{ meter }
|
||||
siMeter struct{ meter }
|
||||
afMeter struct{ meter }
|
||||
aiMeter struct{ meter }
|
||||
|
||||
iAdder struct{ SyncImpl }
|
||||
fAdder struct{ SyncImpl }
|
||||
iRecorder struct{ SyncImpl }
|
||||
fRecorder struct{ SyncImpl }
|
||||
iObserver struct{ AsyncImpl }
|
||||
fObserver struct{ AsyncImpl }
|
||||
)
|
||||
|
||||
func WrapMeterImpl(impl MeterImpl) metric.Meter {
|
||||
return meter{impl}
|
||||
}
|
||||
|
||||
func UnwrapMeterImpl(m metric.Meter) MeterImpl {
|
||||
mm, ok := m.(meter)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return mm.MeterImpl
|
||||
}
|
||||
|
||||
func (m meter) AsyncFloat64() asyncfloat64.InstrumentProvider {
|
||||
return afMeter{m}
|
||||
}
|
||||
|
||||
func (m meter) AsyncInt64() asyncint64.InstrumentProvider {
|
||||
return aiMeter{m}
|
||||
}
|
||||
|
||||
func (m meter) SyncFloat64() syncfloat64.InstrumentProvider {
|
||||
return sfMeter{m}
|
||||
}
|
||||
|
||||
func (m meter) SyncInt64() syncint64.InstrumentProvider {
|
||||
return siMeter{m}
|
||||
}
|
||||
|
||||
func (m meter) RegisterCallback(insts []instrument.Asynchronous, cb func(ctx context.Context)) error {
|
||||
return m.MeterImpl.RegisterCallback(insts, cb)
|
||||
}
|
||||
|
||||
func (m meter) newSync(name string, ikind InstrumentKind, nkind number.Kind, opts []instrument.Option) (SyncImpl, error) {
|
||||
cfg := instrument.NewConfig(opts...)
|
||||
return m.NewSyncInstrument(NewDescriptor(name, ikind, nkind, cfg.Description(), cfg.Unit()))
|
||||
}
|
||||
|
||||
func (m meter) newAsync(name string, ikind InstrumentKind, nkind number.Kind, opts []instrument.Option) (AsyncImpl, error) {
|
||||
cfg := instrument.NewConfig(opts...)
|
||||
return m.NewAsyncInstrument(NewDescriptor(name, ikind, nkind, cfg.Description(), cfg.Unit()))
|
||||
}
|
||||
|
||||
func (m afMeter) Counter(name string, opts ...instrument.Option) (asyncfloat64.Counter, error) {
|
||||
inst, err := m.newAsync(name, CounterObserverInstrumentKind, number.Float64Kind, opts)
|
||||
return fObserver{inst}, err
|
||||
}
|
||||
|
||||
func (m afMeter) UpDownCounter(name string, opts ...instrument.Option) (asyncfloat64.UpDownCounter, error) {
|
||||
inst, err := m.newAsync(name, UpDownCounterObserverInstrumentKind, number.Float64Kind, opts)
|
||||
return fObserver{inst}, err
|
||||
}
|
||||
|
||||
func (m afMeter) Gauge(name string, opts ...instrument.Option) (asyncfloat64.Gauge, error) {
|
||||
inst, err := m.newAsync(name, GaugeObserverInstrumentKind, number.Float64Kind, opts)
|
||||
return fObserver{inst}, err
|
||||
}
|
||||
|
||||
func (m aiMeter) Counter(name string, opts ...instrument.Option) (asyncint64.Counter, error) {
|
||||
inst, err := m.newAsync(name, CounterObserverInstrumentKind, number.Int64Kind, opts)
|
||||
return iObserver{inst}, err
|
||||
}
|
||||
|
||||
func (m aiMeter) UpDownCounter(name string, opts ...instrument.Option) (asyncint64.UpDownCounter, error) {
|
||||
inst, err := m.newAsync(name, UpDownCounterObserverInstrumentKind, number.Int64Kind, opts)
|
||||
return iObserver{inst}, err
|
||||
}
|
||||
|
||||
func (m aiMeter) Gauge(name string, opts ...instrument.Option) (asyncint64.Gauge, error) {
|
||||
inst, err := m.newAsync(name, GaugeObserverInstrumentKind, number.Int64Kind, opts)
|
||||
return iObserver{inst}, err
|
||||
}
|
||||
|
||||
func (m sfMeter) Counter(name string, opts ...instrument.Option) (syncfloat64.Counter, error) {
|
||||
inst, err := m.newSync(name, CounterInstrumentKind, number.Float64Kind, opts)
|
||||
return fAdder{inst}, err
|
||||
}
|
||||
|
||||
func (m sfMeter) UpDownCounter(name string, opts ...instrument.Option) (syncfloat64.UpDownCounter, error) {
|
||||
inst, err := m.newSync(name, UpDownCounterInstrumentKind, number.Float64Kind, opts)
|
||||
return fAdder{inst}, err
|
||||
}
|
||||
|
||||
func (m sfMeter) Histogram(name string, opts ...instrument.Option) (syncfloat64.Histogram, error) {
|
||||
inst, err := m.newSync(name, HistogramInstrumentKind, number.Float64Kind, opts)
|
||||
return fRecorder{inst}, err
|
||||
}
|
||||
|
||||
func (m siMeter) Counter(name string, opts ...instrument.Option) (syncint64.Counter, error) {
|
||||
inst, err := m.newSync(name, CounterInstrumentKind, number.Int64Kind, opts)
|
||||
return iAdder{inst}, err
|
||||
}
|
||||
|
||||
func (m siMeter) UpDownCounter(name string, opts ...instrument.Option) (syncint64.UpDownCounter, error) {
|
||||
inst, err := m.newSync(name, UpDownCounterInstrumentKind, number.Int64Kind, opts)
|
||||
return iAdder{inst}, err
|
||||
}
|
||||
|
||||
func (m siMeter) Histogram(name string, opts ...instrument.Option) (syncint64.Histogram, error) {
|
||||
inst, err := m.newSync(name, HistogramInstrumentKind, number.Int64Kind, opts)
|
||||
return iRecorder{inst}, err
|
||||
}
|
||||
|
||||
func (a fAdder) Add(ctx context.Context, value float64, attrs ...attribute.KeyValue) {
|
||||
if a.SyncImpl != nil {
|
||||
a.SyncImpl.RecordOne(ctx, number.NewFloat64Number(value), attrs)
|
||||
}
|
||||
}
|
||||
|
||||
func (a iAdder) Add(ctx context.Context, value int64, attrs ...attribute.KeyValue) {
|
||||
if a.SyncImpl != nil {
|
||||
a.SyncImpl.RecordOne(ctx, number.NewInt64Number(value), attrs)
|
||||
}
|
||||
}
|
||||
|
||||
func (a fRecorder) Record(ctx context.Context, value float64, attrs ...attribute.KeyValue) {
|
||||
if a.SyncImpl != nil {
|
||||
a.SyncImpl.RecordOne(ctx, number.NewFloat64Number(value), attrs)
|
||||
}
|
||||
}
|
||||
|
||||
func (a iRecorder) Record(ctx context.Context, value int64, attrs ...attribute.KeyValue) {
|
||||
if a.SyncImpl != nil {
|
||||
a.SyncImpl.RecordOne(ctx, number.NewInt64Number(value), attrs)
|
||||
}
|
||||
}
|
||||
|
||||
func (a fObserver) Observe(ctx context.Context, value float64, attrs ...attribute.KeyValue) {
|
||||
if a.AsyncImpl != nil {
|
||||
a.AsyncImpl.ObserveOne(ctx, number.NewFloat64Number(value), attrs)
|
||||
}
|
||||
}
|
||||
|
||||
func (a iObserver) Observe(ctx context.Context, value int64, attrs ...attribute.KeyValue) {
|
||||
if a.AsyncImpl != nil {
|
||||
a.AsyncImpl.ObserveOne(ctx, number.NewInt64Number(value), attrs)
|
||||
}
|
||||
}
|
@ -15,12 +15,12 @@
|
||||
package simple // import "go.opentelemetry.io/otel/sdk/metric/selector/simple"
|
||||
|
||||
import (
|
||||
"go.opentelemetry.io/otel/metric/sdkapi"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator/histogram"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator/lastvalue"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregator/sum"
|
||||
"go.opentelemetry.io/otel/sdk/metric/export"
|
||||
"go.opentelemetry.io/otel/sdk/metric/sdkapi"
|
||||
)
|
||||
|
||||
type (
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user