json_logger.go 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. package log
  2. import (
  3. "encoding"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "reflect"
  8. )
  9. type jsonLogger struct {
  10. io.Writer
  11. }
  12. // NewJSONLogger returns a Logger that encodes keyvals to the Writer as a
  13. // single JSON object. Each log event produces no more than one call to
  14. // w.Write. The passed Writer must be safe for concurrent use by multiple
  15. // goroutines if the returned Logger will be used concurrently.
  16. func NewJSONLogger(w io.Writer) Logger {
  17. return &jsonLogger{w}
  18. }
  19. func (l *jsonLogger) Log(keyvals ...interface{}) error {
  20. n := (len(keyvals) + 1) / 2 // +1 to handle case when len is odd
  21. m := make(map[string]interface{}, n)
  22. for i := 0; i < len(keyvals); i += 2 {
  23. k := keyvals[i]
  24. var v interface{} = ErrMissingValue
  25. if i+1 < len(keyvals) {
  26. v = keyvals[i+1]
  27. }
  28. merge(m, k, v)
  29. }
  30. enc := json.NewEncoder(l.Writer)
  31. enc.SetEscapeHTML(false)
  32. return enc.Encode(m)
  33. }
  34. func merge(dst map[string]interface{}, k, v interface{}) {
  35. var key string
  36. switch x := k.(type) {
  37. case string:
  38. key = x
  39. case fmt.Stringer:
  40. key = safeString(x)
  41. default:
  42. key = fmt.Sprint(x)
  43. }
  44. // We want json.Marshaler and encoding.TextMarshaller to take priority over
  45. // err.Error() and v.String(). But json.Marshall (called later) does that by
  46. // default so we force a no-op if it's one of those 2 case.
  47. switch x := v.(type) {
  48. case json.Marshaler:
  49. case encoding.TextMarshaler:
  50. case error:
  51. v = safeError(x)
  52. case fmt.Stringer:
  53. v = safeString(x)
  54. }
  55. dst[key] = v
  56. }
  57. func safeString(str fmt.Stringer) (s string) {
  58. defer func() {
  59. if panicVal := recover(); panicVal != nil {
  60. if v := reflect.ValueOf(str); v.Kind() == reflect.Ptr && v.IsNil() {
  61. s = "NULL"
  62. } else {
  63. panic(panicVal)
  64. }
  65. }
  66. }()
  67. s = str.String()
  68. return
  69. }
  70. func safeError(err error) (s interface{}) {
  71. defer func() {
  72. if panicVal := recover(); panicVal != nil {
  73. if v := reflect.ValueOf(err); v.Kind() == reflect.Ptr && v.IsNil() {
  74. s = nil
  75. } else {
  76. panic(panicVal)
  77. }
  78. }
  79. }()
  80. s = err.Error()
  81. return
  82. }