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.

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