Skip to content

Commit c27f83d

Browse files
authored
improve handling of Fanout args (#42)
* feat: make Fanout a no-op when len(handlers) == 1 Updates #41 * feat: flatten FanoutHandlers in Fanout Fixes #41
1 parent 1ea1fac commit c27f83d

File tree

2 files changed

+71
-1
lines changed

2 files changed

+71
-1
lines changed

multi.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ type FanoutHandler struct {
2121
}
2222

2323
// Fanout creates a new FanoutHandler that distributes records to multiple slog.Handler instances.
24+
// If exactly one handler is provided, it returns that handler unmodified.
25+
// If you pass a FanoutHandler as an argument, its handlers are flattened into the new FanoutHandler.
2426
// This function is the primary entry point for creating a multi-handler setup.
2527
//
2628
// Example usage:
@@ -39,8 +41,20 @@ type FanoutHandler struct {
3941
//
4042
// A slog.Handler that forwards all operations to the provided handlers
4143
func Fanout(handlers ...slog.Handler) slog.Handler {
44+
var flat []slog.Handler
45+
for _, handler := range handlers {
46+
if fan, ok := handler.(*FanoutHandler); ok {
47+
flat = append(flat, fan.handlers...)
48+
} else {
49+
flat = append(flat, handler)
50+
}
51+
}
52+
53+
if len(flat) == 1 {
54+
return flat[0]
55+
}
4256
return &FanoutHandler{
43-
handlers: handlers,
57+
handlers: flat,
4458
}
4559
}
4660

multi_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package slogmulti
2+
3+
import (
4+
"io"
5+
"log/slog"
6+
"testing"
7+
)
8+
9+
func TestFanoutIncrementalBuildFlattensHandlers(t *testing.T) {
10+
t.Parallel()
11+
12+
h1 := slog.NewJSONHandler(io.Discard, nil)
13+
h2 := slog.NewJSONHandler(io.Discard, nil)
14+
h3 := slog.NewJSONHandler(io.Discard, nil)
15+
16+
var handler slog.Handler = h1
17+
handler = Fanout(handler, h2)
18+
handler = Fanout(handler, h3)
19+
20+
fanout, ok := handler.(*FanoutHandler)
21+
if !ok {
22+
t.Fatalf("expected FanoutHandler, got %T", handler)
23+
}
24+
if len(fanout.handlers) != 3 {
25+
t.Fatalf("expected 3 handlers, got %d", len(fanout.handlers))
26+
}
27+
if fanout.handlers[0] != h1 || fanout.handlers[1] != h2 || fanout.handlers[2] != h3 {
28+
t.Fatalf("handlers were not flattened correctly")
29+
}
30+
}
31+
32+
func TestFanoutFlattensMixedNestedHandlers(t *testing.T) {
33+
t.Parallel()
34+
35+
h1 := slog.NewJSONHandler(io.Discard, nil)
36+
h2 := slog.NewJSONHandler(io.Discard, nil)
37+
h3 := slog.NewJSONHandler(io.Discard, nil)
38+
h4 := slog.NewJSONHandler(io.Discard, nil)
39+
40+
handler := Fanout(Fanout(h1, h2), h3, Fanout(h4))
41+
42+
fanout, ok := handler.(*FanoutHandler)
43+
if !ok {
44+
t.Fatalf("expected FanoutHandler, got %T", handler)
45+
}
46+
if len(fanout.handlers) != 4 {
47+
t.Fatalf("expected 4 handlers, got %d", len(fanout.handlers))
48+
}
49+
50+
if fanout.handlers[0] != h1 ||
51+
fanout.handlers[1] != h2 ||
52+
fanout.handlers[2] != h3 ||
53+
fanout.handlers[3] != h4 {
54+
t.Fatalf("handlers were not flattened correctly")
55+
}
56+
}

0 commit comments

Comments
 (0)