| // 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 ( | |
| "errors" | |
| "log" | |
| "sync" | |
| "sync/atomic" | |
| ) | |
| // ErrorHandler handles irremediable events. | |
| type ErrorHandler interface { | |
| // Handle handles any error deemed irremediable by an OpenTelemetry | |
| // component. | |
| Handle(error) | |
| } | |
| // ErrDelegator is an ErrorHandler that forwards errors to a delegate | |
| // ErrorHandler set with setDelegate. Before a delegate is set, it logs | |
| // errors to STDERR. | |
| type ErrDelegator struct { | |
| delegate atomic.Pointer[ErrorHandler] | |
| } | |
| // Compile-time check that delegator implements ErrorHandler. | |
| var _ ErrorHandler = (*ErrDelegator)(nil) | |
| // Handle handles err by forwarding it to the configured delegate, or | |
| // logging it to STDERR if no delegate is set. | |
| 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 | |
| } |