You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

112 lines
2.6 KiB

  1. package log
  2. import (
  3. "fmt"
  4. "io"
  5. "os"
  6. "strings"
  7. "time"
  8. "github.com/rs/zerolog"
  9. )
  10. var _ Logger = (*defaultLogger)(nil)
  11. type defaultLogger struct {
  12. zerolog.Logger
  13. trace bool
  14. }
  15. // NewDefaultLogger returns a default logger that can be used within Tendermint
  16. // and that fulfills the Logger interface. The underlying logging provider is a
  17. // zerolog logger that supports typical log levels along with JSON and plain/text
  18. // log formats.
  19. //
  20. // Since zerolog supports typed structured logging and it is difficult to reflect
  21. // that in a generic interface, all logging methods accept a series of key/value
  22. // pair tuples, where the key must be a string.
  23. func NewDefaultLogger(format, level string, trace bool) (Logger, error) {
  24. var logWriter io.Writer
  25. switch strings.ToLower(format) {
  26. case LogFormatPlain, LogFormatText:
  27. logWriter = zerolog.ConsoleWriter{
  28. Out: os.Stderr,
  29. NoColor: true,
  30. TimeFormat: time.RFC3339,
  31. FormatLevel: func(i interface{}) string {
  32. if ll, ok := i.(string); ok {
  33. return strings.ToUpper(ll)
  34. }
  35. return "????"
  36. },
  37. }
  38. case LogFormatJSON:
  39. logWriter = os.Stderr
  40. default:
  41. return nil, fmt.Errorf("unsupported log format: %s", format)
  42. }
  43. logLevel, err := zerolog.ParseLevel(level)
  44. if err != nil {
  45. return nil, fmt.Errorf("failed to parse log level (%s): %w", level, err)
  46. }
  47. // make the writer thread-safe
  48. logWriter = newSyncWriter(logWriter)
  49. return defaultLogger{
  50. Logger: zerolog.New(logWriter).Level(logLevel).With().Timestamp().Logger(),
  51. trace: trace,
  52. }, nil
  53. }
  54. // MustNewDefaultLogger delegates a call NewDefaultLogger where it panics on
  55. // error.
  56. func MustNewDefaultLogger(format, level string, trace bool) Logger {
  57. logger, err := NewDefaultLogger(format, level, trace)
  58. if err != nil {
  59. panic(err)
  60. }
  61. return logger
  62. }
  63. func (l defaultLogger) Info(msg string, keyVals ...interface{}) {
  64. l.Logger.Info().Fields(getLogFields(keyVals...)).Msg(msg)
  65. }
  66. func (l defaultLogger) Error(msg string, keyVals ...interface{}) {
  67. e := l.Logger.Error()
  68. if l.trace {
  69. e = e.Stack()
  70. }
  71. e.Fields(getLogFields(keyVals...)).Msg(msg)
  72. }
  73. func (l defaultLogger) Debug(msg string, keyVals ...interface{}) {
  74. l.Logger.Debug().Fields(getLogFields(keyVals...)).Msg(msg)
  75. }
  76. func (l defaultLogger) With(keyVals ...interface{}) Logger {
  77. return defaultLogger{
  78. Logger: l.Logger.With().Fields(getLogFields(keyVals...)).Logger(),
  79. trace: l.trace,
  80. }
  81. }
  82. func getLogFields(keyVals ...interface{}) map[string]interface{} {
  83. if len(keyVals)%2 != 0 {
  84. return nil
  85. }
  86. fields := make(map[string]interface{}, len(keyVals))
  87. for i := 0; i < len(keyVals); i += 2 {
  88. fields[fmt.Sprint(keyVals[i])] = keyVals[i+1]
  89. }
  90. return fields
  91. }