tusd
tusd copied to clipboard
slog: replace golang.org/x/exp/slog with log/slog
Thank you for this PR! I am supportive of this change, but we have to defer merging it until the next major release since this is a breaking change. At the time of writing, there is no concrete plan for the next major release.
Im dropping this here as it might help someone and I have gotten rid of needing a fork of tusd due to it. I hope it helps someone as you can't really downgrade zap logger and so your in a rock/hard place.
func loggerToSlog(logger *zap.Logger) *slog.Logger {
// Create a bridge
bridge := NewSlogBridge(logger)
// Create a handler that wraps the new slog handler but presents the old interface
oldHandler := bridge.Handler()
// Create an old-style logger with this handler
return slog.New(oldHandler)
}
package main
import (
"context"
"go.uber.org/zap/exp/zapslog"
"golang.org/x/exp/slog"
newSlog "log/slog"
)
// SlogBridge bridges between the old and new slog versions
type SlogBridge struct {
logger *newSlog.Logger // new slog.Logger
}
// NewSlogBridge creates a new bridge between slog versions
func NewSlogBridge(logger *zap.Logger) *SlogBridge {
// Convert zap logger to new slog.Logger
newSlogger := newSlog.New(zapslog.NewHandler(logger.Core()))
return &SlogBridge{
logger: newSlogger,
}
}
// Handler returns a handler compatible with the old slog version
func (b *SlogBridge) Handler() slog.Handler {
return &handlerBridge{newHandler: b.logger.Handler()}
}
func convertAttr(attr slog.Attr) newSlog.Attr {
switch attr.Value.Kind() {
case slog.KindBool:
return newSlog.Bool(attr.Key, attr.Value.Bool())
case slog.KindDuration:
return newSlog.Duration(attr.Key, attr.Value.Duration())
case slog.KindFloat64:
return newSlog.Float64(attr.Key, attr.Value.Float64())
case slog.KindInt64:
return newSlog.Int64(attr.Key, attr.Value.Int64())
case slog.KindString:
return newSlog.String(attr.Key, attr.Value.String())
case slog.KindTime:
return newSlog.Time(attr.Key, attr.Value.Time())
case slog.KindUint64:
return newSlog.Uint64(attr.Key, attr.Value.Uint64())
case slog.KindGroup:
group := attr.Value.Group()
attrs := make([]any, len(group))
for i, a := range group {
attrs[i] = convertAttr(a)
}
return newSlog.Group(attr.Key, attrs...)
case slog.KindLogValuer:
return convertAttr(slog.Attr{
Key: attr.Key,
Value: attr.Value.Resolve(),
})
default:
return newSlog.Any(attr.Key, attr.Value.Any())
}
}
// handlerBridge implements the old slog.Handler interface using the new slog.Handler
type handlerBridge struct {
newHandler newSlog.Handler
}
func (h *handlerBridge) Enabled(ctx context.Context, level slog.Level) bool {
return h.newHandler.Enabled(ctx, newSlog.Level(level))
}
func (h *handlerBridge) Handle(ctx context.Context, r slog.Record) error {
// Convert old Record to new Record
newRecord := newSlog.NewRecord(
r.Time,
newSlog.Level(r.Level),
r.Message,
r.PC,
)
r.Attrs(func(attr slog.Attr) bool {
newRecord.Add(convertAttr(attr))
return true
})
return h.newHandler.Handle(ctx, newRecord)
}
func (h *handlerBridge) WithAttrs(attrs []slog.Attr) slog.Handler {
newAttrs := make([]newSlog.Attr, len(attrs))
for i, attr := range attrs {
newAttrs[i] = convertAttr(attr)
}
return &handlerBridge{newHandler: h.newHandler.WithAttrs(newAttrs)}
}
func (h *handlerBridge) WithGroup(name string) slog.Handler {
return &handlerBridge{newHandler: h.newHandler.WithGroup(name)}
}