Skip to content

Conversation

@srebhan
Copy link
Member

@srebhan srebhan commented Oct 31, 2025

Summary

This PR allows to register callbacks for logging events to be able to get informed about such events. Those callbacks are required for the heartbeat plugin.

Checklist

Related issues

related to #17577

@telegraf-tiger telegraf-tiger bot added the feat Improvement on an existing feature such as adding a new setting/mode to an existing plugin label Oct 31, 2025
@Hipska
Copy link
Contributor

Hipska commented Nov 3, 2025

Does this addition also add possibility to implement #10245?

Co-authored-by: Thomas Casteleyn <[email protected]>
@srebhan
Copy link
Member Author

srebhan commented Nov 3, 2025

Does this addition also add possibility to implement #10245?

Yes it will be possible with the heartbeat plugin I think.

@Hipska
Copy link
Contributor

Hipska commented Nov 3, 2025

That plugin only limits the errors to be sent to a HTTP post endpoint. The request mentioned was more general. (e.g. extra option in inputs.internal to convert/emit each log message as a new metric, where it then could be processed as desired..)

Copy link
Contributor

@skartikey skartikey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@srebhan The core implementation is solid. I have a couple of questions/suggestions.

logger/logger.go Outdated
Comment on lines 158 to 162
// Serve all registered callbacks
callbackMu.Lock()
for _, cb := range callbacks {
cb(level, ts.UTC(), l.source, l.attributes, args...)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Callbacks are executed before the log level check, so they run for all messages regardless of the configured level. Consider moving the callback execution after the level check to avoid unnecessary calls. If the heartbeat plugin intentionally needs all messages, that should be clearly documented.

Also, note that the mutex is held while executing all callbacks:

callbackMu.Lock()
for _, cb := range callbacks {
    cb(level, ts.UTC(), l.source, l.attributes, args...) // user code runs with lock held!
}
callbackMu.Unlock()

If a callback is slow or blocks, it will block all logging operations. It might be worth documenting this behavior or switching to a copy-then-execute pattern:

callbackMu.Lock()
cbs := append([]CallbackFunc(nil), callbacks...)
callbackMu.Unlock()

for _, cb := range cbs {
    cb(level, ts.UTC(), l.source, l.attributes, args...)
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed the mutex to an rw-mutex which should resolve the issue... Should I execute the callbacks in a go-routine to prevent blocking the logging?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sticking with synchronous makes sense; the RWMutex already allows concurrent logging calls, so multiple goroutines can call Print() and execute callbacks concurrently.
If the heartbeat plugin needs to do any slow work (like HTTP calls), it should handle that asynchronously within its own callback using a channel/queue pattern rather than blocking the logger.

Copy link
Contributor

@Hipska Hipska Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also feel like the callbacks should happen after level checking. It might give too much unwanted/undocumented behaviour if not?

For example, it will become very hard in the callback to have Debug level for plugin instance A and Warning level for plugin instance B, while that logic is already present.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Hipska I think exactly the contrary is the case if you put the callbacks after filtering because then you will have a combination of all logging configuration with the filtering potentially done on the receiver side of the callback as you basically do a "which-ever setting is higher" kind of operation. That prevents having different filtering for file-based logging and the plugin use.

I agree that having the filtered logs would also be valuable but we should then add another set of callbacks called after the filtering basically allowing to have custom logging outputs that behave the same way as file/console-based logging...

@srebhan
Copy link
Member Author

srebhan commented Nov 3, 2025

That plugin only limits the errors to be sent to a HTTP post endpoint. The request mentioned was more general. (e.g. extra option in inputs.internal to convert/emit each log message as a new metric, where it then could be processed as desired..)

Yeah that would either go with the internal plugin or a new plugin then...

@srebhan srebhan requested a review from skartikey November 3, 2025 15:02
@telegraf-tiger
Copy link
Contributor

telegraf-tiger bot commented Nov 3, 2025

Copy link
Contributor

@skartikey skartikey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@srebhan Great addition to the logger!

@skartikey skartikey merged commit a95cbe9 into influxdata:master Nov 3, 2025
26 of 27 checks passed
@github-actions github-actions bot added this to the v1.37.0 milestone Nov 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/logging feat Improvement on an existing feature such as adding a new setting/mode to an existing plugin

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants