| // Copyright The OpenTelemetry Authors |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| // Package errorhandler provides the global error handler for OpenTelemetry. |
| // |
| // This package has no OTel dependencies, allowing it to be imported by any |
| // package in the module without creating import cycles. |
| package errorhandler // import "go.opentelemetry.io/otel/internal/errorhandler" |
| |
| import ( |
| "errors" |
| "log" |
| "sync" |
| "sync/atomic" |
| ) |
| |
| // ErrorHandler handles irremediable events. |
| type ErrorHandler interface { |
| // Handle handles any error deemed irremediable by an OpenTelemetry |
| // component. |
| Handle(error) |
| } |
| |
| type ErrDelegator struct { |
| delegate atomic.Pointer[ErrorHandler] |
| } |
| |
| // Compile-time check that delegator implements ErrorHandler. |
| var _ ErrorHandler = (*ErrDelegator)(nil) |
| |
| func (d *ErrDelegator) Handle(err error) { |
| if eh := d.delegate.Load(); eh != nil { |
| (*eh).Handle(err) |
| return |
| } |
| log.Print(err) |
| } |
| |
| // setDelegate sets the ErrorHandler delegate. |
| func (d *ErrDelegator) setDelegate(eh ErrorHandler) { |
| d.delegate.Store(&eh) |
| } |
| |
| type errorHandlerHolder struct { |
| eh ErrorHandler |
| } |
| |
| var ( |
| globalErrorHandler = defaultErrorHandler() |
| delegateErrorHandlerOnce sync.Once |
| ) |
| |
| // 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.Load().(errorHandlerHolder).eh |
| } |
| |
| // 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) { |
| current := GetErrorHandler() |
| |
| if _, cOk := current.(*ErrDelegator); cOk { |
| if _, ehOk := h.(*ErrDelegator); ehOk && current == h { |
| // Do not assign to the delegate of the default ErrDelegator to be |
| // itself. |
| log.Print(errors.New("no ErrorHandler delegate configured"), " ErrorHandler remains its current value.") |
| return |
| } |
| } |
| |
| delegateErrorHandlerOnce.Do(func() { |
| if def, ok := current.(*ErrDelegator); ok { |
| def.setDelegate(h) |
| } |
| }) |
| globalErrorHandler.Store(errorHandlerHolder{eh: h}) |
| } |
| |
| func defaultErrorHandler() *atomic.Value { |
| v := &atomic.Value{} |
| v.Store(errorHandlerHolder{eh: &ErrDelegator{}}) |
| return v |
| } |