I’m working on a Go project where I need to bridge slog.Logger to testing.T’s logging system. I want to forward slog.Logger calls so they show as log messages on testing.T. I’ve created a custom log handler:
type TestLogger struct {
t *testing.T
failOnError bool
}
func (tl TestLogger) Handle(ctx context.Context, r slog.Record) error {
tl.t.Helper()
if r.Level >= slog.LevelError && tl.failOnError {
tl.t.Errorf("Log level %v: %s", r.Level, r.Message)
} else {
tl.t.Logf("Log level %v: %s", r.Level, r.Message)
}
return nil
}
// Additional methods for handling attributes and groups can be implemented here
This solution helps catch errors early in tests by failing on error-level logs. I would appreciate feedback on how to better manage attributes and log groups while ensuring the overall test clarity.
I’ve used a similar approach in my projects, and it’s been quite effective. One thing that’s helped me a lot is implementing a buffer to capture logs during test execution. This way, you can analyze the entire log output after the test completes, which is super useful for debugging complex scenarios.
Here’s a quick example of how you might implement this:
You can then use this in your tests and call Flush() at the end to dump all logs. This approach has saved me countless hours when dealing with asynchronous operations or race conditions in tests. Just remember to call Flush() in defer statements to ensure logs are always output, even if the test panics.
Your approach looks solid. One thing to consider is handling structured logging more effectively. You could extend your TestLogger to capture and format attributes:
hey there, i’ve been using a similar setup and found it pretty helpful. one thing you might wanna consider is adding a way to capture and test for specific log messages. maybe something like:
func (tl *TestLogger) ExpectLog(level slog.Level, msg string) bool {
// check if log was recorded
}
this could help with more precise testing. just a thought!