1
0

formatter_common.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. package logger
  2. import (
  3. "encoding"
  4. "fmt"
  5. "log/slog"
  6. "time"
  7. )
  8. // formatterCommon holds the common logic for both pretty and structured formatting.
  9. type formatterCommon struct {
  10. buf *buffer
  11. groups []attrGroup
  12. // Attributes that should be handled specially
  13. error slog.Attr
  14. source slog.Attr
  15. stack slog.Attr
  16. }
  17. // newHandlerFormatterCommon creates a new formatterCommon instance.
  18. func newFormatterCommon(groups []attrGroup, buf *buffer) formatterCommon {
  19. return formatterCommon{
  20. buf: buf,
  21. groups: groups,
  22. }
  23. }
  24. // levelName returns the name of the log level.
  25. func (s *formatterCommon) levelName(lvl slog.Level) string {
  26. switch {
  27. case lvl < slog.LevelInfo:
  28. return "DEBUG"
  29. case lvl < slog.LevelWarn:
  30. return "INFO"
  31. case lvl < slog.LevelError:
  32. return "WARNING"
  33. case lvl < LevelCritical:
  34. return "ERROR"
  35. default:
  36. return "CRITICAL"
  37. }
  38. }
  39. // saveSpecialAttr saves special attributes for later use.
  40. // It returns true if the attribute was saved (meaning it was a special attribute).
  41. func (s *formatterCommon) saveSpecialAttr(attr slog.Attr) bool {
  42. switch attr.Key {
  43. case "error":
  44. s.error = attr
  45. case "source":
  46. s.source = attr
  47. case "stack":
  48. s.stack = attr
  49. default:
  50. return false
  51. }
  52. return true
  53. }
  54. // appendValue appends a value to the buffer, applying quoting rules as necessary.
  55. func (s *formatterCommon) appendValue(val slog.Value, forceQuote bool) {
  56. switch val.Kind() {
  57. case slog.KindString:
  58. s.appendString(val.String(), forceQuote)
  59. case slog.KindInt64:
  60. s.buf.appendInt(val.Int64())
  61. case slog.KindUint64:
  62. s.buf.appendUint(val.Uint64())
  63. case slog.KindFloat64:
  64. s.buf.appendFloat(val.Float64())
  65. case slog.KindBool:
  66. s.buf.appendBool(val.Bool())
  67. case slog.KindDuration:
  68. s.appendString(val.Duration().String(), forceQuote)
  69. case slog.KindTime:
  70. s.appendTime(val.Time())
  71. default:
  72. s.appendAny(val.Any(), forceQuote)
  73. }
  74. }
  75. // appendString appends a string value to the buffer, applying quoting rules as necessary.
  76. func (s *formatterCommon) appendString(val string, forceQuote bool) {
  77. if forceQuote {
  78. s.buf.appendStringQuoted(val)
  79. } else {
  80. s.buf.appendString(val)
  81. }
  82. }
  83. // appendTime appends a time value to the buffer, wrapping it in quotes,
  84. // ([time.DateTime] always contains a space)
  85. func (s *formatterCommon) appendTime(val time.Time) {
  86. s.buf.append('"')
  87. s.buf.appendStringRaw(val.Format(time.DateTime))
  88. s.buf.append('"')
  89. }
  90. // appendAny appends a value of any type to the buffer, applying quoting rules as necessary.
  91. func (s *formatterCommon) appendAny(val any, forceQuote bool) {
  92. switch v := val.(type) {
  93. case fmt.Stringer:
  94. s.appendString(v.String(), forceQuote)
  95. return
  96. case error:
  97. s.appendString(v.Error(), forceQuote)
  98. return
  99. case encoding.TextMarshaler:
  100. if data, err := v.MarshalText(); err == nil {
  101. s.appendString(string(data), forceQuote)
  102. return
  103. }
  104. }
  105. // Fallback to default string representation
  106. s.appendString(fmt.Sprintf("%+v", val), forceQuote)
  107. }