logger.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /*
  2. This Source Code Form is subject to the terms of the Mozilla Public
  3. License, v. 2.0. If a copy of the MPL was not distributed with this
  4. file, You can obtain one at https://mozilla.org/MPL/2.0/.
  5. */
  6. package logger
  7. import (
  8. "fmt"
  9. "io"
  10. "log"
  11. "os"
  12. "strings"
  13. )
  14. type LogLevel int
  15. const (
  16. LogLevelSilent LogLevel = iota
  17. LogLevelFatal
  18. LogLevelError
  19. LogLevelWarn
  20. LogLevelInfo
  21. LogLevelDebug
  22. )
  23. var logLevelPrefix = []string{
  24. "",
  25. "FATAL",
  26. "ERROR",
  27. "Warn",
  28. "",
  29. "debug",
  30. }
  31. const (
  32. LogLevelDefault = LogLevelWarn
  33. FlagsDefault = log.LstdFlags |
  34. log.LUTC |
  35. log.Lmsgprefix |
  36. log.Lmicroseconds
  37. )
  38. func NewLogger() *Logger {
  39. flags := FlagsDefault
  40. return &Logger{
  41. logger: log.New(os.Stderr, "", flags),
  42. debug: log.New(os.Stderr, "", flags|log.Lshortfile),
  43. level: LogLevelDefault,
  44. }
  45. }
  46. type Logger struct {
  47. logger *log.Logger
  48. debug *log.Logger
  49. level LogLevel
  50. context []string
  51. }
  52. func (l *Logger) Level() LogLevel {
  53. return l.level
  54. }
  55. func (l *Logger) SetLevel(level LogLevel) {
  56. l.level = level
  57. }
  58. func (l *Logger) Writer() io.Writer {
  59. return l.logger.Writer()
  60. }
  61. func (l *Logger) SetOutput(w io.Writer) {
  62. l.logger.SetOutput(w)
  63. l.debug.SetOutput(w)
  64. }
  65. func (l *Logger) Flags() int {
  66. return l.logger.Flags()
  67. }
  68. func (l *Logger) SetFlags(flags int) {
  69. l.logger.SetFlags(flags)
  70. l.debug.SetFlags(flags)
  71. }
  72. func (l *Logger) Push(s string) *Logger {
  73. // TODO Is it worth avoiding these allocations?
  74. next := *l
  75. next.context = make([]string, len(l.context))
  76. copy(next.context, l.context)
  77. next.context = append(next.context, s)
  78. return &next
  79. }
  80. func (l *Logger) logAs(
  81. level LogLevel,
  82. format string,
  83. msg []any,
  84. ) {
  85. if level > l.level {
  86. return
  87. }
  88. prefix := logLevelPrefix[level]
  89. logr := l.logger
  90. if level == LogLevelDebug {
  91. logr = l.debug
  92. }
  93. context := strings.Join(l.context, ": ")
  94. if len(context) > 0 {
  95. context += ": "
  96. }
  97. if prefix != "" {
  98. prefix = "[" + prefix + "]"
  99. }
  100. s := fmt.Sprintf(prefix+" "+context+format, msg...)
  101. logr.Output(3, s)
  102. }
  103. func (l *Logger) Fatal(format string, msg ...any) {
  104. l.logAs(LogLevelFatal, format, msg)
  105. os.Exit(1)
  106. }
  107. func (l *Logger) Error(format string, msg ...any) {
  108. l.logAs(LogLevelError, format, msg)
  109. }
  110. func (l *Logger) Warn(format string, msg ...any) {
  111. l.logAs(LogLevelWarn, format, msg)
  112. }
  113. func (l *Logger) Info(format string, msg ...any) {
  114. l.logAs(LogLevelInfo, format, msg)
  115. }
  116. func (l *Logger) Debug(format string, msg ...any) {
  117. l.logAs(LogLevelDebug, format, msg)
  118. }