json_formatter.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package logrus
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "runtime"
  7. )
  8. type fieldKey string
  9. // FieldMap allows customization of the key names for default fields.
  10. type FieldMap map[fieldKey]string
  11. func (f FieldMap) resolve(key fieldKey) string {
  12. if k, ok := f[key]; ok {
  13. return k
  14. }
  15. return string(key)
  16. }
  17. // JSONFormatter formats logs into parsable json
  18. type JSONFormatter struct {
  19. // TimestampFormat sets the format used for marshaling timestamps.
  20. // The format to use is the same than for time.Format or time.Parse from the standard
  21. // library.
  22. // The standard Library already provides a set of predefined format.
  23. TimestampFormat string
  24. // DisableTimestamp allows disabling automatic timestamps in output
  25. DisableTimestamp bool
  26. // DisableHTMLEscape allows disabling html escaping in output
  27. DisableHTMLEscape bool
  28. // DataKey allows users to put all the log entry parameters into a nested dictionary at a given key.
  29. DataKey string
  30. // FieldMap allows users to customize the names of keys for default fields.
  31. // As an example:
  32. // formatter := &JSONFormatter{
  33. // FieldMap: FieldMap{
  34. // FieldKeyTime: "@timestamp",
  35. // FieldKeyLevel: "@level",
  36. // FieldKeyMsg: "@message",
  37. // FieldKeyFunc: "@caller",
  38. // },
  39. // }
  40. FieldMap FieldMap
  41. // CallerPrettyfier can be set by the user to modify the content
  42. // of the function and file keys in the json data when ReportCaller is
  43. // activated. If any of the returned value is the empty string the
  44. // corresponding key will be removed from json fields.
  45. CallerPrettyfier func(*runtime.Frame) (function string, file string)
  46. // PrettyPrint will indent all json logs
  47. PrettyPrint bool
  48. }
  49. // Format renders a single log entry
  50. func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
  51. data := make(Fields, len(entry.Data)+4)
  52. for k, v := range entry.Data {
  53. switch v := v.(type) {
  54. case error:
  55. // Otherwise errors are ignored by `encoding/json`
  56. // https://github.com/sirupsen/logrus/issues/137
  57. data[k] = v.Error()
  58. default:
  59. data[k] = v
  60. }
  61. }
  62. if f.DataKey != "" {
  63. newData := make(Fields, 4)
  64. newData[f.DataKey] = data
  65. data = newData
  66. }
  67. prefixFieldClashes(data, f.FieldMap, entry.HasCaller())
  68. timestampFormat := f.TimestampFormat
  69. if timestampFormat == "" {
  70. timestampFormat = defaultTimestampFormat
  71. }
  72. if entry.err != "" {
  73. data[f.FieldMap.resolve(FieldKeyLogrusError)] = entry.err
  74. }
  75. if !f.DisableTimestamp {
  76. data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat)
  77. }
  78. data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
  79. data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
  80. if entry.HasCaller() {
  81. funcVal := entry.Caller.Function
  82. fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
  83. if f.CallerPrettyfier != nil {
  84. funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
  85. }
  86. if funcVal != "" {
  87. data[f.FieldMap.resolve(FieldKeyFunc)] = funcVal
  88. }
  89. if fileVal != "" {
  90. data[f.FieldMap.resolve(FieldKeyFile)] = fileVal
  91. }
  92. }
  93. var b *bytes.Buffer
  94. if entry.Buffer != nil {
  95. b = entry.Buffer
  96. } else {
  97. b = &bytes.Buffer{}
  98. }
  99. encoder := json.NewEncoder(b)
  100. encoder.SetEscapeHTML(!f.DisableHTMLEscape)
  101. if f.PrettyPrint {
  102. encoder.SetIndent("", " ")
  103. }
  104. if err := encoder.Encode(data); err != nil {
  105. return nil, fmt.Errorf("failed to marshal fields to JSON, %w", err)
  106. }
  107. return b.Bytes(), nil
  108. }