logger.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. package log15
  2. import (
  3. "fmt"
  4. "time"
  5. "github.com/go-stack/stack"
  6. )
  7. const timeKey = "t"
  8. const lvlKey = "lvl"
  9. const msgKey = "msg"
  10. const errorKey = "LOG15_ERROR"
  11. // Lvl is a type for predefined log levels.
  12. type Lvl int
  13. // List of predefined log Levels
  14. const (
  15. LvlCrit Lvl = iota
  16. LvlError
  17. LvlWarn
  18. LvlInfo
  19. LvlDebug
  20. )
  21. // Returns the name of a Lvl
  22. func (l Lvl) String() string {
  23. switch l {
  24. case LvlDebug:
  25. return "dbug"
  26. case LvlInfo:
  27. return "info"
  28. case LvlWarn:
  29. return "warn"
  30. case LvlError:
  31. return "eror"
  32. case LvlCrit:
  33. return "crit"
  34. default:
  35. panic("bad level")
  36. }
  37. }
  38. // LvlFromString returns the appropriate Lvl from a string name.
  39. // Useful for parsing command line args and configuration files.
  40. func LvlFromString(lvlString string) (Lvl, error) {
  41. switch lvlString {
  42. case "debug", "dbug":
  43. return LvlDebug, nil
  44. case "info":
  45. return LvlInfo, nil
  46. case "warn":
  47. return LvlWarn, nil
  48. case "error", "eror":
  49. return LvlError, nil
  50. case "crit":
  51. return LvlCrit, nil
  52. default:
  53. return LvlDebug, fmt.Errorf("Unknown level: %v", lvlString)
  54. }
  55. }
  56. // A Record is what a Logger asks its handler to write
  57. type Record struct {
  58. Time time.Time
  59. Lvl Lvl
  60. Msg string
  61. Ctx []interface{}
  62. Call stack.Call
  63. KeyNames RecordKeyNames
  64. }
  65. // RecordKeyNames are the predefined names of the log props used by the Logger interface.
  66. type RecordKeyNames struct {
  67. Time string
  68. Msg string
  69. Lvl string
  70. }
  71. // A Logger writes key/value pairs to a Handler
  72. type Logger interface {
  73. // New returns a new Logger that has this logger's context plus the given context
  74. New(ctx ...interface{}) Logger
  75. // GetHandler gets the handler associated with the logger.
  76. GetHandler() Handler
  77. // SetHandler updates the logger to write records to the specified handler.
  78. SetHandler(h Handler)
  79. // Log a message at the given level with context key/value pairs
  80. Debug(msg string, ctx ...interface{})
  81. Info(msg string, ctx ...interface{})
  82. Warn(msg string, ctx ...interface{})
  83. Error(msg string, ctx ...interface{})
  84. Crit(msg string, ctx ...interface{})
  85. }
  86. type logger struct {
  87. ctx []interface{}
  88. h *swapHandler
  89. }
  90. func (l *logger) write(msg string, lvl Lvl, ctx []interface{}) {
  91. l.h.Log(&Record{
  92. Time: time.Now(),
  93. Lvl: lvl,
  94. Msg: msg,
  95. Ctx: newContext(l.ctx, ctx),
  96. Call: stack.Caller(2),
  97. KeyNames: RecordKeyNames{
  98. Time: timeKey,
  99. Msg: msgKey,
  100. Lvl: lvlKey,
  101. },
  102. })
  103. }
  104. func (l *logger) New(ctx ...interface{}) Logger {
  105. child := &logger{newContext(l.ctx, ctx), new(swapHandler)}
  106. child.SetHandler(l.h)
  107. return child
  108. }
  109. func newContext(prefix []interface{}, suffix []interface{}) []interface{} {
  110. normalizedSuffix := normalize(suffix)
  111. newCtx := make([]interface{}, len(prefix)+len(normalizedSuffix))
  112. n := copy(newCtx, prefix)
  113. copy(newCtx[n:], normalizedSuffix)
  114. return newCtx
  115. }
  116. func (l *logger) Debug(msg string, ctx ...interface{}) {
  117. l.write(msg, LvlDebug, ctx)
  118. }
  119. func (l *logger) Info(msg string, ctx ...interface{}) {
  120. l.write(msg, LvlInfo, ctx)
  121. }
  122. func (l *logger) Warn(msg string, ctx ...interface{}) {
  123. l.write(msg, LvlWarn, ctx)
  124. }
  125. func (l *logger) Error(msg string, ctx ...interface{}) {
  126. l.write(msg, LvlError, ctx)
  127. }
  128. func (l *logger) Crit(msg string, ctx ...interface{}) {
  129. l.write(msg, LvlCrit, ctx)
  130. }
  131. func (l *logger) GetHandler() Handler {
  132. return l.h.Get()
  133. }
  134. func (l *logger) SetHandler(h Handler) {
  135. l.h.Swap(h)
  136. }
  137. func normalize(ctx []interface{}) []interface{} {
  138. // if the caller passed a Ctx object, then expand it
  139. if len(ctx) == 1 {
  140. if ctxMap, ok := ctx[0].(Ctx); ok {
  141. ctx = ctxMap.toArray()
  142. }
  143. }
  144. // ctx needs to be even because it's a series of key/value pairs
  145. // no one wants to check for errors on logging functions,
  146. // so instead of erroring on bad input, we'll just make sure
  147. // that things are the right length and users can fix bugs
  148. // when they see the output looks wrong
  149. if len(ctx)%2 != 0 {
  150. ctx = append(ctx, nil, errorKey, "Normalized odd number of arguments by adding nil")
  151. }
  152. return ctx
  153. }
  154. // Lazy allows you to defer calculation of a logged value that is expensive
  155. // to compute until it is certain that it must be evaluated with the given filters.
  156. //
  157. // Lazy may also be used in conjunction with a Logger's New() function
  158. // to generate a child logger which always reports the current value of changing
  159. // state.
  160. //
  161. // You may wrap any function which takes no arguments to Lazy. It may return any
  162. // number of values of any type.
  163. type Lazy struct {
  164. Fn interface{}
  165. }
  166. // Ctx is a map of key/value pairs to pass as context to a log function
  167. // Use this only if you really need greater safety around the arguments you pass
  168. // to the logging functions.
  169. type Ctx map[string]interface{}
  170. func (c Ctx) toArray() []interface{} {
  171. arr := make([]interface{}, len(c)*2)
  172. i := 0
  173. for k, v := range c {
  174. arr[i] = k
  175. arr[i+1] = v
  176. i += 2
  177. }
  178. return arr
  179. }