Simple configurable logging tool
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.

220 lines
6.0KB

  1. package log
  2. import (
  3. "fmt"
  4. golog "log"
  5. "os"
  6. "runtime"
  7. "strings"
  8. )
  9. // Level indicates the level a log should be classified at
  10. type Level int
  11. // The possible levels a log can have
  12. const (
  13. LevelDebug Level = iota + 1
  14. LevelInfo
  15. LevelWarn
  16. LevelError
  17. )
  18. var levelString = map[Level]string{LevelDebug: "[DBUG]", LevelInfo: "[INFO]", LevelWarn: "[WARN]", LevelError: "[ERR ]"}
  19. // Logger is a go Logger wrapper that adds log levels and pattern filtering
  20. // It allows high level 'log level' filtering broadly
  21. // It allows allows two addition levels of filtering:
  22. // everythingFrom which allows inclusion of packages/patterns along with general logging
  23. // nothingExcept which allows focusing on just listed areas
  24. type Logger struct {
  25. logger *golog.Logger
  26. level Level
  27. nothingExceptPatterns []string
  28. everythingFromPatterns []string
  29. excludeFromPatterns []string
  30. }
  31. // New returns a new Logger with a filter set to the supplied level
  32. func New(level Level) *Logger {
  33. return &Logger{logger: golog.New(os.Stderr, "", golog.Ldate|golog.Ltime), level: level, everythingFromPatterns: make([]string, 0), nothingExceptPatterns: make([]string, 0)}
  34. }
  35. // NewFile returns a new Logger that logs to the supplied file with a filter set to the supplied level
  36. func NewFile(level Level, filename string) (*Logger, error) {
  37. logfile, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
  38. if err != nil {
  39. return nil, err
  40. }
  41. return &Logger{logger: golog.New(logfile, "", golog.Ldate|golog.Ltime), level: level, everythingFromPatterns: make([]string, 0), nothingExceptPatterns: make([]string, 0)}, nil
  42. }
  43. var std = New(LevelWarn)
  44. // SetStd sets the default logger all other functions use
  45. func SetStd(logger *Logger) {
  46. std = logger
  47. }
  48. // filter
  49. func (l *Logger) filter(level Level) bool {
  50. _, file, _, ok := runtime.Caller(3)
  51. if !ok {
  52. file = "???"
  53. }
  54. for _, pattern := range l.excludeFromPatterns {
  55. if strings.Contains(file, pattern) {
  56. return false
  57. }
  58. }
  59. for _, pattern := range l.everythingFromPatterns {
  60. if strings.Contains(file, pattern) {
  61. return true
  62. }
  63. }
  64. for _, pattern := range l.nothingExceptPatterns {
  65. if strings.Contains(file, pattern) {
  66. return true
  67. }
  68. }
  69. if len(l.nothingExceptPatterns) > 0 {
  70. return false
  71. }
  72. return l.aboveLevel(level)
  73. }
  74. func (l *Logger) aboveLevel(level Level) bool {
  75. return level >= l.level
  76. }
  77. // SetLevel adjusts the output filter by logging level
  78. func (l *Logger) SetLevel(level Level) {
  79. l.level = level
  80. }
  81. // AddNothingExceptFilter enables strong filtering showing logs only for things on the approved list, adding this pattern to the list
  82. func (l *Logger) AddNothingExceptFilter(pattern string) {
  83. l.nothingExceptPatterns = append(l.nothingExceptPatterns, pattern)
  84. }
  85. // AddEverythingFromPattern adds a pattern to skip log level filtering, guaranteeing all logs matching the pattern are seen
  86. func (l *Logger) AddEverythingFromPattern(pattern string) {
  87. l.everythingFromPatterns = append(l.everythingFromPatterns, pattern)
  88. }
  89. // ExcludeFromPattern adds a pattern to exclude logs from
  90. func (l *Logger) ExcludeFromPattern(pattern string) {
  91. l.excludeFromPatterns = append(l.excludeFromPatterns, pattern)
  92. }
  93. func (l *Logger) header(level Level) string {
  94. _, file, _, ok := runtime.Caller(3)
  95. if !ok {
  96. file = "???"
  97. } else {
  98. short := file
  99. count := 0
  100. for i := len(file) - 1; i > 0; i-- {
  101. if file[i] == '/' {
  102. short = file[i+1:]
  103. count++
  104. if count == 2 {
  105. break
  106. }
  107. }
  108. }
  109. file = short
  110. }
  111. return file + " " + levelString[level] + " "
  112. }
  113. // Printf outputs the format and variables, assuming it passes the filter levels
  114. func (l *Logger) Printf(level Level, format string, v ...interface{}) {
  115. if l.filter(level) {
  116. l.logger.Output(3, l.header(level)+fmt.Sprintf(format, v...))
  117. }
  118. }
  119. // Println outputs the variables assuming the filter levels are passed
  120. func (l *Logger) Println(level Level, v ...interface{}) {
  121. if l.filter(level) {
  122. l.logger.Output(3, l.header(level)+fmt.Sprintln(v...))
  123. }
  124. }
  125. // SetLevel changes the filtering level of the system logger
  126. func SetLevel(level Level) {
  127. std.SetLevel(level)
  128. }
  129. // AddNothingExceptFilter enables strong filtering showing logs only for things on the approved list, adding this pattern to the list
  130. func AddNothingExceptFilter(pattern string) {
  131. std.AddNothingExceptFilter(pattern)
  132. }
  133. // AddEverythingFromPattern adds a pattern to skip log level filtering, guaranteeing all logs matching the pattern are seen
  134. func AddEverythingFromPattern(pattern string) {
  135. std.AddEverythingFromPattern(pattern)
  136. }
  137. // ExcludeFromPattern adds a pattern to exclude logs from
  138. func ExcludeFromPattern(pattern string) {
  139. std.ExcludeFromPattern(pattern)
  140. }
  141. // Printf outputs the format with variables assuming it passes the filter level
  142. func Printf(level Level, format string, v ...interface{}) {
  143. std.Printf(level, format, v...)
  144. }
  145. // Println outputs the varibles assuming they pass the filter level
  146. func Println(level Level, v ...interface{}) {
  147. std.Println(level, v...)
  148. }
  149. // Debugf outputs the format and variables at the Debug level
  150. func Debugf(format string, v ...interface{}) {
  151. std.Printf(LevelDebug, format, v...)
  152. }
  153. // Infof outputs the format and variables at the Info level
  154. func Infof(format string, v ...interface{}) {
  155. std.Printf(LevelInfo, format, v...)
  156. }
  157. // Warnf outputs the format and variables at the Warning level
  158. func Warnf(format string, v ...interface{}) {
  159. std.Printf(LevelWarn, format, v...)
  160. }
  161. // Errorf outputs the format and variables at the Error level
  162. func Errorf(format string, v ...interface{}) {
  163. std.Printf(LevelError, format, v...)
  164. }
  165. // Debugln outputs the variables at the Debug level
  166. func Debugln(v ...interface{}) {
  167. std.Println(LevelDebug, v...)
  168. }
  169. // Infoln outputs the variables at the Info level
  170. func Infoln(v ...interface{}) {
  171. std.Println(LevelInfo, v...)
  172. }
  173. // Warnln outputs the variables at the Warn level
  174. func Warnln(v ...interface{}) {
  175. std.Println(LevelWarn, v...)
  176. }
  177. // Errorln outputs the variables at the Error level
  178. func Errorln(v ...interface{}) {
  179. std.Println(LevelError, v...)
  180. }