json_formatter.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. package logrus
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. )
  7. type fieldKey string
  8. // FieldMap allows customization of the key names for default fields.
  9. type FieldMap map[fieldKey]string
  10. func (f FieldMap) resolve(key fieldKey) string {
  11. if k, ok := f[key]; ok {
  12. return k
  13. }
  14. return string(key)
  15. }
  16. // JSONFormatter formats logs into parsable json
  17. type JSONFormatter struct {
  18. // TimestampFormat sets the format used for marshaling timestamps.
  19. TimestampFormat string
  20. // DisableTimestamp allows disabling automatic timestamps in output
  21. DisableTimestamp bool
  22. // DataKey allows users to put all the log entry parameters into a nested dictionary at a given key.
  23. DataKey string
  24. // FieldMap allows users to customize the names of keys for default fields.
  25. // As an example:
  26. // formatter := &JSONFormatter{
  27. // FieldMap: FieldMap{
  28. // FieldKeyTime: "@timestamp",
  29. // FieldKeyLevel: "@level",
  30. // FieldKeyMsg: "@message",
  31. // FieldKeyFunc: "@caller",
  32. // },
  33. // }
  34. FieldMap FieldMap
  35. // PrettyPrint will indent all json logs
  36. PrettyPrint bool
  37. }
  38. // Format renders a single log entry
  39. func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
  40. data := make(Fields, len(entry.Data)+4)
  41. for k, v := range entry.Data {
  42. switch v := v.(type) {
  43. case error:
  44. // Otherwise errors are ignored by `encoding/json`
  45. // https://github.com/sirupsen/logrus/issues/137
  46. data[k] = v.Error()
  47. default:
  48. data[k] = v
  49. }
  50. }
  51. if f.DataKey != "" {
  52. newData := make(Fields, 4)
  53. newData[f.DataKey] = data
  54. data = newData
  55. }
  56. prefixFieldClashes(data, f.FieldMap, entry.HasCaller())
  57. timestampFormat := f.TimestampFormat
  58. if timestampFormat == "" {
  59. timestampFormat = defaultTimestampFormat
  60. }
  61. if entry.err != "" {
  62. data[f.FieldMap.resolve(FieldKeyLogrusError)] = entry.err
  63. }
  64. if !f.DisableTimestamp {
  65. data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat)
  66. }
  67. data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
  68. data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
  69. if entry.HasCaller() {
  70. data[f.FieldMap.resolve(FieldKeyFunc)] = entry.Caller.Function
  71. data[f.FieldMap.resolve(FieldKeyFile)] = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
  72. }
  73. var b *bytes.Buffer
  74. if entry.Buffer != nil {
  75. b = entry.Buffer
  76. } else {
  77. b = &bytes.Buffer{}
  78. }
  79. encoder := json.NewEncoder(b)
  80. if f.PrettyPrint {
  81. encoder.SetIndent("", " ")
  82. }
  83. if err := encoder.Encode(data); err != nil {
  84. return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
  85. }
  86. return b.Bytes(), nil
  87. }