Skip to content

Commit a95cbe9

Browse files
srebhanHipska
andauthored
feat(logging): Allow registering callbacks for logging events (#17916)
Co-authored-by: Thomas Casteleyn <[email protected]>
1 parent b2407f2 commit a95cbe9

File tree

1 file changed

+62
-12
lines changed

1 file changed

+62
-12
lines changed

logger/logger.go

Lines changed: 62 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,28 @@ import (
1010
"sync"
1111
"time"
1212

13+
"github.com/google/uuid"
14+
1315
"github.com/influxdata/telegraf"
1416
)
1517

1618
// Central handler for the logs used by the logger to actually output the logs.
1719
// This is necessary to be able to dynamically switch the sink even though
1820
// plugins already instantiated a logger _before_ the final sink is set up.
1921
var (
20-
instance *handler // handler for the actual output
21-
once sync.Once // once token to initialize the handler only once
22+
instance *handler // handler for the actual output
23+
callbacks map[string]CallbackFunc // logging callback registry
24+
callbackMu sync.RWMutex
25+
once sync.Once // once token to initialize the handler only once
26+
)
27+
28+
// CallbackFunc is a function to be called when printing messages
29+
type CallbackFunc func(
30+
level telegraf.LogLevel,
31+
timestamp time.Time,
32+
source string,
33+
attributes map[string]interface{},
34+
arguments ...interface{},
2235
)
2336

2437
// sink interface that has to be implemented by a logging sink
@@ -33,6 +46,7 @@ type logger struct {
3346
name string
3447
alias string
3548

49+
source string
3650
prefix string
3751
onError []func()
3852
attributes map[string]interface{}
@@ -51,20 +65,19 @@ func New(category, name, alias string) *logger {
5165
}
5266

5367
// Format the prefix
54-
l.prefix = l.category
68+
l.source = l.category
5569

56-
if l.prefix != "" && l.name != "" {
57-
l.prefix += "."
70+
if l.source != "" && l.name != "" {
71+
l.source += "."
5872
}
59-
l.prefix += l.name
73+
l.source += l.name
6074

61-
if l.prefix != "" && l.alias != "" {
62-
l.prefix += "::"
75+
if l.source != "" && l.alias != "" {
76+
l.source += "::"
6377
}
64-
l.prefix += l.alias
65-
66-
if l.prefix != "" {
67-
l.prefix = "[" + l.prefix + "] "
78+
l.source += l.alias
79+
if l.source != "" {
80+
l.prefix = "[" + l.source + "] "
6881
}
6982

7083
return l
@@ -142,6 +155,14 @@ func (l *logger) Print(level telegraf.LogLevel, ts time.Time, args ...interface{
142155
instance.add(level, ts, l.prefix, l.attributes, args...)
143156
}
144157

158+
// Serve all registered callbacks before checking the log-level. This is
159+
// intentional to allow the callback to apply its own log-level filtering.
160+
callbackMu.RLock()
161+
for _, cb := range callbacks {
162+
cb(level, ts.UTC(), l.source, l.attributes, args...)
163+
}
164+
callbackMu.RUnlock()
165+
145166
// Skip all messages with insufficient log-levels
146167
if l.level != nil && !l.level.Includes(level) || l.level == nil && !instance.level.Includes(level) {
147168
return
@@ -301,12 +322,41 @@ func CloseLogging() error {
301322
return nil
302323
}
303324

325+
// AddCallback adds the given callback function to the registry and returns an
326+
// ID that can be used for removing the callback later. Callback functions must
327+
// not block or take a lot of time!
328+
func AddCallback(callback CallbackFunc) (string, error) {
329+
// Create a cookie to be returned to the caller in order to be able to
330+
// remove the callback later
331+
rawid, err := uuid.NewRandom()
332+
if err != nil {
333+
return "", err
334+
}
335+
id := rawid.String()
336+
337+
callbackMu.Lock()
338+
callbacks[id] = callback
339+
callbackMu.Unlock()
340+
341+
return id, nil
342+
}
343+
344+
// RemoveCallback removes the callback function with the given ID from the registry
345+
func RemoveCallback(id string) {
346+
callbackMu.Lock()
347+
defer callbackMu.Unlock()
348+
delete(callbacks, id)
349+
}
350+
304351
func init() {
305352
once.Do(func() {
306353
// Create a special logging instance that additionally buffers all
307354
// messages logged before the final logger is up.
308355
instance = defaultHandler()
309356

357+
// Setup callback registry
358+
callbacks = make(map[string]CallbackFunc)
359+
310360
// Redirect the standard logger output to our logger instance
311361
log.SetFlags(0)
312362
log.SetOutput(&stdlogRedirector{})

0 commit comments

Comments
 (0)