Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 977ddd3

Browse files
2
Change-Id: I2effccfd296366065ee9626a9674cd637b702218
1 parent 2937564 commit 977ddd3

File tree

3 files changed

+71
-104
lines changed

3 files changed

+71
-104
lines changed

‎src/log/slog/handler.go

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ package slog
66

77
import (
88
"context"
9-
"errors"
109
"fmt"
1110
"io"
1211
"log/slog/internal/buffer"
@@ -643,49 +642,3 @@ func (dh discardHandler) Enabled(context.Context, Level) bool { return false }
643642
func (dh discardHandler) Handle(context.Context, Record) error { return nil }
644643
func (dh discardHandler) WithAttrs(attrs []Attr) Handler { return dh }
645644
func (dh discardHandler) WithGroup(name string) Handler { return dh }
646-
647-
// MultiHandler returns a handler that invokes all the given Handlers.
648-
// Its Enable method reports whether any of the handlers' Enabled methods return true.
649-
// Its Handle, WithAttr and WithGroup methods call the corresponding method on each of the enabled handlers.
650-
func MultiHandler(handlers ...Handler) Handler {
651-
return multiHandler(handlers)
652-
}
653-
654-
type multiHandler []Handler
655-
656-
func (h multiHandler) Enabled(ctx context.Context, l Level) bool {
657-
for i := range h {
658-
if h[i].Enabled(ctx, l) {
659-
return true
660-
}
661-
}
662-
return false
663-
}
664-
665-
func (h multiHandler) Handle(ctx context.Context, r Record) error {
666-
var errs []error
667-
for i := range h {
668-
if h[i].Enabled(ctx, r.Level) {
669-
if err := h[i].Handle(ctx, r.Clone()); err != nil {
670-
errs = append(errs, err)
671-
}
672-
}
673-
}
674-
return errors.Join(errs...)
675-
}
676-
677-
func (h multiHandler) WithAttrs(attrs []Attr) Handler {
678-
handlers := make([]Handler, 0, len(h))
679-
for i := range h {
680-
handlers = append(handlers, h[i].WithAttrs(attrs))
681-
}
682-
return multiHandler(handlers)
683-
}
684-
685-
func (h multiHandler) WithGroup(name string) Handler {
686-
handlers := make([]Handler, 0, len(h))
687-
for i := range h {
688-
handlers = append(handlers, h[i].WithGroup(name))
689-
}
690-
return multiHandler(handlers)
691-
}

‎src/log/slog/multi_handler.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright 2025 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package slog
6+
7+
import (
8+
"context"
9+
"errors"
10+
)
11+
12+
// MultiHandler returns a handler that invokes all the given Handlers.
13+
// Its Enable method reports whether any of the handlers' Enabled methods return true.
14+
// Its Handle, WithAttr and WithGroup methods call the corresponding method on each of the enabled handlers.
15+
func MultiHandler(handlers ...Handler) Handler {
16+
return &multiHandler{multi: handlers}
17+
}
18+
19+
type multiHandler struct {
20+
multi []Handler
21+
}
22+
23+
func (h *multiHandler) Enabled(ctx context.Context, l Level) bool {
24+
for i := range h.multi {
25+
if h.multi[i].Enabled(ctx, l) {
26+
return true
27+
}
28+
}
29+
return false
30+
}
31+
32+
func (h *multiHandler) Handle(ctx context.Context, r Record) error {
33+
var errs []error
34+
for i := range h.multi {
35+
if h.multi[i].Enabled(ctx, r.Level) {
36+
if err := h.multi[i].Handle(ctx, r.Clone()); err != nil {
37+
errs = append(errs, err)
38+
}
39+
}
40+
}
41+
return errors.Join(errs...)
42+
}
43+
44+
func (h *multiHandler) WithAttrs(attrs []Attr) Handler {
45+
handlers := make([]Handler, 0, len(h.multi))
46+
for i := range h.multi {
47+
handlers = append(handlers, h.multi[i].WithAttrs(attrs))
48+
}
49+
return &multiHandler{multi: handlers}
50+
}
51+
52+
func (h *multiHandler) WithGroup(name string) Handler {
53+
handlers := make([]Handler, 0, len(h.multi))
54+
for i := range h.multi {
55+
handlers = append(handlers, h.multi[i].WithGroup(name))
56+
}
57+
return &multiHandler{multi: handlers}
58+
}

‎src/log/slog/multi_handler_test.go

Lines changed: 13 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"bytes"
99
"context"
1010
"errors"
11-
"strings"
1211
"testing"
1312
"time"
1413
)
@@ -27,8 +26,6 @@ func (h *mockFailingHandler) Handle(ctx context.Context, r Record) error {
2726
}
2827

2928
func TestMultiHandler(t *testing.T) {
30-
ctx := context.Background()
31-
3229
t.Run("Handle sends log to all handlers", func(t *testing.T) {
3330
var buf1, buf2 bytes.Buffer
3431
h1 := NewTextHandler(&buf1, nil)
@@ -39,21 +36,8 @@ func TestMultiHandler(t *testing.T) {
3936

4037
logger.Info("hello world", "user", "test")
4138

42-
// Check the output of the Text handler.
43-
output1 := buf1.String()
44-
if !strings.Contains(output1, `level=INFO`) ||
45-
!strings.Contains(output1, `msg="hello world"`) ||
46-
!strings.Contains(output1, `user=test`) {
47-
t.Errorf("Text handler did not receive the correct log message. Got: %s", output1)
48-
}
49-
50-
// Check the output of the JSON handle.
51-
output2 := buf2.String()
52-
if !strings.Contains(output2, `"level":"INFO"`) ||
53-
!strings.Contains(output2, `"msg":"hello world"`) ||
54-
!strings.Contains(output2, `"user":"test"`) {
55-
t.Errorf("JSON handler did not receive the correct log message. Got: %s", output2)
56-
}
39+
checkLogOutput(t, buf1.String(), "time="+textTimeRE+` level=INFO msg="hello world" user=test`)
40+
checkLogOutput(t, buf2.String(), `{"time":"`+jsonTimeRE+`","level":"INFO","msg":"hello world","user":"test"}`)
5741
})
5842

5943
t.Run("Enabled returns true if any handler is enabled", func(t *testing.T) {
@@ -62,10 +46,10 @@ func TestMultiHandler(t *testing.T) {
6246

6347
multi := MultiHandler(h1, h2)
6448

65-
if !multi.Enabled(ctx, LevelInfo) {
49+
if !multi.Enabled(context.Background(), LevelInfo) {
6650
t.Error("Enabled should be true for INFO level, but got false")
6751
}
68-
if !multi.Enabled(ctx, LevelError) {
52+
if !multi.Enabled(context.Background(), LevelError) {
6953
t.Error("Enabled should be true for ERROR level, but got false")
7054
}
7155
})
@@ -76,7 +60,7 @@ func TestMultiHandler(t *testing.T) {
7660

7761
multi := MultiHandler(h1, h2)
7862

79-
if multi.Enabled(ctx, LevelDebug) {
63+
if multi.Enabled(context.Background(), LevelDebug) {
8064
t.Error("Enabled should be false for DEBUG level, but got true")
8165
}
8266
})
@@ -91,15 +75,8 @@ func TestMultiHandler(t *testing.T) {
9175

9276
logger.Info("request processed")
9377

94-
// Check if the Text handler contains the attribute.
95-
if !strings.Contains(buf1.String(), "request_id=123") {
96-
t.Errorf("Text handler output missing attribute. Got: %s", buf1.String())
97-
}
98-
99-
// Check if the JSON handler contains the attribute.
100-
if !strings.Contains(buf2.String(), `"request_id":"123"`) {
101-
t.Errorf("JSON handler output missing attribute. Got: %s", buf2.String())
102-
}
78+
checkLogOutput(t, buf1.String(), "time="+textTimeRE+` level=INFO msg="request processed" request_id=123`)
79+
checkLogOutput(t, buf2.String(), `{"time":"`+jsonTimeRE+`","level":"INFO","msg":"request processed","request_id":"123"}`)
10380
})
10481

10582
t.Run("WithGroup propagates group to all handlers", func(t *testing.T) {
@@ -112,24 +89,14 @@ func TestMultiHandler(t *testing.T) {
11289

11390
logger.Info("user login", "user_id", 42)
11491

115-
// Check if the Text handler contains the group.
116-
expectedText := "req.user_id=42"
117-
if !strings.Contains(buf1.String(), expectedText) {
118-
t.Errorf("Text handler output missing group. Expected to contain %q, Got: %s", expectedText, buf1.String())
119-
}
120-
121-
// Check if the JSON handler contains the group.
122-
expectedJSON := `"req":{"user_id":42}`
123-
if !strings.Contains(buf2.String(), expectedJSON) {
124-
t.Errorf("JSON handler output missing group. Expected to contain %q, Got: %s", expectedJSON, buf2.String())
125-
}
92+
checkLogOutput(t, buf1.String(), "time="+textTimeRE+` level=INFO msg="user login" req.user_id=42`)
93+
checkLogOutput(t, buf2.String(), `{"time":"`+jsonTimeRE+`","level":"INFO","msg":"user login","req":{"user_id":42}}`)
12694
})
12795

12896
t.Run("Handle propagates errors from handlers", func(t *testing.T) {
12997
var buf bytes.Buffer
13098
h1 := NewTextHandler(&buf, nil)
13199

132-
// Simulate a handler that will fail.
133100
errFail := errors.New("fake fail")
134101
h2 := &mockFailingHandler{
135102
Handler: NewTextHandler(&bytes.Buffer{}, nil),
@@ -138,32 +105,21 @@ func TestMultiHandler(t *testing.T) {
138105

139106
multi := MultiHandler(h1, h2)
140107

141-
err := multi.Handle(ctx, NewRecord(time.Now(), LevelInfo, "test message", 0))
142-
143-
// Check if the error was returned correctly.
144-
if err == nil {
145-
t.Fatal("Expected an error from Handle, but got nil")
146-
}
108+
err := multi.Handle(context.Background(), NewRecord(time.Now(), LevelInfo, "test message", 0))
147109
if !errors.Is(err, errFail) {
148110
t.Errorf("Expected error: %v, but got: %v", errFail, err)
149111
}
150112

151-
// Also, check that the successful handler still output the log.
152-
if !strings.Contains(buf.String(), "test message") {
153-
t.Error("The successful handler should still have processed the log")
154-
}
113+
checkLogOutput(t, buf.String(), "time="+textTimeRE+` level=INFO msg="test message"`)
155114
})
156115

157116
t.Run("Handle with no handlers", func(t *testing.T) {
158-
// Create an empty multi-handler.
159117
multi := MultiHandler()
160118
logger := New(multi)
161119

162-
// This should be safe to call and do nothing.
163-
logger.Info("this is nothing")
120+
logger.Info("nothing")
164121

165-
// Calling Handle directly should also be safe.
166-
err := multi.Handle(ctx, NewRecord(time.Now(), LevelInfo, "test", 0))
122+
err := multi.Handle(context.Background(), NewRecord(time.Now(), LevelInfo, "test", 0))
167123
if err != nil {
168124
t.Errorf("Handle with no sub-handlers should return nil, but got: %v", err)
169125
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /