formatter.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. package logger
  2. import (
  3. "bytes"
  4. "fmt"
  5. "regexp"
  6. "sort"
  7. "strings"
  8. "time"
  9. "unicode/utf8"
  10. logrus "github.com/sirupsen/logrus"
  11. )
  12. var (
  13. logKeysPriorities = map[string]int{
  14. "request_id": 3,
  15. "method": 2,
  16. "status": 1,
  17. "error": -1,
  18. "stack": -2,
  19. }
  20. logQuotingRe = regexp.MustCompile(`^[a-zA-Z0-9\-._/@^+]+$`)
  21. )
  22. type logKeys []string
  23. func (p logKeys) Len() int { return len(p) }
  24. func (p logKeys) Less(i, j int) bool { return logKeysPriorities[p[i]] > logKeysPriorities[p[j]] }
  25. func (p logKeys) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
  26. type prettyFormatter struct {
  27. levelFormat string
  28. }
  29. func newPrettyFormatter() *prettyFormatter {
  30. f := new(prettyFormatter)
  31. levelLenMax := 0
  32. for _, level := range logrus.AllLevels {
  33. levelLen := utf8.RuneCount([]byte(level.String()))
  34. if levelLen > levelLenMax {
  35. levelLenMax = levelLen
  36. }
  37. }
  38. f.levelFormat = fmt.Sprintf("%%-%ds", levelLenMax)
  39. return f
  40. }
  41. func (f *prettyFormatter) Format(entry *logrus.Entry) ([]byte, error) {
  42. keys := make([]string, 0, len(entry.Data))
  43. for k := range entry.Data {
  44. if k != "stack" {
  45. keys = append(keys, k)
  46. }
  47. }
  48. sort.Sort(logKeys(keys))
  49. levelColor := 36
  50. switch entry.Level {
  51. case logrus.DebugLevel, logrus.TraceLevel:
  52. levelColor = 37
  53. case logrus.WarnLevel:
  54. levelColor = 33
  55. case logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel:
  56. levelColor = 31
  57. }
  58. levelText := fmt.Sprintf(f.levelFormat, strings.ToUpper(entry.Level.String()))
  59. msg := strings.TrimSuffix(entry.Message, "\n")
  60. var b *bytes.Buffer
  61. if entry.Buffer != nil {
  62. b = entry.Buffer
  63. } else {
  64. b = new(bytes.Buffer)
  65. }
  66. fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m [%s] %s ", levelColor, levelText, entry.Time.Format(time.RFC3339), msg)
  67. for _, k := range keys {
  68. v := entry.Data[k]
  69. fmt.Fprintf(b, " \x1b[1m%s\x1b[0m=", k)
  70. f.appendValue(b, v)
  71. }
  72. b.WriteByte('\n')
  73. if stack, ok := entry.Data["stack"]; ok {
  74. fmt.Fprintln(b, stack)
  75. }
  76. return b.Bytes(), nil
  77. }
  78. func (f *prettyFormatter) appendValue(b *bytes.Buffer, value interface{}) {
  79. strValue, ok := value.(string)
  80. if !ok {
  81. strValue = fmt.Sprint(value)
  82. }
  83. if logQuotingRe.MatchString(strValue) {
  84. b.WriteString(strValue)
  85. } else {
  86. fmt.Fprintf(b, "%q", strValue)
  87. }
  88. }
  89. type structuredFormatter struct{}
  90. func (f *structuredFormatter) Format(entry *logrus.Entry) ([]byte, error) {
  91. keys := make([]string, 0, len(entry.Data))
  92. for k := range entry.Data {
  93. keys = append(keys, k)
  94. }
  95. sort.Sort(logKeys(keys))
  96. msg := strings.TrimSuffix(entry.Message, "\n")
  97. var b *bytes.Buffer
  98. if entry.Buffer != nil {
  99. b = entry.Buffer
  100. } else {
  101. b = new(bytes.Buffer)
  102. }
  103. f.appendKeyValue(b, "time", entry.Time.Format(time.RFC3339))
  104. f.appendKeyValue(b, "level", entry.Level.String())
  105. f.appendKeyValue(b, "message", msg)
  106. for _, k := range keys {
  107. f.appendKeyValue(b, k, entry.Data[k])
  108. }
  109. b.WriteByte('\n')
  110. return b.Bytes(), nil
  111. }
  112. func (f *structuredFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
  113. if b.Len() != 0 {
  114. b.WriteByte(' ')
  115. }
  116. strValue, ok := value.(string)
  117. if !ok {
  118. strValue = fmt.Sprint(value)
  119. }
  120. fmt.Fprintf(b, "%s=%q", key, strValue)
  121. }