github.com/searKing/golang/go@v1.2.117/log/slog/multi.go (about) 1 // Copyright 2023 The searKing Author. 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 "log/slog" 10 ) 11 12 var _ slog.Handler = (*multiHandler)(nil) 13 14 type multiHandler []slog.Handler 15 16 func (t multiHandler) Enabled(ctx context.Context, level slog.Level) bool { 17 for _, w := range t { 18 if w != nil && w.Enabled(ctx, level) { 19 return true 20 } 21 } 22 return false 23 } 24 25 func (t multiHandler) Handle(ctx context.Context, record slog.Record) error { 26 for _, w := range t { 27 if w == nil || !w.Enabled(ctx, record.Level) { 28 continue 29 } 30 if err := w.Handle(ctx, record); err != nil { 31 return err 32 } 33 } 34 return nil 35 } 36 37 func (t multiHandler) WithAttrs(attrs []slog.Attr) slog.Handler { 38 var handlers []slog.Handler 39 for _, w := range t { 40 if w != nil { 41 handlers = append(handlers, w.WithAttrs(attrs)) 42 } 43 } 44 return MultiHandler(handlers...) 45 } 46 47 func (t multiHandler) WithGroup(name string) slog.Handler { 48 var handlers []slog.Handler 49 for _, w := range t { 50 if w != nil { 51 handlers = append(handlers, w.WithGroup(name)) 52 } 53 } 54 return MultiHandler(handlers...) 55 } 56 57 // MultiHandler creates a slog.Handler that duplicates its writes to all the 58 // provided handlers, similar to the Unix tee(1) command. 59 // 60 // Each write is written to each listed writer, one at a time. 61 // If a listed writer returns an error, that overall write operation 62 // stops and returns the error; it does not continue down the list. 63 func MultiHandler(handlers ...slog.Handler) slog.Handler { 64 allHandlers := make([]slog.Handler, 0, len(handlers)) 65 for _, w := range handlers { 66 if w == nil { 67 continue 68 } 69 if mw, ok := w.(multiHandler); ok { 70 allHandlers = append(allHandlers, mw...) 71 } else { 72 allHandlers = append(allHandlers, w) 73 } 74 } 75 return multiHandler(allHandlers) 76 } 77 78 // MultiReplaceAttr creates a [ReplaceAttr] that call all the provided replacers one by one 79 func MultiReplaceAttr(replacers ...func(groups []string, a slog.Attr) slog.Attr) func(groups []string, a slog.Attr) slog.Attr { 80 return func(groups []string, a slog.Attr) slog.Attr { 81 for _, h := range replacers { 82 if h != nil { 83 a = h(groups, a) 84 } 85 } 86 return a 87 } 88 }