slog_handler.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. package logger
  2. import (
  3. "context"
  4. "log/slog"
  5. "strings"
  6. "time"
  7. "go.uber.org/zap"
  8. "go.uber.org/zap/zapcore"
  9. )
  10. type slogZapHandler struct {
  11. logger *zap.Logger
  12. attrs []slog.Attr
  13. groups []string
  14. }
  15. func newSlogZapHandler(logger *zap.Logger) slog.Handler {
  16. if logger == nil {
  17. logger = zap.NewNop()
  18. }
  19. return &slogZapHandler{
  20. logger: logger,
  21. attrs: make([]slog.Attr, 0, 8),
  22. groups: make([]string, 0, 4),
  23. }
  24. }
  25. func (h *slogZapHandler) Enabled(_ context.Context, level slog.Level) bool {
  26. switch {
  27. case level >= slog.LevelError:
  28. return h.logger.Core().Enabled(LevelError)
  29. case level >= slog.LevelWarn:
  30. return h.logger.Core().Enabled(LevelWarn)
  31. case level <= slog.LevelDebug:
  32. return h.logger.Core().Enabled(LevelDebug)
  33. default:
  34. return h.logger.Core().Enabled(LevelInfo)
  35. }
  36. }
  37. func (h *slogZapHandler) Handle(_ context.Context, record slog.Record) error {
  38. fields := make([]zap.Field, 0, len(h.attrs)+record.NumAttrs()+3)
  39. fields = append(fields, slogAttrsToZapFields(h.groups, h.attrs)...)
  40. record.Attrs(func(attr slog.Attr) bool {
  41. fields = append(fields, slogAttrToZapField(h.groups, attr))
  42. return true
  43. })
  44. switch {
  45. case record.Level >= slog.LevelError:
  46. h.logger.Error(record.Message, fields...)
  47. case record.Level >= slog.LevelWarn:
  48. h.logger.Warn(record.Message, fields...)
  49. case record.Level <= slog.LevelDebug:
  50. h.logger.Debug(record.Message, fields...)
  51. default:
  52. h.logger.Info(record.Message, fields...)
  53. }
  54. return nil
  55. }
  56. func (h *slogZapHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
  57. next := *h
  58. next.attrs = append(append([]slog.Attr{}, h.attrs...), attrs...)
  59. return &next
  60. }
  61. func (h *slogZapHandler) WithGroup(name string) slog.Handler {
  62. name = strings.TrimSpace(name)
  63. if name == "" {
  64. return h
  65. }
  66. next := *h
  67. next.groups = append(append([]string{}, h.groups...), name)
  68. return &next
  69. }
  70. func slogAttrsToZapFields(groups []string, attrs []slog.Attr) []zap.Field {
  71. fields := make([]zap.Field, 0, len(attrs))
  72. for _, attr := range attrs {
  73. fields = append(fields, slogAttrToZapField(groups, attr))
  74. }
  75. return fields
  76. }
  77. func slogAttrToZapField(groups []string, attr slog.Attr) zap.Field {
  78. if len(groups) > 0 {
  79. attr.Key = strings.Join(append(append([]string{}, groups...), attr.Key), ".")
  80. }
  81. value := attr.Value.Resolve()
  82. switch value.Kind() {
  83. case slog.KindBool:
  84. return zap.Bool(attr.Key, value.Bool())
  85. case slog.KindInt64:
  86. return zap.Int64(attr.Key, value.Int64())
  87. case slog.KindUint64:
  88. return zap.Uint64(attr.Key, value.Uint64())
  89. case slog.KindFloat64:
  90. return zap.Float64(attr.Key, value.Float64())
  91. case slog.KindDuration:
  92. return zap.Duration(attr.Key, value.Duration())
  93. case slog.KindTime:
  94. return zap.Time(attr.Key, value.Time())
  95. case slog.KindString:
  96. return zap.String(attr.Key, value.String())
  97. case slog.KindGroup:
  98. groupFields := make([]zap.Field, 0, len(value.Group()))
  99. for _, nested := range value.Group() {
  100. groupFields = append(groupFields, slogAttrToZapField(nil, nested))
  101. }
  102. return zap.Object(attr.Key, zapObjectFields(groupFields))
  103. case slog.KindAny:
  104. if t, ok := value.Any().(time.Time); ok {
  105. return zap.Time(attr.Key, t)
  106. }
  107. return zap.Any(attr.Key, value.Any())
  108. default:
  109. return zap.String(attr.Key, value.String())
  110. }
  111. }
  112. type zapObjectFields []zap.Field
  113. func (z zapObjectFields) MarshalLogObject(enc zapcore.ObjectEncoder) error {
  114. for _, field := range z {
  115. field.AddTo(enc)
  116. }
  117. return nil
  118. }