logger.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. package logging
  2. import (
  3. "fmt"
  4. "io"
  5. "log"
  6. "os"
  7. "strings"
  8. "sync"
  9. )
  10. // Use this abstraction to ensure thread-safe access to the logger's io.Writer
  11. // (which could change at runtime)
  12. type loggerWriter struct {
  13. sync.RWMutex
  14. output io.Writer
  15. }
  16. func (lw *loggerWriter) SetOutput(output io.Writer) {
  17. lw.Lock()
  18. defer lw.Unlock()
  19. lw.output = output
  20. }
  21. func (lw *loggerWriter) Write(data []byte) (int, error) {
  22. lw.RLock()
  23. defer lw.RUnlock()
  24. return lw.output.Write(data)
  25. }
  26. // DefaultLeveledLogger encapsulates functionality for providing logging at
  27. // user-defined levels
  28. type DefaultLeveledLogger struct {
  29. level LogLevel
  30. writer *loggerWriter
  31. trace *log.Logger
  32. debug *log.Logger
  33. info *log.Logger
  34. warn *log.Logger
  35. err *log.Logger
  36. }
  37. // WithTraceLogger is a chainable configuration function which sets the
  38. // Trace-level logger
  39. func (ll *DefaultLeveledLogger) WithTraceLogger(log *log.Logger) *DefaultLeveledLogger {
  40. ll.trace = log
  41. return ll
  42. }
  43. // WithDebugLogger is a chainable configuration function which sets the
  44. // Debug-level logger
  45. func (ll *DefaultLeveledLogger) WithDebugLogger(log *log.Logger) *DefaultLeveledLogger {
  46. ll.debug = log
  47. return ll
  48. }
  49. // WithInfoLogger is a chainable configuration function which sets the
  50. // Info-level logger
  51. func (ll *DefaultLeveledLogger) WithInfoLogger(log *log.Logger) *DefaultLeveledLogger {
  52. ll.info = log
  53. return ll
  54. }
  55. // WithWarnLogger is a chainable configuration function which sets the
  56. // Warn-level logger
  57. func (ll *DefaultLeveledLogger) WithWarnLogger(log *log.Logger) *DefaultLeveledLogger {
  58. ll.warn = log
  59. return ll
  60. }
  61. // WithErrorLogger is a chainable configuration function which sets the
  62. // Error-level logger
  63. func (ll *DefaultLeveledLogger) WithErrorLogger(log *log.Logger) *DefaultLeveledLogger {
  64. ll.err = log
  65. return ll
  66. }
  67. // WithOutput is a chainable configuration function which sets the logger's
  68. // logging output to the supplied io.Writer
  69. func (ll *DefaultLeveledLogger) WithOutput(output io.Writer) *DefaultLeveledLogger {
  70. ll.writer.SetOutput(output)
  71. return ll
  72. }
  73. func (ll *DefaultLeveledLogger) logf(logger *log.Logger, level LogLevel, format string, args ...interface{}) {
  74. if ll.level.Get() < level {
  75. return
  76. }
  77. callDepth := 3 // this frame + wrapper func + caller
  78. msg := fmt.Sprintf(format, args...)
  79. if err := logger.Output(callDepth, msg); err != nil {
  80. fmt.Fprintf(os.Stderr, "Unable to log: %s", err)
  81. }
  82. }
  83. // SetLevel sets the logger's logging level
  84. func (ll *DefaultLeveledLogger) SetLevel(newLevel LogLevel) {
  85. ll.level.Set(newLevel)
  86. }
  87. // Trace emits the preformatted message if the logger is at or below LogLevelTrace
  88. func (ll *DefaultLeveledLogger) Trace(msg string) {
  89. ll.logf(ll.trace, LogLevelTrace, msg)
  90. }
  91. // Tracef formats and emits a message if the logger is at or below LogLevelTrace
  92. func (ll *DefaultLeveledLogger) Tracef(format string, args ...interface{}) {
  93. ll.logf(ll.trace, LogLevelTrace, format, args...)
  94. }
  95. // Debug emits the preformatted message if the logger is at or below LogLevelDebug
  96. func (ll *DefaultLeveledLogger) Debug(msg string) {
  97. ll.logf(ll.debug, LogLevelDebug, msg)
  98. }
  99. // Debugf formats and emits a message if the logger is at or below LogLevelDebug
  100. func (ll *DefaultLeveledLogger) Debugf(format string, args ...interface{}) {
  101. ll.logf(ll.debug, LogLevelDebug, format, args...)
  102. }
  103. // Info emits the preformatted message if the logger is at or below LogLevelInfo
  104. func (ll *DefaultLeveledLogger) Info(msg string) {
  105. ll.logf(ll.info, LogLevelInfo, msg)
  106. }
  107. // Infof formats and emits a message if the logger is at or below LogLevelInfo
  108. func (ll *DefaultLeveledLogger) Infof(format string, args ...interface{}) {
  109. ll.logf(ll.info, LogLevelInfo, format, args...)
  110. }
  111. // Warn emits the preformatted message if the logger is at or below LogLevelWarn
  112. func (ll *DefaultLeveledLogger) Warn(msg string) {
  113. ll.logf(ll.warn, LogLevelWarn, msg)
  114. }
  115. // Warnf formats and emits a message if the logger is at or below LogLevelWarn
  116. func (ll *DefaultLeveledLogger) Warnf(format string, args ...interface{}) {
  117. ll.logf(ll.warn, LogLevelWarn, format, args...)
  118. }
  119. // Error emits the preformatted message if the logger is at or below LogLevelError
  120. func (ll *DefaultLeveledLogger) Error(msg string) {
  121. ll.logf(ll.err, LogLevelError, msg)
  122. }
  123. // Errorf formats and emits a message if the logger is at or below LogLevelError
  124. func (ll *DefaultLeveledLogger) Errorf(format string, args ...interface{}) {
  125. ll.logf(ll.err, LogLevelError, format, args...)
  126. }
  127. // NewDefaultLeveledLoggerForScope returns a configured LeveledLogger
  128. func NewDefaultLeveledLoggerForScope(scope string, level LogLevel, writer io.Writer) *DefaultLeveledLogger {
  129. if writer == nil {
  130. writer = os.Stdout
  131. }
  132. logger := &DefaultLeveledLogger{
  133. writer: &loggerWriter{output: writer},
  134. level: level,
  135. }
  136. return logger.
  137. WithTraceLogger(log.New(logger.writer, fmt.Sprintf("%s TRACE: ", scope), log.Lmicroseconds|log.Lshortfile)).
  138. WithDebugLogger(log.New(logger.writer, fmt.Sprintf("%s DEBUG: ", scope), log.Lmicroseconds|log.Lshortfile)).
  139. WithInfoLogger(log.New(logger.writer, fmt.Sprintf("%s INFO: ", scope), log.LstdFlags)).
  140. WithWarnLogger(log.New(logger.writer, fmt.Sprintf("%s WARNING: ", scope), log.LstdFlags)).
  141. WithErrorLogger(log.New(logger.writer, fmt.Sprintf("%s ERROR: ", scope), log.LstdFlags))
  142. }
  143. // DefaultLoggerFactory define levels by scopes and creates new DefaultLeveledLogger
  144. type DefaultLoggerFactory struct {
  145. Writer io.Writer
  146. DefaultLogLevel LogLevel
  147. ScopeLevels map[string]LogLevel
  148. }
  149. // NewDefaultLoggerFactory creates a new DefaultLoggerFactory
  150. func NewDefaultLoggerFactory() *DefaultLoggerFactory {
  151. factory := DefaultLoggerFactory{}
  152. factory.DefaultLogLevel = LogLevelError
  153. factory.ScopeLevels = make(map[string]LogLevel)
  154. factory.Writer = os.Stdout
  155. logLevels := map[string]LogLevel{
  156. "DISABLE": LogLevelDisabled,
  157. "ERROR": LogLevelError,
  158. "WARN": LogLevelWarn,
  159. "INFO": LogLevelInfo,
  160. "DEBUG": LogLevelDebug,
  161. "TRACE": LogLevelTrace,
  162. }
  163. for name, level := range logLevels {
  164. env := os.Getenv(fmt.Sprintf("PION_LOG_%s", name))
  165. if env == "" {
  166. env = os.Getenv(fmt.Sprintf("PIONS_LOG_%s", name))
  167. }
  168. if env == "" {
  169. continue
  170. }
  171. if strings.ToLower(env) == "all" {
  172. factory.DefaultLogLevel = level
  173. continue
  174. }
  175. scopes := strings.Split(strings.ToLower(env), ",")
  176. for _, scope := range scopes {
  177. factory.ScopeLevels[scope] = level
  178. }
  179. }
  180. return &factory
  181. }
  182. // NewLogger returns a configured LeveledLogger for the given , argsscope
  183. func (f *DefaultLoggerFactory) NewLogger(scope string) LeveledLogger {
  184. logLevel := f.DefaultLogLevel
  185. if f.ScopeLevels != nil {
  186. scopeLevel, found := f.ScopeLevels[scope]
  187. if found {
  188. logLevel = scopeLevel
  189. }
  190. }
  191. return NewDefaultLeveledLoggerForScope(scope, logLevel, f.Writer)
  192. }