json_formatter.go 3.0 KB

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