1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2024-12-04 09:43:23 +02:00

Update global Handler delegate to atomic value

This commit is contained in:
Tyler Yahn 2020-06-01 11:50:35 -07:00
parent 57e65fe7f8
commit c50803d259
No known key found for this signature in database
GPG Key ID: 42AA23B0BC85B798
2 changed files with 32 additions and 22 deletions

View File

@ -18,47 +18,50 @@ import (
"log"
"os"
"sync"
"sync/atomic"
"go.opentelemetry.io/otel/api/oterror"
)
var (
defaultHandler = &handler{
// globalHandler provides an oterror.Handler that can be used throughout
// an OpenTelemetry instrumented project. When a user specified Handler
// is registered (`SetHandler`) all calls to `Handle` will be delegated
// to the registered Handler.
globalHandler = &handler{
l: log.New(os.Stderr, "", log.LstdFlags),
}
// delegateHanderOnce ensures that a user provided Handler is only ever
// registered once.
delegateHanderOnce sync.Once
// Ensure the handler implements oterror.Handle at build time.
_ oterror.Handler = (*handler)(nil)
)
// handler logs all errors to STDERR.
type handler struct {
sync.Mutex
delegate oterror.Handler
delegate atomic.Value
l *log.Logger
}
// setDelegate sets the handler delegate if one is not already set.
func (h *handler) setDelegate(d oterror.Handler) {
h.Lock()
defer h.Unlock()
if h.delegate != nil {
// delegate already registered
if h.delegate.Load() != nil {
// Delegate already registered
return
}
h.delegate = d
h.delegate.Store(d)
}
// Handle implements oterror.Handler.
func (h *handler) Handle(err error) {
if h.delegate != nil {
h.delegate.Handle(err)
if d := h.delegate.Load(); d != nil {
d.(oterror.Handler).Handle(err)
return
}
h.Lock()
defer h.Unlock()
h.l.Print(err)
}
@ -67,15 +70,23 @@ func (h *handler) Handle(err error) {
// until an Handler is set (all functionality is delegated to the set
// Handler once it is set).
func Handler() oterror.Handler {
return defaultHandler
return globalHandler
}
// SetHandler sets the global Handler to be h.
func SetHandler(h oterror.Handler) {
defaultHandler.setDelegate(h)
delegateHanderOnce.Do(func() {
current := Handler()
if current == h {
return
}
if internalHandler, ok := current.(*handler); ok {
internalHandler.setDelegate(h)
}
})
}
// Handle is a convience function for Handler().Handle(err)
func Handle(err error) {
defaultHandler.Handle(err)
globalHandler.Handle(err)
}

View File

@ -44,20 +44,19 @@ type HandlerTestSuite struct {
suite.Suite
origHandler *handler
errLogger *errLogger
errLogger *errLogger
}
func (s *HandlerTestSuite) SetupSuite() {
s.errLogger = new(errLogger)
s.origHandler = defaultHandler
defaultHandler = &handler{
s.origHandler = globalHandler
globalHandler = &handler{
l: log.New(s.errLogger, "", 0),
}
}
func (s *HandlerTestSuite) TearDownSuite() {
defaultHandler = s.origHandler
globalHandler = s.origHandler
}
func (s *HandlerTestSuite) SetupTest() {