69 lines
1.7 KiB
Go
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}
|
|
}
|