| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- package logger
- import (
- "context"
- "log/slog"
- "strings"
- "time"
- "go.uber.org/zap"
- "go.uber.org/zap/zapcore"
- )
- type slogZapHandler struct {
- logger *zap.Logger
- attrs []slog.Attr
- groups []string
- }
- func newSlogZapHandler(logger *zap.Logger) slog.Handler {
- if logger == nil {
- logger = zap.NewNop()
- }
- return &slogZapHandler{
- logger: logger,
- attrs: make([]slog.Attr, 0, 8),
- groups: make([]string, 0, 4),
- }
- }
- func (h *slogZapHandler) Enabled(_ context.Context, level slog.Level) bool {
- switch {
- case level >= slog.LevelError:
- return h.logger.Core().Enabled(LevelError)
- case level >= slog.LevelWarn:
- return h.logger.Core().Enabled(LevelWarn)
- case level <= slog.LevelDebug:
- return h.logger.Core().Enabled(LevelDebug)
- default:
- return h.logger.Core().Enabled(LevelInfo)
- }
- }
- func (h *slogZapHandler) Handle(_ context.Context, record slog.Record) error {
- fields := make([]zap.Field, 0, len(h.attrs)+record.NumAttrs()+3)
- fields = append(fields, slogAttrsToZapFields(h.groups, h.attrs)...)
- record.Attrs(func(attr slog.Attr) bool {
- fields = append(fields, slogAttrToZapField(h.groups, attr))
- return true
- })
- switch {
- case record.Level >= slog.LevelError:
- h.logger.Error(record.Message, fields...)
- case record.Level >= slog.LevelWarn:
- h.logger.Warn(record.Message, fields...)
- case record.Level <= slog.LevelDebug:
- h.logger.Debug(record.Message, fields...)
- default:
- h.logger.Info(record.Message, fields...)
- }
- return nil
- }
- func (h *slogZapHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
- next := *h
- next.attrs = append(append([]slog.Attr{}, h.attrs...), attrs...)
- return &next
- }
- func (h *slogZapHandler) WithGroup(name string) slog.Handler {
- name = strings.TrimSpace(name)
- if name == "" {
- return h
- }
- next := *h
- next.groups = append(append([]string{}, h.groups...), name)
- return &next
- }
- func slogAttrsToZapFields(groups []string, attrs []slog.Attr) []zap.Field {
- fields := make([]zap.Field, 0, len(attrs))
- for _, attr := range attrs {
- fields = append(fields, slogAttrToZapField(groups, attr))
- }
- return fields
- }
- func slogAttrToZapField(groups []string, attr slog.Attr) zap.Field {
- if len(groups) > 0 {
- attr.Key = strings.Join(append(append([]string{}, groups...), attr.Key), ".")
- }
- value := attr.Value.Resolve()
- switch value.Kind() {
- case slog.KindBool:
- return zap.Bool(attr.Key, value.Bool())
- case slog.KindInt64:
- return zap.Int64(attr.Key, value.Int64())
- case slog.KindUint64:
- return zap.Uint64(attr.Key, value.Uint64())
- case slog.KindFloat64:
- return zap.Float64(attr.Key, value.Float64())
- case slog.KindDuration:
- return zap.Duration(attr.Key, value.Duration())
- case slog.KindTime:
- return zap.Time(attr.Key, value.Time())
- case slog.KindString:
- return zap.String(attr.Key, value.String())
- case slog.KindGroup:
- groupFields := make([]zap.Field, 0, len(value.Group()))
- for _, nested := range value.Group() {
- groupFields = append(groupFields, slogAttrToZapField(nil, nested))
- }
- return zap.Object(attr.Key, zapObjectFields(groupFields))
- case slog.KindAny:
- if t, ok := value.Any().(time.Time); ok {
- return zap.Time(attr.Key, t)
- }
- return zap.Any(attr.Key, value.Any())
- default:
- return zap.String(attr.Key, value.String())
- }
- }
- type zapObjectFields []zap.Field
- func (z zapObjectFields) MarshalLogObject(enc zapcore.ObjectEncoder) error {
- for _, field := range z {
- field.AddTo(enc)
- }
- return nil
- }
|