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.

101 lines
2.4 KiB

  1. package log
  2. import (
  3. "fmt"
  4. "io"
  5. "os"
  6. "strings"
  7. "github.com/rs/zerolog"
  8. )
  9. var _ Logger = (*defaultLogger)(nil)
  10. type defaultLogger struct {
  11. zerolog.Logger
  12. trace bool
  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, trace bool) (Logger, error) {
  23. var logWriter io.Writer
  24. switch strings.ToLower(format) {
  25. case LogFormatPlain, LogFormatText:
  26. logWriter = zerolog.ConsoleWriter{Out: os.Stderr}
  27. case LogFormatJSON:
  28. logWriter = os.Stderr
  29. default:
  30. return nil, fmt.Errorf("unsupported log format: %s", format)
  31. }
  32. logLevel, err := zerolog.ParseLevel(level)
  33. if err != nil {
  34. return nil, fmt.Errorf("failed to parse log level (%s): %w", level, err)
  35. }
  36. // make the writer thread-safe
  37. logWriter = newSyncWriter(logWriter)
  38. return defaultLogger{
  39. Logger: zerolog.New(logWriter).Level(logLevel).With().Timestamp().Logger(),
  40. trace: trace,
  41. }, nil
  42. }
  43. // MustNewDefaultLogger delegates a call NewDefaultLogger where it panics on
  44. // error.
  45. func MustNewDefaultLogger(format, level string, trace bool) Logger {
  46. logger, err := NewDefaultLogger(format, level, trace)
  47. if err != nil {
  48. panic(err)
  49. }
  50. return logger
  51. }
  52. func (l defaultLogger) Info(msg string, keyVals ...interface{}) {
  53. l.Logger.Info().Fields(getLogFields(keyVals...)).Msg(msg)
  54. }
  55. func (l defaultLogger) Error(msg string, keyVals ...interface{}) {
  56. e := l.Logger.Error()
  57. if l.trace {
  58. e = e.Stack()
  59. }
  60. e.Fields(getLogFields(keyVals...)).Msg(msg)
  61. }
  62. func (l defaultLogger) Debug(msg string, keyVals ...interface{}) {
  63. l.Logger.Debug().Fields(getLogFields(keyVals...)).Msg(msg)
  64. }
  65. func (l defaultLogger) With(keyVals ...interface{}) Logger {
  66. return defaultLogger{
  67. Logger: l.Logger.With().Fields(getLogFields(keyVals...)).Logger(),
  68. trace: l.trace,
  69. }
  70. }
  71. func getLogFields(keyVals ...interface{}) map[string]interface{} {
  72. if len(keyVals)%2 != 0 {
  73. return nil
  74. }
  75. fields := make(map[string]interface{}, len(keyVals))
  76. for i := 0; i < len(keyVals); i += 2 {
  77. fields[fmt.Sprint(keyVals[i])] = keyVals[i+1]
  78. }
  79. return fields
  80. }