blob: 83f3e523a9a3ea7add9ba061ab0327fa2a4045d4 [file] [log] [blame]
Joey Armstrong5f51f2e2023-01-17 17:06:26 -05001// 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 global
16
17import (
18 "log"
19 "os"
20 "sync"
21 "sync/atomic"
22
23 "go.opentelemetry.io/otel"
24)
25
26var (
27 // globalErrorHandler provides an ErrorHandler that can be used
28 // throughout an OpenTelemetry instrumented project. When a user
29 // specified ErrorHandler is registered (`SetErrorHandler`) all calls to
30 // `Handle` and will be delegated to the registered ErrorHandler.
31 globalErrorHandler = &loggingErrorHandler{
32 l: log.New(os.Stderr, "", log.LstdFlags),
33 }
34
35 // delegateErrorHandlerOnce ensures that a user provided ErrorHandler is
36 // only ever registered once.
37 delegateErrorHandlerOnce sync.Once
38
39 // Comiple time check that loggingErrorHandler implements ErrorHandler.
40 _ otel.ErrorHandler = (*loggingErrorHandler)(nil)
41)
42
43// loggingErrorHandler logs all errors to STDERR.
44type loggingErrorHandler struct {
45 delegate atomic.Value
46
47 l *log.Logger
48}
49
50// setDelegate sets the ErrorHandler delegate if one is not already set.
51func (h *loggingErrorHandler) setDelegate(d otel.ErrorHandler) {
52 if h.delegate.Load() != nil {
53 // Delegate already registered
54 return
55 }
56 h.delegate.Store(d)
57}
58
59// Handle implements otel.ErrorHandler.
60func (h *loggingErrorHandler) Handle(err error) {
61 if d := h.delegate.Load(); d != nil {
62 d.(otel.ErrorHandler).Handle(err)
63 return
64 }
65 h.l.Print(err)
66}
67
68// ErrorHandler returns the global ErrorHandler instance. If no ErrorHandler
69// instance has been set (`SetErrorHandler`), the default ErrorHandler which
70// logs errors to STDERR is returned.
71func ErrorHandler() otel.ErrorHandler {
72 return globalErrorHandler
73}
74
75// SetErrorHandler sets the global ErrorHandler to be h.
76func SetErrorHandler(h otel.ErrorHandler) {
77 delegateErrorHandlerOnce.Do(func() {
78 current := ErrorHandler()
79 if current == h {
80 return
81 }
82 if internalHandler, ok := current.(*loggingErrorHandler); ok {
83 internalHandler.setDelegate(h)
84 }
85 })
86}
87
88// Handle is a convience function for ErrorHandler().Handle(err)
89func Handle(err error) {
90 ErrorHandler().Handle(err)
91}