Files
2026-09-11 01:47:20 +08:00

69 lines
1.7 KiB
Go

package tracing
import (
"context"
"errors"
"log/slog"
)
// FanoutHandler 是一个将日志记录扇出到多个 slog.Handler 的组合处理器,
// 用于同时输出本地 JSON 日志与 OTel 日志桥接。
type FanoutHandler struct {
handlers []slog.Handler
}
// NewFanoutHandler 创建扇出处理器(忽略 nil handler)。
func NewFanoutHandler(handlers ...slog.Handler) *FanoutHandler {
filtered := make([]slog.Handler, 0, len(handlers))
for _, h := range handlers {
if h != nil {
filtered = append(filtered, h)
}
}
return &FanoutHandler{handlers: filtered}
}
// Enabled 任一子处理器启用即返回 true。
func (f *FanoutHandler) Enabled(ctx context.Context, level slog.Level) bool {
for _, h := range f.handlers {
if h.Enabled(ctx, level) {
return true
}
}
return false
}
// Handle 将记录分发给每个启用的子处理器(各自使用副本,避免相互污染)。
func (f *FanoutHandler) Handle(ctx context.Context, r slog.Record) error {
var errs []error
for _, h := range f.handlers {
if h.Enabled(ctx, r.Level) {
if err := h.Handle(ctx, r.Clone()); err != nil {
errs = append(errs, err)
}
}
}
return errors.Join(errs...)
}
// WithAttrs 为每个子处理器附加属性。
func (f *FanoutHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
next := make([]slog.Handler, len(f.handlers))
for i, h := range f.handlers {
next[i] = h.WithAttrs(attrs)
}
return &FanoutHandler{handlers: next}
}
// WithGroup 为每个子处理器开启分组。
func (f *FanoutHandler) WithGroup(name string) slog.Handler {
if name == "" {
return f
}
next := make([]slog.Handler, len(f.handlers))
for i, h := range f.handlers {
next[i] = h.WithGroup(name)
}
return &FanoutHandler{handlers: next}
}