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 
			
		
		
		
	Support a global MeterProvider in go.opentelemetry.io/otel (#3818)
				
					
				
			* Move ErrorHandler impl to internal To avoid the import cycle, the otel/metric package needs to not import otel. To achieve this, the error handling implementation is moved to the otel/internal/global package where both can import the needed functionality. * Add global metric to go.opentelemetry.io/otel * Crosslink and update to global metric in otel * Add changes to changelog * Set PR number in changelog * Add global metric unit tests * Rename MeterProivder() to GetMeterProivder() * Add TODO to remove nolint comments
This commit is contained in:
		
							
								
								
									
										12
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -8,6 +8,13 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm | ||||
|  | ||||
| ## [Unreleased] | ||||
|  | ||||
| ### Added | ||||
|  | ||||
| - Support global `MeterProvider` in `go.opentelemetry.io/otel`. (#3818) | ||||
|   - Use `Meter` for a `metric.Meter` from the global `metric.MeterProvider`. | ||||
|   - Use `GetMeterProivder` for a global `metric.MeterProvider`. | ||||
|   - Use `SetMeterProivder` to set the global `metric.MeterProvider`. | ||||
|  | ||||
| ### Changed | ||||
|  | ||||
| - Dropped compatibility testing for [Go 1.18]. | ||||
| @@ -17,6 +24,11 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm | ||||
|  | ||||
| - Handle empty environment variable as it they were not set. (#3764) | ||||
|  | ||||
| ### Deprecated | ||||
|  | ||||
| - The `go.opentelemetry.io/otel/metric/global` package is deprecated. | ||||
|   Use `go.opentelemetry.io/otel` instead. (#3818) | ||||
|  | ||||
| ### Removed | ||||
|  | ||||
| - The deprecated `go.opentelemetry.io/otel/metric/unit` package is removed. (#3814) | ||||
|   | ||||
| @@ -18,5 +18,8 @@ require ( | ||||
| 	github.com/go-logr/logr v1.2.3 // indirect | ||||
| 	github.com/go-logr/stdr v1.2.2 // indirect | ||||
| 	github.com/pmezard/go-difflib v1.0.0 // indirect | ||||
| 	go.opentelemetry.io/otel/metric v0.37.0 // indirect | ||||
| 	gopkg.in/yaml.v3 v3.0.1 // indirect | ||||
| ) | ||||
|  | ||||
| replace go.opentelemetry.io/otel/metric => ../../metric | ||||
|   | ||||
| @@ -23,6 +23,7 @@ require ( | ||||
| 	github.com/go-logr/stdr v1.2.2 // indirect | ||||
| 	github.com/golang/protobuf v1.5.2 // indirect | ||||
| 	github.com/pmezard/go-difflib v1.0.0 // indirect | ||||
| 	go.opentelemetry.io/otel/metric v0.37.0 // indirect | ||||
| 	go.opentelemetry.io/otel/trace v1.14.0 // indirect | ||||
| 	golang.org/x/net v0.7.0 // indirect | ||||
| 	golang.org/x/sys v0.5.0 // indirect | ||||
| @@ -31,3 +32,5 @@ require ( | ||||
| 	google.golang.org/protobuf v1.28.1 // indirect | ||||
| 	gopkg.in/yaml.v3 v3.0.1 // indirect | ||||
| ) | ||||
|  | ||||
| replace go.opentelemetry.io/otel/metric => ../../../metric | ||||
|   | ||||
| @@ -12,6 +12,7 @@ require ( | ||||
| require ( | ||||
| 	github.com/go-logr/logr v1.2.3 // indirect | ||||
| 	github.com/go-logr/stdr v1.2.2 // indirect | ||||
| 	go.opentelemetry.io/otel/metric v0.37.0 // indirect | ||||
| 	golang.org/x/sys v0.5.0 // indirect | ||||
| ) | ||||
|  | ||||
| @@ -22,3 +23,5 @@ replace go.opentelemetry.io/otel/exporters/stdout/stdouttrace => ../../exporters | ||||
| replace go.opentelemetry.io/otel/sdk => ../../sdk | ||||
|  | ||||
| replace go.opentelemetry.io/otel/trace => ../../trace | ||||
|  | ||||
| replace go.opentelemetry.io/otel/metric => ../../metric | ||||
|   | ||||
| @@ -17,8 +17,11 @@ require ( | ||||
| require ( | ||||
| 	github.com/go-logr/logr v1.2.3 // indirect | ||||
| 	github.com/go-logr/stdr v1.2.2 // indirect | ||||
| 	go.opentelemetry.io/otel/metric v0.37.0 // indirect | ||||
| 	go.opentelemetry.io/otel/trace v1.14.0 // indirect | ||||
| 	golang.org/x/sys v0.5.0 // indirect | ||||
| ) | ||||
|  | ||||
| replace go.opentelemetry.io/otel/trace => ../../trace | ||||
|  | ||||
| replace go.opentelemetry.io/otel/metric => ../../metric | ||||
|   | ||||
| @@ -17,9 +17,12 @@ require ( | ||||
|  | ||||
| require ( | ||||
| 	github.com/go-logr/logr v1.2.3 // indirect | ||||
| 	go.opentelemetry.io/otel/metric v0.37.0 // indirect | ||||
| 	golang.org/x/sys v0.5.0 // indirect | ||||
| ) | ||||
|  | ||||
| replace go.opentelemetry.io/otel/trace => ../../trace | ||||
|  | ||||
| replace go.opentelemetry.io/otel/exporters/stdout/stdouttrace => ../../exporters/stdout/stdouttrace | ||||
|  | ||||
| replace go.opentelemetry.io/otel/metric => ../../metric | ||||
|   | ||||
| @@ -23,6 +23,7 @@ require ( | ||||
| 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect | ||||
| 	go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 // indirect | ||||
| 	go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 // indirect | ||||
| 	go.opentelemetry.io/otel/metric v0.37.0 // indirect | ||||
| 	go.opentelemetry.io/proto/otlp v0.19.0 // indirect | ||||
| 	golang.org/x/net v0.7.0 // indirect | ||||
| 	golang.org/x/sys v0.5.0 // indirect | ||||
| @@ -38,3 +39,5 @@ replace go.opentelemetry.io/otel/exporters/otlp/otlptrace => ../../exporters/otl | ||||
| replace go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc => ../../exporters/otlp/otlptrace/otlptracegrpc | ||||
|  | ||||
| replace go.opentelemetry.io/otel/exporters/otlp/internal/retry => ../../exporters/otlp/internal/retry | ||||
|  | ||||
| replace go.opentelemetry.io/otel/metric => ../../metric | ||||
|   | ||||
| @@ -12,6 +12,7 @@ require ( | ||||
| require ( | ||||
| 	github.com/go-logr/logr v1.2.3 // indirect | ||||
| 	github.com/go-logr/stdr v1.2.2 // indirect | ||||
| 	go.opentelemetry.io/otel/metric v0.37.0 // indirect | ||||
| 	golang.org/x/sys v0.5.0 // indirect | ||||
| ) | ||||
|  | ||||
| @@ -22,3 +23,5 @@ replace ( | ||||
| ) | ||||
|  | ||||
| replace go.opentelemetry.io/otel/exporters/stdout/stdouttrace => ../../exporters/stdout/stdouttrace | ||||
|  | ||||
| replace go.opentelemetry.io/otel/metric => ../../metric | ||||
|   | ||||
| @@ -19,7 +19,10 @@ require ( | ||||
| 	github.com/go-logr/logr v1.2.3 // indirect | ||||
| 	github.com/go-logr/stdr v1.2.2 // indirect | ||||
| 	github.com/openzipkin/zipkin-go v0.4.1 // indirect | ||||
| 	go.opentelemetry.io/otel/metric v0.37.0 // indirect | ||||
| 	golang.org/x/sys v0.5.0 // indirect | ||||
| ) | ||||
|  | ||||
| replace go.opentelemetry.io/otel/trace => ../../trace | ||||
|  | ||||
| replace go.opentelemetry.io/otel/metric => ../../metric | ||||
|   | ||||
| @@ -16,6 +16,7 @@ require ( | ||||
| 	github.com/davecgh/go-spew v1.1.1 // indirect | ||||
| 	github.com/pmezard/go-difflib v1.0.0 // indirect | ||||
| 	github.com/stretchr/objx v0.5.0 // indirect | ||||
| 	go.opentelemetry.io/otel/metric v0.37.0 // indirect | ||||
| 	golang.org/x/sys v0.5.0 // indirect | ||||
| 	gopkg.in/yaml.v3 v3.0.1 // indirect | ||||
| ) | ||||
| @@ -25,3 +26,5 @@ replace go.opentelemetry.io/otel/trace => ../../trace | ||||
| replace go.opentelemetry.io/otel => ../.. | ||||
|  | ||||
| replace go.opentelemetry.io/otel/sdk => ../../sdk | ||||
|  | ||||
| replace go.opentelemetry.io/otel/metric => ../../metric | ||||
|   | ||||
| @@ -17,8 +17,8 @@ package otlpmetricgrpc_test | ||||
| import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel" | ||||
| 	"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" | ||||
| 	"go.opentelemetry.io/otel/metric/global" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric" | ||||
| ) | ||||
|  | ||||
| @@ -35,7 +35,7 @@ func Example() { | ||||
| 			panic(err) | ||||
| 		} | ||||
| 	}() | ||||
| 	global.SetMeterProvider(meterProvider) | ||||
| 	otel.SetMeterProvider(meterProvider) | ||||
|  | ||||
| 	// From here, the meterProvider can be used by instrumentation to collect | ||||
| 	// telemetry. | ||||
|   | ||||
| @@ -9,7 +9,6 @@ require ( | ||||
| 	go.opentelemetry.io/otel v1.14.0 | ||||
| 	go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 | ||||
| 	go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.37.0 | ||||
| 	go.opentelemetry.io/otel/metric v0.37.0 | ||||
| 	go.opentelemetry.io/otel/sdk/metric v0.37.0 | ||||
| 	go.opentelemetry.io/proto/otlp v0.19.0 | ||||
| 	google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f | ||||
| @@ -26,6 +25,7 @@ require ( | ||||
| 	github.com/google/go-cmp v0.5.9 // indirect | ||||
| 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect | ||||
| 	github.com/pmezard/go-difflib v1.0.0 // indirect | ||||
| 	go.opentelemetry.io/otel/metric v0.37.0 // indirect | ||||
| 	go.opentelemetry.io/otel/sdk v1.14.0 // indirect | ||||
| 	go.opentelemetry.io/otel/trace v1.14.0 // indirect | ||||
| 	golang.org/x/net v0.7.0 // indirect | ||||
|   | ||||
| @@ -17,8 +17,8 @@ package otlpmetrichttp_test | ||||
| import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel" | ||||
| 	"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp" | ||||
| 	"go.opentelemetry.io/otel/metric/global" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric" | ||||
| ) | ||||
|  | ||||
| @@ -35,7 +35,7 @@ func Example() { | ||||
| 			panic(err) | ||||
| 		} | ||||
| 	}() | ||||
| 	global.SetMeterProvider(meterProvider) | ||||
| 	otel.SetMeterProvider(meterProvider) | ||||
|  | ||||
| 	// From here, the meterProvider can be used by instrumentation to collect | ||||
| 	// telemetry. | ||||
|   | ||||
| @@ -9,7 +9,6 @@ require ( | ||||
| 	go.opentelemetry.io/otel v1.14.0 | ||||
| 	go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 | ||||
| 	go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.37.0 | ||||
| 	go.opentelemetry.io/otel/metric v0.37.0 | ||||
| 	go.opentelemetry.io/otel/sdk/metric v0.37.0 | ||||
| 	go.opentelemetry.io/proto/otlp v0.19.0 | ||||
| 	google.golang.org/protobuf v1.28.1 | ||||
| @@ -24,6 +23,7 @@ require ( | ||||
| 	github.com/google/go-cmp v0.5.9 // indirect | ||||
| 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect | ||||
| 	github.com/pmezard/go-difflib v1.0.0 // indirect | ||||
| 	go.opentelemetry.io/otel/metric v0.37.0 // indirect | ||||
| 	go.opentelemetry.io/otel/sdk v1.14.0 // indirect | ||||
| 	go.opentelemetry.io/otel/trace v1.14.0 // indirect | ||||
| 	golang.org/x/net v0.7.0 // indirect | ||||
|   | ||||
| @@ -22,6 +22,7 @@ require ( | ||||
| 	github.com/golang/protobuf v1.5.2 // indirect | ||||
| 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect | ||||
| 	github.com/pmezard/go-difflib v1.0.0 // indirect | ||||
| 	go.opentelemetry.io/otel/metric v0.37.0 // indirect | ||||
| 	golang.org/x/net v0.7.0 // indirect | ||||
| 	golang.org/x/sys v0.5.0 // indirect | ||||
| 	golang.org/x/text v0.7.0 // indirect | ||||
| @@ -36,3 +37,5 @@ replace go.opentelemetry.io/otel/sdk => ../../../sdk | ||||
| replace go.opentelemetry.io/otel/trace => ../../../trace | ||||
|  | ||||
| replace go.opentelemetry.io/otel/exporters/otlp/internal/retry => ../internal/retry | ||||
|  | ||||
| replace go.opentelemetry.io/otel/metric => ../../../metric | ||||
|   | ||||
| @@ -23,6 +23,7 @@ require ( | ||||
| 	github.com/golang/protobuf v1.5.2 // indirect | ||||
| 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect | ||||
| 	github.com/pmezard/go-difflib v1.0.0 // indirect | ||||
| 	go.opentelemetry.io/otel/metric v0.37.0 // indirect | ||||
| 	go.opentelemetry.io/otel/trace v1.14.0 // indirect | ||||
| 	golang.org/x/net v0.7.0 // indirect | ||||
| 	golang.org/x/sys v0.5.0 // indirect | ||||
| @@ -39,3 +40,5 @@ replace go.opentelemetry.io/otel/exporters/otlp/otlptrace => ../ | ||||
| replace go.opentelemetry.io/otel/trace => ../../../../trace | ||||
|  | ||||
| replace go.opentelemetry.io/otel/exporters/otlp/internal/retry => ../../internal/retry | ||||
|  | ||||
| replace go.opentelemetry.io/otel/metric => ../../../../metric | ||||
|   | ||||
| @@ -21,6 +21,7 @@ require ( | ||||
| 	github.com/golang/protobuf v1.5.2 // indirect | ||||
| 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect | ||||
| 	github.com/pmezard/go-difflib v1.0.0 // indirect | ||||
| 	go.opentelemetry.io/otel/metric v0.37.0 // indirect | ||||
| 	golang.org/x/net v0.7.0 // indirect | ||||
| 	golang.org/x/sys v0.5.0 // indirect | ||||
| 	golang.org/x/text v0.7.0 // indirect | ||||
| @@ -38,3 +39,5 @@ replace go.opentelemetry.io/otel/sdk => ../../../../sdk | ||||
| replace go.opentelemetry.io/otel/trace => ../../../../trace | ||||
|  | ||||
| replace go.opentelemetry.io/otel/exporters/otlp/internal/retry => ../../internal/retry | ||||
|  | ||||
| replace go.opentelemetry.io/otel/metric => ../../../../metric | ||||
|   | ||||
| @@ -19,8 +19,11 @@ require ( | ||||
| 	github.com/go-logr/logr v1.2.3 // indirect | ||||
| 	github.com/go-logr/stdr v1.2.2 // indirect | ||||
| 	github.com/pmezard/go-difflib v1.0.0 // indirect | ||||
| 	go.opentelemetry.io/otel/metric v0.37.0 // indirect | ||||
| 	golang.org/x/sys v0.5.0 // indirect | ||||
| 	gopkg.in/yaml.v3 v3.0.1 // indirect | ||||
| ) | ||||
|  | ||||
| replace go.opentelemetry.io/otel/trace => ../../../trace | ||||
|  | ||||
| replace go.opentelemetry.io/otel/metric => ../../../metric | ||||
|   | ||||
| @@ -16,6 +16,7 @@ require ( | ||||
| require ( | ||||
| 	github.com/davecgh/go-spew v1.1.1 // indirect | ||||
| 	github.com/pmezard/go-difflib v1.0.0 // indirect | ||||
| 	go.opentelemetry.io/otel/metric v0.37.0 // indirect | ||||
| 	golang.org/x/sys v0.5.0 // indirect | ||||
| 	gopkg.in/yaml.v3 v3.0.1 // indirect | ||||
| ) | ||||
| @@ -25,3 +26,5 @@ replace go.opentelemetry.io/otel/trace => ../../trace | ||||
| replace go.opentelemetry.io/otel => ../.. | ||||
|  | ||||
| replace go.opentelemetry.io/otel/sdk => ../../sdk | ||||
|  | ||||
| replace go.opentelemetry.io/otel/metric => ../../metric | ||||
|   | ||||
							
								
								
									
										3
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								go.mod
									
									
									
									
									
								
							| @@ -7,6 +7,7 @@ require ( | ||||
| 	github.com/go-logr/stdr v1.2.2 | ||||
| 	github.com/google/go-cmp v0.5.9 | ||||
| 	github.com/stretchr/testify v1.8.2 | ||||
| 	go.opentelemetry.io/otel/metric v0.37.0 | ||||
| 	go.opentelemetry.io/otel/trace v1.14.0 | ||||
| ) | ||||
|  | ||||
| @@ -17,3 +18,5 @@ require ( | ||||
| ) | ||||
|  | ||||
| replace go.opentelemetry.io/otel/trace => ./trace | ||||
|  | ||||
| replace go.opentelemetry.io/otel/metric => ./metric | ||||
|   | ||||
							
								
								
									
										64
									
								
								handler.go
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								handler.go
									
									
									
									
									
								
							| @@ -15,58 +15,16 @@ | ||||
| package otel // import "go.opentelemetry.io/otel" | ||||
|  | ||||
| import ( | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"sync/atomic" | ||||
| 	"unsafe" | ||||
| 	"go.opentelemetry.io/otel/internal/global" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	// globalErrorHandler provides an ErrorHandler that can be used | ||||
| 	// throughout an OpenTelemetry instrumented project. When a user | ||||
| 	// specified ErrorHandler is registered (`SetErrorHandler`) all calls to | ||||
| 	// `Handle` and will be delegated to the registered ErrorHandler. | ||||
| 	globalErrorHandler = defaultErrorHandler() | ||||
|  | ||||
| 	// Compile-time check that delegator implements ErrorHandler. | ||||
| 	_ ErrorHandler = (*delegator)(nil) | ||||
| 	// Compile-time check that errLogger implements ErrorHandler. | ||||
| 	_ ErrorHandler = (*errLogger)(nil) | ||||
| 	// Compile-time check global.ErrDelegator implements ErrorHandler. | ||||
| 	_ ErrorHandler = (*global.ErrDelegator)(nil) | ||||
| 	// Compile-time check global.ErrLogger implements ErrorHandler. | ||||
| 	_ ErrorHandler = (*global.ErrLogger)(nil) | ||||
| ) | ||||
|  | ||||
| type delegator struct { | ||||
| 	delegate unsafe.Pointer | ||||
| } | ||||
|  | ||||
| func (d *delegator) Handle(err error) { | ||||
| 	d.getDelegate().Handle(err) | ||||
| } | ||||
|  | ||||
| func (d *delegator) getDelegate() ErrorHandler { | ||||
| 	return *(*ErrorHandler)(atomic.LoadPointer(&d.delegate)) | ||||
| } | ||||
|  | ||||
| // setDelegate sets the ErrorHandler delegate. | ||||
| func (d *delegator) setDelegate(eh ErrorHandler) { | ||||
| 	atomic.StorePointer(&d.delegate, unsafe.Pointer(&eh)) | ||||
| } | ||||
|  | ||||
| func defaultErrorHandler() *delegator { | ||||
| 	d := &delegator{} | ||||
| 	d.setDelegate(&errLogger{l: log.New(os.Stderr, "", log.LstdFlags)}) | ||||
| 	return d | ||||
| } | ||||
|  | ||||
| // errLogger logs errors if no delegate is set, otherwise they are delegated. | ||||
| type errLogger struct { | ||||
| 	l *log.Logger | ||||
| } | ||||
|  | ||||
| // Handle logs err if no delegate is set, otherwise it is delegated. | ||||
| func (h *errLogger) Handle(err error) { | ||||
| 	h.l.Print(err) | ||||
| } | ||||
|  | ||||
| // GetErrorHandler returns the global ErrorHandler instance. | ||||
| // | ||||
| // The default ErrorHandler instance returned will log all errors to STDERR | ||||
| @@ -76,9 +34,7 @@ func (h *errLogger) Handle(err error) { | ||||
| // | ||||
| // Subsequent calls to SetErrorHandler after the first will not forward errors | ||||
| // to the new ErrorHandler for prior returned instances. | ||||
| func GetErrorHandler() ErrorHandler { | ||||
| 	return globalErrorHandler | ||||
| } | ||||
| func GetErrorHandler() ErrorHandler { return global.GetErrorHandler() } | ||||
|  | ||||
| // SetErrorHandler sets the global ErrorHandler to h. | ||||
| // | ||||
| @@ -86,11 +42,7 @@ func GetErrorHandler() ErrorHandler { | ||||
| // GetErrorHandler will send errors to h instead of the default logging | ||||
| // ErrorHandler. Subsequent calls will set the global ErrorHandler, but not | ||||
| // delegate errors to h. | ||||
| func SetErrorHandler(h ErrorHandler) { | ||||
| 	globalErrorHandler.setDelegate(h) | ||||
| } | ||||
| func SetErrorHandler(h ErrorHandler) { global.SetErrorHandler(h) } | ||||
|  | ||||
| // Handle is a convenience function for ErrorHandler().Handle(err). | ||||
| func Handle(err error) { | ||||
| 	GetErrorHandler().Handle(err) | ||||
| } | ||||
| func Handle(err error) { global.Handle(err) } | ||||
|   | ||||
							
								
								
									
										220
									
								
								handler_test.go
									
									
									
									
									
								
							
							
						
						
									
										220
									
								
								handler_test.go
									
									
									
									
									
								
							| @@ -15,212 +15,28 @@ | ||||
| package otel | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/suite" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| type testErrCatcher []string | ||||
|  | ||||
| func (l *testErrCatcher) Write(p []byte) (int, error) { | ||||
| 	msg := bytes.TrimRight(p, "\n") | ||||
| 	(*l) = append(*l, string(msg)) | ||||
| 	return len(msg), nil | ||||
| type testErrHandler struct { | ||||
| 	err error | ||||
| } | ||||
|  | ||||
| func (l *testErrCatcher) Reset() { | ||||
| 	*l = testErrCatcher([]string{}) | ||||
| } | ||||
|  | ||||
| func (l *testErrCatcher) Got() []string { | ||||
| 	return []string(*l) | ||||
| } | ||||
|  | ||||
| func causeErr(text string) { | ||||
| 	Handle(errors.New(text)) | ||||
| } | ||||
|  | ||||
| type HandlerTestSuite struct { | ||||
| 	suite.Suite | ||||
|  | ||||
| 	origHandler ErrorHandler | ||||
| 	errCatcher  *testErrCatcher | ||||
| } | ||||
|  | ||||
| func (s *HandlerTestSuite) SetupSuite() { | ||||
| 	s.errCatcher = new(testErrCatcher) | ||||
| 	s.origHandler = globalErrorHandler.getDelegate() | ||||
|  | ||||
| 	globalErrorHandler.setDelegate(&errLogger{l: log.New(s.errCatcher, "", 0)}) | ||||
| } | ||||
|  | ||||
| func (s *HandlerTestSuite) TearDownSuite() { | ||||
| 	globalErrorHandler.setDelegate(s.origHandler) | ||||
| } | ||||
|  | ||||
| func (s *HandlerTestSuite) SetupTest() { | ||||
| 	s.errCatcher.Reset() | ||||
| } | ||||
|  | ||||
| func (s *HandlerTestSuite) TearDownTest() { | ||||
| 	globalErrorHandler.setDelegate(&errLogger{l: log.New(s.errCatcher, "", 0)}) | ||||
| } | ||||
|  | ||||
| func (s *HandlerTestSuite) TestGlobalHandler() { | ||||
| 	errs := []string{"one", "two"} | ||||
| 	GetErrorHandler().Handle(errors.New(errs[0])) | ||||
| 	Handle(errors.New(errs[1])) | ||||
| 	s.Assert().Equal(errs, s.errCatcher.Got()) | ||||
| } | ||||
|  | ||||
| func (s *HandlerTestSuite) TestDelegatedHandler() { | ||||
| 	eh := GetErrorHandler() | ||||
|  | ||||
| 	newErrLogger := new(testErrCatcher) | ||||
| 	SetErrorHandler(&errLogger{l: log.New(newErrLogger, "", 0)}) | ||||
|  | ||||
| 	errs := []string{"TestDelegatedHandler"} | ||||
| 	eh.Handle(errors.New(errs[0])) | ||||
| 	s.Assert().Equal(errs, newErrLogger.Got()) | ||||
| } | ||||
|  | ||||
| func (s *HandlerTestSuite) TestNoDropsOnDelegate() { | ||||
| 	causeErr("") | ||||
| 	s.Require().Len(s.errCatcher.Got(), 1) | ||||
|  | ||||
| 	// Change to another Handler. We are testing this is loss-less. | ||||
| 	newErrLogger := new(testErrCatcher) | ||||
| 	secondary := &errLogger{ | ||||
| 		l: log.New(newErrLogger, "", 0), | ||||
| 	} | ||||
| 	SetErrorHandler(secondary) | ||||
|  | ||||
| 	causeErr("") | ||||
| 	s.Assert().Len(s.errCatcher.Got(), 1, "original Handler used after delegation") | ||||
| 	s.Assert().Len(newErrLogger.Got(), 1, "new Handler not used after delegation") | ||||
| } | ||||
|  | ||||
| func (s *HandlerTestSuite) TestAllowMultipleSets() { | ||||
| 	notUsed := new(testErrCatcher) | ||||
|  | ||||
| 	secondary := &errLogger{l: log.New(notUsed, "", 0)} | ||||
| 	SetErrorHandler(secondary) | ||||
| 	s.Require().Same(GetErrorHandler(), globalErrorHandler, "set changed globalErrorHandler") | ||||
| 	s.Require().Same(globalErrorHandler.getDelegate(), secondary, "new Handler not set") | ||||
|  | ||||
| 	tertiary := &errLogger{l: log.New(notUsed, "", 0)} | ||||
| 	SetErrorHandler(tertiary) | ||||
| 	s.Require().Same(GetErrorHandler(), globalErrorHandler, "set changed globalErrorHandler") | ||||
| 	s.Assert().Same(globalErrorHandler.getDelegate(), tertiary, "user Handler not overridden") | ||||
| } | ||||
|  | ||||
| func TestHandlerTestSuite(t *testing.T) { | ||||
| 	suite.Run(t, new(HandlerTestSuite)) | ||||
| } | ||||
|  | ||||
| func TestHandlerRace(t *testing.T) { | ||||
| 	go SetErrorHandler(&errLogger{log.New(os.Stderr, "", 0)}) | ||||
| 	go Handle(errors.New("error")) | ||||
| } | ||||
|  | ||||
| func BenchmarkErrorHandler(b *testing.B) { | ||||
| 	primary := &errLogger{l: log.New(io.Discard, "", 0)} | ||||
| 	secondary := &errLogger{l: log.New(io.Discard, "", 0)} | ||||
| 	tertiary := &errLogger{l: log.New(io.Discard, "", 0)} | ||||
|  | ||||
| 	globalErrorHandler.setDelegate(primary) | ||||
|  | ||||
| 	err := errors.New("benchmark error handler") | ||||
|  | ||||
| 	b.ReportAllocs() | ||||
| 	b.ResetTimer() | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		GetErrorHandler().Handle(err) | ||||
| 		Handle(err) | ||||
|  | ||||
| 		SetErrorHandler(secondary) | ||||
| 		GetErrorHandler().Handle(err) | ||||
| 		Handle(err) | ||||
|  | ||||
| 		SetErrorHandler(tertiary) | ||||
| 		GetErrorHandler().Handle(err) | ||||
| 		Handle(err) | ||||
|  | ||||
| 		globalErrorHandler.setDelegate(primary) | ||||
| 	} | ||||
|  | ||||
| 	reset() | ||||
| } | ||||
|  | ||||
| var eh ErrorHandler | ||||
|  | ||||
| func BenchmarkGetDefaultErrorHandler(b *testing.B) { | ||||
| 	b.ReportAllocs() | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		eh = GetErrorHandler() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func BenchmarkGetDelegatedErrorHandler(b *testing.B) { | ||||
| 	SetErrorHandler(&errLogger{l: log.New(io.Discard, "", 0)}) | ||||
|  | ||||
| 	b.ReportAllocs() | ||||
| 	b.ResetTimer() | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		eh = GetErrorHandler() | ||||
| 	} | ||||
|  | ||||
| 	reset() | ||||
| } | ||||
|  | ||||
| func BenchmarkDefaultErrorHandlerHandle(b *testing.B) { | ||||
| 	globalErrorHandler.setDelegate( | ||||
| 		&errLogger{l: log.New(io.Discard, "", 0)}, | ||||
| 	) | ||||
|  | ||||
| 	eh := GetErrorHandler() | ||||
| 	err := errors.New("benchmark default error handler handle") | ||||
|  | ||||
| 	b.ReportAllocs() | ||||
| 	b.ResetTimer() | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		eh.Handle(err) | ||||
| 	} | ||||
|  | ||||
| 	reset() | ||||
| } | ||||
|  | ||||
| func BenchmarkDelegatedErrorHandlerHandle(b *testing.B) { | ||||
| 	eh := GetErrorHandler() | ||||
| 	SetErrorHandler(&errLogger{l: log.New(io.Discard, "", 0)}) | ||||
| 	err := errors.New("benchmark delegated error handler handle") | ||||
|  | ||||
| 	b.ReportAllocs() | ||||
| 	b.ResetTimer() | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		eh.Handle(err) | ||||
| 	} | ||||
|  | ||||
| 	reset() | ||||
| } | ||||
|  | ||||
| func BenchmarkSetErrorHandlerDelegation(b *testing.B) { | ||||
| 	alt := &errLogger{l: log.New(io.Discard, "", 0)} | ||||
|  | ||||
| 	b.ReportAllocs() | ||||
| 	b.ResetTimer() | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		SetErrorHandler(alt) | ||||
|  | ||||
| 		reset() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func reset() { | ||||
| 	globalErrorHandler = defaultErrorHandler() | ||||
| var _ ErrorHandler = &testErrHandler{} | ||||
|  | ||||
| func (eh *testErrHandler) Handle(err error) { eh.err = err } | ||||
|  | ||||
| func TestGlobalErrorHandler(t *testing.T) { | ||||
| 	e1 := &testErrHandler{} | ||||
| 	SetErrorHandler(e1) | ||||
| 	Handle(assert.AnError) | ||||
| 	assert.ErrorIs(t, e1.err, assert.AnError) | ||||
| 	e1.err = nil | ||||
|  | ||||
| 	e2 := &testErrHandler{} | ||||
| 	SetErrorHandler(e2) | ||||
| 	GetErrorHandler().Handle(assert.AnError) | ||||
| 	assert.ErrorIs(t, e2.err, assert.AnError) | ||||
| } | ||||
|   | ||||
							
								
								
									
										103
									
								
								internal/global/handler.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								internal/global/handler.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | ||||
| // 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/global" | ||||
|  | ||||
| import ( | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"sync/atomic" | ||||
| 	"unsafe" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	// GlobalErrorHandler provides an ErrorHandler that can be used | ||||
| 	// throughout an OpenTelemetry instrumented project. When a user | ||||
| 	// specified ErrorHandler is registered (`SetErrorHandler`) all calls to | ||||
| 	// `Handle` and will be delegated to the registered ErrorHandler. | ||||
| 	GlobalErrorHandler = defaultErrorHandler() | ||||
|  | ||||
| 	// Compile-time check that delegator implements ErrorHandler. | ||||
| 	_ ErrorHandler = (*ErrDelegator)(nil) | ||||
| 	// Compile-time check that errLogger implements ErrorHandler. | ||||
| 	_ ErrorHandler = (*ErrLogger)(nil) | ||||
| ) | ||||
|  | ||||
| // ErrorHandler handles irremediable events. | ||||
| type ErrorHandler interface { | ||||
| 	// Handle handles any error deemed irremediable by an OpenTelemetry | ||||
| 	// component. | ||||
| 	Handle(error) | ||||
| } | ||||
|  | ||||
| type ErrDelegator struct { | ||||
| 	delegate unsafe.Pointer | ||||
| } | ||||
|  | ||||
| func (d *ErrDelegator) Handle(err error) { | ||||
| 	d.getDelegate().Handle(err) | ||||
| } | ||||
|  | ||||
| func (d *ErrDelegator) getDelegate() ErrorHandler { | ||||
| 	return *(*ErrorHandler)(atomic.LoadPointer(&d.delegate)) | ||||
| } | ||||
|  | ||||
| // setDelegate sets the ErrorHandler delegate. | ||||
| func (d *ErrDelegator) setDelegate(eh ErrorHandler) { | ||||
| 	atomic.StorePointer(&d.delegate, unsafe.Pointer(&eh)) | ||||
| } | ||||
|  | ||||
| func defaultErrorHandler() *ErrDelegator { | ||||
| 	d := &ErrDelegator{} | ||||
| 	d.setDelegate(&ErrLogger{l: log.New(os.Stderr, "", log.LstdFlags)}) | ||||
| 	return d | ||||
| } | ||||
|  | ||||
| // ErrLogger logs errors if no delegate is set, otherwise they are delegated. | ||||
| type ErrLogger struct { | ||||
| 	l *log.Logger | ||||
| } | ||||
|  | ||||
| // Handle logs err if no delegate is set, otherwise it is delegated. | ||||
| func (h *ErrLogger) Handle(err error) { | ||||
| 	h.l.Print(err) | ||||
| } | ||||
|  | ||||
| // GetErrorHandler returns the global ErrorHandler instance. | ||||
| // | ||||
| // The default ErrorHandler instance returned will log all errors to STDERR | ||||
| // until an override ErrorHandler is set with SetErrorHandler. All | ||||
| // ErrorHandler returned prior to this will automatically forward errors to | ||||
| // the set instance instead of logging. | ||||
| // | ||||
| // Subsequent calls to SetErrorHandler after the first will not forward errors | ||||
| // to the new ErrorHandler for prior returned instances. | ||||
| func GetErrorHandler() ErrorHandler { | ||||
| 	return GlobalErrorHandler | ||||
| } | ||||
|  | ||||
| // SetErrorHandler sets the global ErrorHandler to h. | ||||
| // | ||||
| // The first time this is called all ErrorHandler previously returned from | ||||
| // GetErrorHandler will send errors to h instead of the default logging | ||||
| // ErrorHandler. Subsequent calls will set the global ErrorHandler, but not | ||||
| // delegate errors to h. | ||||
| func SetErrorHandler(h ErrorHandler) { | ||||
| 	GlobalErrorHandler.setDelegate(h) | ||||
| } | ||||
|  | ||||
| // Handle is a convenience function for ErrorHandler().Handle(err). | ||||
| func Handle(err error) { | ||||
| 	GetErrorHandler().Handle(err) | ||||
| } | ||||
							
								
								
									
										226
									
								
								internal/global/handler_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								internal/global/handler_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,226 @@ | ||||
| // 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 ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/suite" | ||||
| ) | ||||
|  | ||||
| type testErrCatcher []string | ||||
|  | ||||
| func (l *testErrCatcher) Write(p []byte) (int, error) { | ||||
| 	msg := bytes.TrimRight(p, "\n") | ||||
| 	(*l) = append(*l, string(msg)) | ||||
| 	return len(msg), nil | ||||
| } | ||||
|  | ||||
| func (l *testErrCatcher) Reset() { | ||||
| 	*l = testErrCatcher([]string{}) | ||||
| } | ||||
|  | ||||
| func (l *testErrCatcher) Got() []string { | ||||
| 	return []string(*l) | ||||
| } | ||||
|  | ||||
| func causeErr(text string) { | ||||
| 	Handle(errors.New(text)) | ||||
| } | ||||
|  | ||||
| type HandlerTestSuite struct { | ||||
| 	suite.Suite | ||||
|  | ||||
| 	origHandler ErrorHandler | ||||
| 	errCatcher  *testErrCatcher | ||||
| } | ||||
|  | ||||
| func (s *HandlerTestSuite) SetupSuite() { | ||||
| 	s.errCatcher = new(testErrCatcher) | ||||
| 	s.origHandler = GlobalErrorHandler.getDelegate() | ||||
|  | ||||
| 	GlobalErrorHandler.setDelegate(&ErrLogger{l: log.New(s.errCatcher, "", 0)}) | ||||
| } | ||||
|  | ||||
| func (s *HandlerTestSuite) TearDownSuite() { | ||||
| 	GlobalErrorHandler.setDelegate(s.origHandler) | ||||
| } | ||||
|  | ||||
| func (s *HandlerTestSuite) SetupTest() { | ||||
| 	s.errCatcher.Reset() | ||||
| } | ||||
|  | ||||
| func (s *HandlerTestSuite) TearDownTest() { | ||||
| 	GlobalErrorHandler.setDelegate(&ErrLogger{l: log.New(s.errCatcher, "", 0)}) | ||||
| } | ||||
|  | ||||
| func (s *HandlerTestSuite) TestGlobalHandler() { | ||||
| 	errs := []string{"one", "two"} | ||||
| 	GetErrorHandler().Handle(errors.New(errs[0])) | ||||
| 	Handle(errors.New(errs[1])) | ||||
| 	s.Assert().Equal(errs, s.errCatcher.Got()) | ||||
| } | ||||
|  | ||||
| func (s *HandlerTestSuite) TestDelegatedHandler() { | ||||
| 	eh := GetErrorHandler() | ||||
|  | ||||
| 	newErrLogger := new(testErrCatcher) | ||||
| 	SetErrorHandler(&ErrLogger{l: log.New(newErrLogger, "", 0)}) | ||||
|  | ||||
| 	errs := []string{"TestDelegatedHandler"} | ||||
| 	eh.Handle(errors.New(errs[0])) | ||||
| 	s.Assert().Equal(errs, newErrLogger.Got()) | ||||
| } | ||||
|  | ||||
| func (s *HandlerTestSuite) TestNoDropsOnDelegate() { | ||||
| 	causeErr("") | ||||
| 	s.Require().Len(s.errCatcher.Got(), 1) | ||||
|  | ||||
| 	// Change to another Handler. We are testing this is loss-less. | ||||
| 	newErrLogger := new(testErrCatcher) | ||||
| 	secondary := &ErrLogger{ | ||||
| 		l: log.New(newErrLogger, "", 0), | ||||
| 	} | ||||
| 	SetErrorHandler(secondary) | ||||
|  | ||||
| 	causeErr("") | ||||
| 	s.Assert().Len(s.errCatcher.Got(), 1, "original Handler used after delegation") | ||||
| 	s.Assert().Len(newErrLogger.Got(), 1, "new Handler not used after delegation") | ||||
| } | ||||
|  | ||||
| func (s *HandlerTestSuite) TestAllowMultipleSets() { | ||||
| 	notUsed := new(testErrCatcher) | ||||
|  | ||||
| 	secondary := &ErrLogger{l: log.New(notUsed, "", 0)} | ||||
| 	SetErrorHandler(secondary) | ||||
| 	s.Require().Same(GetErrorHandler(), GlobalErrorHandler, "set changed globalErrorHandler") | ||||
| 	s.Require().Same(GlobalErrorHandler.getDelegate(), secondary, "new Handler not set") | ||||
|  | ||||
| 	tertiary := &ErrLogger{l: log.New(notUsed, "", 0)} | ||||
| 	SetErrorHandler(tertiary) | ||||
| 	s.Require().Same(GetErrorHandler(), GlobalErrorHandler, "set changed globalErrorHandler") | ||||
| 	s.Assert().Same(GlobalErrorHandler.getDelegate(), tertiary, "user Handler not overridden") | ||||
| } | ||||
|  | ||||
| func TestHandlerTestSuite(t *testing.T) { | ||||
| 	suite.Run(t, new(HandlerTestSuite)) | ||||
| } | ||||
|  | ||||
| func TestHandlerRace(t *testing.T) { | ||||
| 	go SetErrorHandler(&ErrLogger{log.New(os.Stderr, "", 0)}) | ||||
| 	go Handle(errors.New("error")) | ||||
| } | ||||
|  | ||||
| func BenchmarkErrorHandler(b *testing.B) { | ||||
| 	primary := &ErrLogger{l: log.New(io.Discard, "", 0)} | ||||
| 	secondary := &ErrLogger{l: log.New(io.Discard, "", 0)} | ||||
| 	tertiary := &ErrLogger{l: log.New(io.Discard, "", 0)} | ||||
|  | ||||
| 	GlobalErrorHandler.setDelegate(primary) | ||||
|  | ||||
| 	err := errors.New("benchmark error handler") | ||||
|  | ||||
| 	b.ReportAllocs() | ||||
| 	b.ResetTimer() | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		GetErrorHandler().Handle(err) | ||||
| 		Handle(err) | ||||
|  | ||||
| 		SetErrorHandler(secondary) | ||||
| 		GetErrorHandler().Handle(err) | ||||
| 		Handle(err) | ||||
|  | ||||
| 		SetErrorHandler(tertiary) | ||||
| 		GetErrorHandler().Handle(err) | ||||
| 		Handle(err) | ||||
|  | ||||
| 		GlobalErrorHandler.setDelegate(primary) | ||||
| 	} | ||||
|  | ||||
| 	reset() | ||||
| } | ||||
|  | ||||
| var eh ErrorHandler | ||||
|  | ||||
| func BenchmarkGetDefaultErrorHandler(b *testing.B) { | ||||
| 	b.ReportAllocs() | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		eh = GetErrorHandler() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func BenchmarkGetDelegatedErrorHandler(b *testing.B) { | ||||
| 	SetErrorHandler(&ErrLogger{l: log.New(io.Discard, "", 0)}) | ||||
|  | ||||
| 	b.ReportAllocs() | ||||
| 	b.ResetTimer() | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		eh = GetErrorHandler() | ||||
| 	} | ||||
|  | ||||
| 	reset() | ||||
| } | ||||
|  | ||||
| func BenchmarkDefaultErrorHandlerHandle(b *testing.B) { | ||||
| 	GlobalErrorHandler.setDelegate( | ||||
| 		&ErrLogger{l: log.New(io.Discard, "", 0)}, | ||||
| 	) | ||||
|  | ||||
| 	eh := GetErrorHandler() | ||||
| 	err := errors.New("benchmark default error handler handle") | ||||
|  | ||||
| 	b.ReportAllocs() | ||||
| 	b.ResetTimer() | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		eh.Handle(err) | ||||
| 	} | ||||
|  | ||||
| 	reset() | ||||
| } | ||||
|  | ||||
| func BenchmarkDelegatedErrorHandlerHandle(b *testing.B) { | ||||
| 	eh := GetErrorHandler() | ||||
| 	SetErrorHandler(&ErrLogger{l: log.New(io.Discard, "", 0)}) | ||||
| 	err := errors.New("benchmark delegated error handler handle") | ||||
|  | ||||
| 	b.ReportAllocs() | ||||
| 	b.ResetTimer() | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		eh.Handle(err) | ||||
| 	} | ||||
|  | ||||
| 	reset() | ||||
| } | ||||
|  | ||||
| func BenchmarkSetErrorHandlerDelegation(b *testing.B) { | ||||
| 	alt := &ErrLogger{l: log.New(io.Discard, "", 0)} | ||||
|  | ||||
| 	b.ReportAllocs() | ||||
| 	b.ResetTimer() | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		SetErrorHandler(alt) | ||||
|  | ||||
| 		reset() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func reset() { | ||||
| 	GlobalErrorHandler = defaultErrorHandler() | ||||
| } | ||||
							
								
								
									
										61
									
								
								metric.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								metric.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| // 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 otel // import "go.opentelemetry.io/otel" | ||||
|  | ||||
| import ( | ||||
| 	"go.opentelemetry.io/otel/metric" | ||||
| 	// TODO (#3819): Remove this disablement. | ||||
| 	// nolint: staticcheck  // Temporary, while metric/global is deprecated. | ||||
| 	"go.opentelemetry.io/otel/metric/global" | ||||
| ) | ||||
|  | ||||
| // Meter returns a Meter from the global MeterProvider. The name 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 name is empty, then a implementation defined default name will be | ||||
| // used instead. | ||||
| // | ||||
| // If this is called before a global MeterProvider is registered the returned | ||||
| // Meter will be a No-op implementation of a Meter. When a global MeterProvider | ||||
| // is registered for the first time, the returned Meter, and all the | ||||
| // instruments it has created or will create, are recreated automatically from | ||||
| // the new MeterProvider. | ||||
| // | ||||
| // This is short for GetMeterProvider().Meter(name). | ||||
| func Meter(name string, opts ...metric.MeterOption) metric.Meter { | ||||
| 	// TODO (#3819): Remove this disablement. | ||||
| 	// nolint: staticcheck  // Temporary, while metric/global is deprecated. | ||||
| 	return GetMeterProvider().Meter(name, opts...) | ||||
| } | ||||
|  | ||||
| // GetMeterProvider returns the registered global meter provider. | ||||
| // | ||||
| // If no global GetMeterProvider has been registered, a No-op GetMeterProvider | ||||
| // implementation is returned. When a global GetMeterProvider is registered for | ||||
| // the first time, the returned GetMeterProvider, and all the Meters it has | ||||
| // created or will create, are recreated automatically from the new | ||||
| // GetMeterProvider. | ||||
| func GetMeterProvider() metric.MeterProvider { | ||||
| 	// TODO (#3819): Remove this disablement. | ||||
| 	// nolint: staticcheck  // Temporary, while metric/global is deprecated. | ||||
| 	return global.MeterProvider() | ||||
| } | ||||
|  | ||||
| // SetMeterProvider registers mp as the global MeterProvider. | ||||
| func SetMeterProvider(mp metric.MeterProvider) { | ||||
| 	// TODO (#3819): Remove this disablement. | ||||
| 	// nolint: staticcheck  // Temporary, while metric/global is deprecated. | ||||
| 	global.SetMeterProvider(mp) | ||||
| } | ||||
| @@ -12,6 +12,9 @@ | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| // Package global provides a global MeterProvider for OpenTelemetry. | ||||
| // | ||||
| // Deprecated: Use go.opentelemetry.io/otel instead. | ||||
| package global // import "go.opentelemetry.io/otel/metric/global" | ||||
|  | ||||
| import ( | ||||
| @@ -26,17 +29,23 @@ import ( | ||||
| // empty, then a implementation defined default name will be used instead. | ||||
| // | ||||
| // This is short for MeterProvider().Meter(name). | ||||
| // | ||||
| // Deprecated: Use Meter from go.opentelemetry.io/otel instead. | ||||
| func Meter(instrumentationName string, opts ...metric.MeterOption) metric.Meter { | ||||
| 	return MeterProvider().Meter(instrumentationName, opts...) | ||||
| } | ||||
|  | ||||
| // MeterProvider returns the registered global meter provider. | ||||
| // If none is registered then a No-op MeterProvider is returned. | ||||
| // | ||||
| // Deprecated: Use MeterProvider from go.opentelemetry.io/otel instead. | ||||
| func MeterProvider() metric.MeterProvider { | ||||
| 	return global.MeterProvider() | ||||
| } | ||||
|  | ||||
| // SetMeterProvider registers `mp` as the global meter provider. | ||||
| // | ||||
| // Deprecated: Use SetMeterProvider from go.opentelemetry.io/otel instead. | ||||
| func SetMeterProvider(mp metric.MeterProvider) { | ||||
| 	global.SetMeterProvider(mp) | ||||
| } | ||||
|   | ||||
| @@ -18,8 +18,8 @@ import ( | ||||
| 	"context" | ||||
| 	"sync/atomic" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel" | ||||
| 	"go.opentelemetry.io/otel/attribute" | ||||
| 	oGlob "go.opentelemetry.io/otel/internal/global" | ||||
| 	"go.opentelemetry.io/otel/metric" | ||||
| 	"go.opentelemetry.io/otel/metric/instrument" | ||||
| ) | ||||
| @@ -44,7 +44,7 @@ var _ instrument.Float64ObservableCounter = (*afCounter)(nil) | ||||
| func (i *afCounter) setDelegate(m metric.Meter) { | ||||
| 	ctr, err := m.Float64ObservableCounter(i.name, i.opts...) | ||||
| 	if err != nil { | ||||
| 		otel.Handle(err) | ||||
| 		oGlob.GetErrorHandler().Handle(err) | ||||
| 		return | ||||
| 	} | ||||
| 	i.delegate.Store(ctr) | ||||
| @@ -72,7 +72,7 @@ var _ instrument.Float64ObservableUpDownCounter = (*afUpDownCounter)(nil) | ||||
| func (i *afUpDownCounter) setDelegate(m metric.Meter) { | ||||
| 	ctr, err := m.Float64ObservableUpDownCounter(i.name, i.opts...) | ||||
| 	if err != nil { | ||||
| 		otel.Handle(err) | ||||
| 		oGlob.GetErrorHandler().Handle(err) | ||||
| 		return | ||||
| 	} | ||||
| 	i.delegate.Store(ctr) | ||||
| @@ -100,7 +100,7 @@ var _ instrument.Float64ObservableGauge = (*afGauge)(nil) | ||||
| func (i *afGauge) setDelegate(m metric.Meter) { | ||||
| 	ctr, err := m.Float64ObservableGauge(i.name, i.opts...) | ||||
| 	if err != nil { | ||||
| 		otel.Handle(err) | ||||
| 		oGlob.GetErrorHandler().Handle(err) | ||||
| 		return | ||||
| 	} | ||||
| 	i.delegate.Store(ctr) | ||||
| @@ -128,7 +128,7 @@ var _ instrument.Int64ObservableCounter = (*aiCounter)(nil) | ||||
| func (i *aiCounter) setDelegate(m metric.Meter) { | ||||
| 	ctr, err := m.Int64ObservableCounter(i.name, i.opts...) | ||||
| 	if err != nil { | ||||
| 		otel.Handle(err) | ||||
| 		oGlob.GetErrorHandler().Handle(err) | ||||
| 		return | ||||
| 	} | ||||
| 	i.delegate.Store(ctr) | ||||
| @@ -156,7 +156,7 @@ var _ instrument.Int64ObservableUpDownCounter = (*aiUpDownCounter)(nil) | ||||
| func (i *aiUpDownCounter) setDelegate(m metric.Meter) { | ||||
| 	ctr, err := m.Int64ObservableUpDownCounter(i.name, i.opts...) | ||||
| 	if err != nil { | ||||
| 		otel.Handle(err) | ||||
| 		oGlob.GetErrorHandler().Handle(err) | ||||
| 		return | ||||
| 	} | ||||
| 	i.delegate.Store(ctr) | ||||
| @@ -184,7 +184,7 @@ var _ instrument.Int64ObservableGauge = (*aiGauge)(nil) | ||||
| func (i *aiGauge) setDelegate(m metric.Meter) { | ||||
| 	ctr, err := m.Int64ObservableGauge(i.name, i.opts...) | ||||
| 	if err != nil { | ||||
| 		otel.Handle(err) | ||||
| 		oGlob.GetErrorHandler().Handle(err) | ||||
| 		return | ||||
| 	} | ||||
| 	i.delegate.Store(ctr) | ||||
| @@ -212,7 +212,7 @@ var _ instrument.Float64Counter = (*sfCounter)(nil) | ||||
| func (i *sfCounter) setDelegate(m metric.Meter) { | ||||
| 	ctr, err := m.Float64Counter(i.name, i.opts...) | ||||
| 	if err != nil { | ||||
| 		otel.Handle(err) | ||||
| 		oGlob.GetErrorHandler().Handle(err) | ||||
| 		return | ||||
| 	} | ||||
| 	i.delegate.Store(ctr) | ||||
| @@ -238,7 +238,7 @@ var _ instrument.Float64UpDownCounter = (*sfUpDownCounter)(nil) | ||||
| func (i *sfUpDownCounter) setDelegate(m metric.Meter) { | ||||
| 	ctr, err := m.Float64UpDownCounter(i.name, i.opts...) | ||||
| 	if err != nil { | ||||
| 		otel.Handle(err) | ||||
| 		oGlob.GetErrorHandler().Handle(err) | ||||
| 		return | ||||
| 	} | ||||
| 	i.delegate.Store(ctr) | ||||
| @@ -264,7 +264,7 @@ var _ instrument.Float64Histogram = (*sfHistogram)(nil) | ||||
| func (i *sfHistogram) setDelegate(m metric.Meter) { | ||||
| 	ctr, err := m.Float64Histogram(i.name, i.opts...) | ||||
| 	if err != nil { | ||||
| 		otel.Handle(err) | ||||
| 		oGlob.GetErrorHandler().Handle(err) | ||||
| 		return | ||||
| 	} | ||||
| 	i.delegate.Store(ctr) | ||||
| @@ -290,7 +290,7 @@ var _ instrument.Int64Counter = (*siCounter)(nil) | ||||
| func (i *siCounter) setDelegate(m metric.Meter) { | ||||
| 	ctr, err := m.Int64Counter(i.name, i.opts...) | ||||
| 	if err != nil { | ||||
| 		otel.Handle(err) | ||||
| 		oGlob.GetErrorHandler().Handle(err) | ||||
| 		return | ||||
| 	} | ||||
| 	i.delegate.Store(ctr) | ||||
| @@ -316,7 +316,7 @@ var _ instrument.Int64UpDownCounter = (*siUpDownCounter)(nil) | ||||
| func (i *siUpDownCounter) setDelegate(m metric.Meter) { | ||||
| 	ctr, err := m.Int64UpDownCounter(i.name, i.opts...) | ||||
| 	if err != nil { | ||||
| 		otel.Handle(err) | ||||
| 		oGlob.GetErrorHandler().Handle(err) | ||||
| 		return | ||||
| 	} | ||||
| 	i.delegate.Store(ctr) | ||||
| @@ -342,7 +342,7 @@ var _ instrument.Int64Histogram = (*siHistogram)(nil) | ||||
| func (i *siHistogram) setDelegate(m metric.Meter) { | ||||
| 	ctr, err := m.Int64Histogram(i.name, i.opts...) | ||||
| 	if err != nil { | ||||
| 		otel.Handle(err) | ||||
| 		oGlob.GetErrorHandler().Handle(err) | ||||
| 		return | ||||
| 	} | ||||
| 	i.delegate.Store(ctr) | ||||
|   | ||||
| @@ -19,7 +19,7 @@ import ( | ||||
| 	"sync" | ||||
| 	"sync/atomic" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel" | ||||
| 	oGlob "go.opentelemetry.io/otel/internal/global" | ||||
| 	"go.opentelemetry.io/otel/metric" | ||||
| 	"go.opentelemetry.io/otel/metric/instrument" | ||||
| ) | ||||
| @@ -334,7 +334,7 @@ func (c *registration) setDelegate(m metric.Meter) { | ||||
|  | ||||
| 	reg, err := m.RegisterCallback(c.function, insts...) | ||||
| 	if err != nil { | ||||
| 		otel.Handle(err) | ||||
| 		oGlob.GetErrorHandler().Handle(err) | ||||
| 	} | ||||
|  | ||||
| 	c.unreg = reg.Unregister | ||||
|   | ||||
							
								
								
									
										41
									
								
								metric_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								metric_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| // 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 otel // import "go.opentelemetry.io/otel" | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/metric" | ||||
| ) | ||||
|  | ||||
| type testMeterProvider struct{} | ||||
|  | ||||
| var _ metric.MeterProvider = &testMeterProvider{} | ||||
|  | ||||
| func (*testMeterProvider) Meter(_ string, _ ...metric.MeterOption) metric.Meter { | ||||
| 	return metric.NewNoopMeterProvider().Meter("") | ||||
| } | ||||
|  | ||||
| func TestMultipleGlobalMeterProvider(t *testing.T) { | ||||
| 	p1 := testMeterProvider{} | ||||
| 	p2 := metric.NewNoopMeterProvider() | ||||
| 	SetMeterProvider(&p1) | ||||
| 	SetMeterProvider(p2) | ||||
|  | ||||
| 	got := GetMeterProvider() | ||||
| 	assert.Equal(t, p2, got) | ||||
| } | ||||
| @@ -17,7 +17,10 @@ require ( | ||||
| 	github.com/davecgh/go-spew v1.1.1 // indirect | ||||
| 	github.com/go-logr/stdr v1.2.2 // indirect | ||||
| 	github.com/pmezard/go-difflib v1.0.0 // indirect | ||||
| 	go.opentelemetry.io/otel/metric v0.37.0 // indirect | ||||
| 	gopkg.in/yaml.v3 v3.0.1 // indirect | ||||
| ) | ||||
|  | ||||
| replace go.opentelemetry.io/otel/trace => ../trace | ||||
|  | ||||
| replace go.opentelemetry.io/otel/metric => ../metric | ||||
|   | ||||
| @@ -18,7 +18,7 @@ import ( | ||||
| 	"context" | ||||
| 	"log" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/metric/global" | ||||
| 	"go.opentelemetry.io/otel" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/resource" | ||||
| 	semconv "go.opentelemetry.io/otel/semconv/v1.17.0" | ||||
| @@ -42,7 +42,7 @@ func Example() { | ||||
| 		metric.WithResource(res), | ||||
| 		metric.WithReader(reader), | ||||
| 	) | ||||
| 	global.SetMeterProvider(meterProvider) | ||||
| 	otel.SetMeterProvider(meterProvider) | ||||
| 	defer func() { | ||||
| 		err := meterProvider.Shutdown(context.Background()) | ||||
| 		if err != nil { | ||||
|   | ||||
| @@ -29,7 +29,6 @@ import ( | ||||
| 	"go.opentelemetry.io/otel" | ||||
| 	"go.opentelemetry.io/otel/attribute" | ||||
| 	"go.opentelemetry.io/otel/metric" | ||||
| 	"go.opentelemetry.io/otel/metric/global" | ||||
| 	"go.opentelemetry.io/otel/metric/instrument" | ||||
| 	"go.opentelemetry.io/otel/sdk/instrumentation" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric/aggregation" | ||||
| @@ -631,7 +630,7 @@ func TestGlobalInstRegisterCallback(t *testing.T) { | ||||
| 	otel.SetLogger(logr.New(l)) | ||||
|  | ||||
| 	const mtrName = "TestGlobalInstRegisterCallback" | ||||
| 	preMtr := global.Meter(mtrName) | ||||
| 	preMtr := otel.Meter(mtrName) | ||||
| 	preInt64Ctr, err := preMtr.Int64ObservableCounter("pre.int64.counter") | ||||
| 	require.NoError(t, err) | ||||
| 	preFloat64Ctr, err := preMtr.Float64ObservableCounter("pre.float64.counter") | ||||
| @@ -639,9 +638,9 @@ func TestGlobalInstRegisterCallback(t *testing.T) { | ||||
|  | ||||
| 	rdr := NewManualReader() | ||||
| 	mp := NewMeterProvider(WithReader(rdr), WithResource(resource.Empty())) | ||||
| 	global.SetMeterProvider(mp) | ||||
| 	otel.SetMeterProvider(mp) | ||||
|  | ||||
| 	postMtr := global.Meter(mtrName) | ||||
| 	postMtr := otel.Meter(mtrName) | ||||
| 	postInt64Ctr, err := postMtr.Int64ObservableCounter("post.int64.counter") | ||||
| 	require.NoError(t, err) | ||||
| 	postFloat64Ctr, err := postMtr.Float64ObservableCounter("post.float64.counter") | ||||
|   | ||||
| @@ -15,3 +15,5 @@ require ( | ||||
| 	github.com/pmezard/go-difflib v1.0.0 // indirect | ||||
| 	gopkg.in/yaml.v3 v3.0.1 // indirect | ||||
| ) | ||||
|  | ||||
| replace go.opentelemetry.io/otel/metric => ../metric | ||||
|   | ||||
		Reference in New Issue
	
	Block a user