You've already forked opentelemetry-go
							
							
				mirror of
				https://github.com/open-telemetry/opentelemetry-go.git
				synced 2025-10-31 00:07:40 +02:00 
			
		
		
		
	[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:
		
							
								
								
									
										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,34 +351,16 @@ 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 { | ||||
| 	if r.current == nil { | ||||
| @@ -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
		Reference in New Issue
	
	Block a user