master
go 163 lines 3.14 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package logger
4
5 import (
6 "context"
7 "fmt"
8 "io"
9 "log/slog"
10 "os"
11 "sync/atomic"
12
13 "github.com/netdata/netdata/go/plugins/pkg/executable"
14 "github.com/netdata/netdata/go/plugins/pkg/terminal"
15 )
16
17 var isTerm = terminal.IsTerminal()
18
19 var isJournal = isStderrConnectedToJournal()
20
21 var pluginAttr = slog.String("plugin", executable.Name)
22
23 func New() *Logger {
24 return newLogger(os.Stderr, isTerm, 4)
25 }
26
27 func NewWithWriter(w io.Writer) *Logger {
28 if w == nil {
29 w = os.Stderr
30 }
31 return newLogger(w, false, 4)
32 }
33
34 func newLogger(w io.Writer, isTerminal bool, depth int) *Logger {
35 if isTerminal {
36 // skip 2 slog pkg calls, 2 this pkg calls
37 return &Logger{sl: slog.New(withTerminalCallDepth(depth, newTerminalHandler(w))), rl: newRateLimiter()}
38 }
39 return &Logger{sl: slog.New(newTextHandler(w)).With(pluginAttr), rl: newRateLimiter()}
40 }
41
42 type Logger struct {
43 muted atomic.Bool
44 sl *slog.Logger
45 rl *rateLimiter
46 }
47
48 func (l *Logger) Error(a ...any) {
49 if !l.canLog(slog.LevelError) {
50 return
51 }
52 l.log(slog.LevelError, fmt.Sprint(a...))
53 }
54
55 func (l *Logger) Warning(a ...any) {
56 if !l.canLog(slog.LevelWarn) {
57 return
58 }
59 l.log(slog.LevelWarn, fmt.Sprint(a...))
60 }
61
62 func (l *Logger) Notice(a ...any) {
63 if !l.canLog(levelNotice) {
64 return
65 }
66 l.log(levelNotice, fmt.Sprint(a...))
67 }
68
69 func (l *Logger) Info(a ...any) {
70 if !l.canLog(slog.LevelInfo) {
71 return
72 }
73 l.log(slog.LevelInfo, fmt.Sprint(a...))
74 }
75
76 func (l *Logger) Debug(a ...any) {
77 if !l.canLog(slog.LevelDebug) {
78 return
79 }
80 l.log(slog.LevelDebug, fmt.Sprint(a...))
81 }
82
83 func (l *Logger) Errorf(format string, a ...any) {
84 if !l.canLog(slog.LevelError) {
85 return
86 }
87 l.log(slog.LevelError, fmt.Sprintf(format, a...))
88 }
89
90 func (l *Logger) Warningf(format string, a ...any) {
91 if !l.canLog(slog.LevelWarn) {
92 return
93 }
94 l.log(slog.LevelWarn, fmt.Sprintf(format, a...))
95 }
96
97 func (l *Logger) Noticef(format string, a ...any) {
98 if !l.canLog(levelNotice) {
99 return
100 }
101 l.log(levelNotice, fmt.Sprintf(format, a...))
102 }
103
104 func (l *Logger) Infof(format string, a ...any) {
105 if !l.canLog(slog.LevelInfo) {
106 return
107 }
108 l.log(slog.LevelInfo, fmt.Sprintf(format, a...))
109 }
110
111 func (l *Logger) Debugf(format string, a ...any) {
112 if !l.canLog(slog.LevelDebug) {
113 return
114 }
115 l.log(slog.LevelDebug, fmt.Sprintf(format, a...))
116 }
117
118 func (l *Logger) Mute() { l.mute(true) }
119 func (l *Logger) Unmute() { l.mute(false) }
120
121 func (l *Logger) With(args ...any) *Logger {
122 if l.isNil() {
123 ll := New()
124 return &Logger{sl: ll.sl.With(args...), rl: ll.rl}
125 }
126
127 ll := &Logger{sl: l.sl.With(args...), rl: l.rl}
128 ll.muted.Store(l.muted.Load())
129
130 return ll
131 }
132
133 func (l *Logger) log(level slog.Level, msg string) {
134 if l.isNil() {
135 nilLogger.sl.Log(context.Background(), level, msg)
136 return
137 }
138
139 if !l.muted.Load() {
140 l.sl.Log(context.Background(), level, msg)
141 }
142 }
143
144 func (l *Logger) canLog(level slog.Level) bool {
145 if !Level.Enabled(level) {
146 return false
147 }
148 if l.isNil() {
149 return true
150 }
151 return !l.muted.Load()
152 }
153
154 func (l *Logger) mute(v bool) {
155 if l.isNil() || isTerm && Level.Enabled(slog.LevelDebug) {
156 return
157 }
158 l.muted.Store(v)
159 }
160
161 func (l *Logger) isNil() bool { return l == nil || l.sl == nil }
162
163 var nilLogger = New()