json_formatter.go 3.1 KB

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