1// Copyright The OpenTelemetry Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package otel // import "go.opentelemetry.io/otel"
16
17import (
18	"log"
19	"os"
20	"sync"
21	"sync/atomic"
22)
23
24var (
25	// globalErrorHandler provides an ErrorHandler that can be used
26	// throughout an OpenTelemetry instrumented project. When a user
27	// specified ErrorHandler is registered (`SetErrorHandler`) all calls to
28	// `Handle` and will be delegated to the registered ErrorHandler.
29	globalErrorHandler = defaultErrorHandler()
30
31	// delegateErrorHandlerOnce ensures that a user provided ErrorHandler is
32	// only ever registered once.
33	delegateErrorHandlerOnce sync.Once
34
35	// Compile-time check that delegator implements ErrorHandler.
36	_ ErrorHandler = (*delegator)(nil)
37)
38
39type holder struct {
40	eh ErrorHandler
41}
42
43func defaultErrorHandler() *atomic.Value {
44	v := &atomic.Value{}
45	v.Store(holder{eh: &delegator{l: log.New(os.Stderr, "", log.LstdFlags)}})
46	return v
47}
48
49// delegator logs errors if no delegate is set, otherwise they are delegated.
50type delegator struct {
51	delegate atomic.Value
52
53	l *log.Logger
54}
55
56// setDelegate sets the ErrorHandler delegate.
57func (h *delegator) setDelegate(d ErrorHandler) {
58	// It is critical this is guarded with delegateErrorHandlerOnce, if it is
59	// called again with a different concrete type it will panic.
60	h.delegate.Store(d)
61}
62
63// Handle logs err if no delegate is set, otherwise it is delegated.
64func (h *delegator) Handle(err error) {
65	if d := h.delegate.Load(); d != nil {
66		d.(ErrorHandler).Handle(err)
67		return
68	}
69	h.l.Print(err)
70}
71
72// GetErrorHandler returns the global ErrorHandler instance.
73//
74// The default ErrorHandler instance returned will log all errors to STDERR
75// until an override ErrorHandler is set with SetErrorHandler. All
76// ErrorHandler returned prior to this will automatically forward errors to
77// the set instance instead of logging.
78//
79// Subsequent calls to SetErrorHandler after the first will not forward errors
80// to the new ErrorHandler for prior returned instances.
81func GetErrorHandler() ErrorHandler {
82	return globalErrorHandler.Load().(holder).eh
83}
84
85// SetErrorHandler sets the global ErrorHandler to h.
86//
87// The first time this is called all ErrorHandler previously returned from
88// GetErrorHandler will send errors to h instead of the default logging
89// ErrorHandler. Subsequent calls will set the global ErrorHandler, but not
90// delegate errors to h.
91func SetErrorHandler(h ErrorHandler) {
92	delegateErrorHandlerOnce.Do(func() {
93		current := GetErrorHandler()
94		if current == h {
95			return
96		}
97		if internalHandler, ok := current.(*delegator); ok {
98			internalHandler.setDelegate(h)
99		}
100	})
101	globalErrorHandler.Store(holder{eh: h})
102}
103
104// Handle is a convenience function for ErrorHandler().Handle(err)
105func Handle(err error) {
106	GetErrorHandler().Handle(err)
107}
108