handler.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. package log
  2. import (
  3. "fmt"
  4. "io"
  5. "net"
  6. "os"
  7. "reflect"
  8. "sync"
  9. "github.com/go-stack/stack"
  10. )
  11. // A Logger prints its log records by writing to a Handler.
  12. // The Handler interface defines where and how log records are written.
  13. // Handlers are composable, providing you great flexibility in combining
  14. // them to achieve the logging structure that suits your applications.
  15. type Handler interface {
  16. Log(r *Record) error
  17. }
  18. // FuncHandler returns a Handler that logs records with the given
  19. // function.
  20. func FuncHandler(fn func(r *Record) error) Handler {
  21. return funcHandler(fn)
  22. }
  23. type funcHandler func(r *Record) error
  24. func (h funcHandler) Log(r *Record) error {
  25. return h(r)
  26. }
  27. // StreamHandler writes log records to an io.Writer
  28. // with the given format. StreamHandler can be used
  29. // to easily begin writing log records to other
  30. // outputs.
  31. //
  32. // StreamHandler wraps itself with LazyHandler and SyncHandler
  33. // to evaluate Lazy objects and perform safe concurrent writes.
  34. func StreamHandler(wr io.Writer, fmtr Format) Handler {
  35. h := FuncHandler(func(r *Record) error {
  36. _, err := wr.Write(fmtr.Format(r))
  37. return err
  38. })
  39. return LazyHandler(SyncHandler(h))
  40. }
  41. // SyncHandler can be wrapped around a handler to guarantee that
  42. // only a single Log operation can proceed at a time. It's necessary
  43. // for thread-safe concurrent writes.
  44. func SyncHandler(h Handler) Handler {
  45. var mu sync.Mutex
  46. return FuncHandler(func(r *Record) error {
  47. defer mu.Unlock()
  48. mu.Lock()
  49. return h.Log(r)
  50. })
  51. }
  52. // FileHandler returns a handler which writes log records to the give file
  53. // using the given format. If the path
  54. // already exists, FileHandler will append to the given file. If it does not,
  55. // FileHandler will create the file with mode 0644.
  56. func FileHandler(path string, fmtr Format) (Handler, error) {
  57. f, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
  58. if err != nil {
  59. return nil, err
  60. }
  61. return closingHandler{f, StreamHandler(f, fmtr)}, nil
  62. }
  63. // NetHandler opens a socket to the given address and writes records
  64. // over the connection.
  65. func NetHandler(network, addr string, fmtr Format) (Handler, error) {
  66. conn, err := net.Dial(network, addr)
  67. if err != nil {
  68. return nil, err
  69. }
  70. return closingHandler{conn, StreamHandler(conn, fmtr)}, nil
  71. }
  72. // XXX: closingHandler is essentially unused at the moment
  73. // it's meant for a future time when the Handler interface supports
  74. // a possible Close() operation
  75. type closingHandler struct {
  76. io.WriteCloser
  77. Handler
  78. }
  79. func (h *closingHandler) Close() error {
  80. return h.WriteCloser.Close()
  81. }
  82. // CallerFileHandler returns a Handler that adds the line number and file of
  83. // the calling function to the context with key "caller".
  84. func CallerFileHandler(h Handler) Handler {
  85. return FuncHandler(func(r *Record) error {
  86. r.Ctx = append(r.Ctx, "caller", fmt.Sprint(r.Call))
  87. return h.Log(r)
  88. })
  89. }
  90. // CallerFuncHandler returns a Handler that adds the calling function name to
  91. // the context with key "fn".
  92. func CallerFuncHandler(h Handler) Handler {
  93. return FuncHandler(func(r *Record) error {
  94. r.Ctx = append(r.Ctx, "fn", fmt.Sprintf("%+n", r.Call))
  95. return h.Log(r)
  96. })
  97. }
  98. // CallerStackHandler returns a Handler that adds a stack trace to the context
  99. // with key "stack". The stack trace is formated as a space separated list of
  100. // call sites inside matching []'s. The most recent call site is listed first.
  101. // Each call site is formatted according to format. See the documentation of
  102. // package github.com/go-stack/stack for the list of supported formats.
  103. func CallerStackHandler(format string, h Handler) Handler {
  104. return FuncHandler(func(r *Record) error {
  105. s := stack.Trace().TrimBelow(r.Call).TrimRuntime()
  106. if len(s) > 0 {
  107. r.Ctx = append(r.Ctx, "stack", fmt.Sprintf(format, s))
  108. }
  109. return h.Log(r)
  110. })
  111. }
  112. // FilterHandler returns a Handler that only writes records to the
  113. // wrapped Handler if the given function evaluates true. For example,
  114. // to only log records where the 'err' key is not nil:
  115. //
  116. // logger.SetHandler(FilterHandler(func(r *Record) bool {
  117. // for i := 0; i < len(r.Ctx); i += 2 {
  118. // if r.Ctx[i] == "err" {
  119. // return r.Ctx[i+1] != nil
  120. // }
  121. // }
  122. // return false
  123. // }, h))
  124. //
  125. func FilterHandler(fn func(r *Record) bool, h Handler) Handler {
  126. return FuncHandler(func(r *Record) error {
  127. if fn(r) {
  128. return h.Log(r)
  129. }
  130. return nil
  131. })
  132. }
  133. // MatchFilterHandler returns a Handler that only writes records
  134. // to the wrapped Handler if the given key in the logged
  135. // context matches the value. For example, to only log records
  136. // from your ui package:
  137. //
  138. // log.MatchFilterHandler("pkg", "app/ui", log.StdoutHandler)
  139. //
  140. func MatchFilterHandler(key string, value interface{}, h Handler) Handler {
  141. return FilterHandler(func(r *Record) (pass bool) {
  142. switch key {
  143. case r.KeyNames.Lvl:
  144. return r.Lvl == value
  145. case r.KeyNames.Time:
  146. return r.Time == value
  147. case r.KeyNames.Msg:
  148. return r.Msg == value
  149. }
  150. for i := 0; i < len(r.Ctx); i += 2 {
  151. if r.Ctx[i] == key {
  152. return r.Ctx[i+1] == value
  153. }
  154. }
  155. return false
  156. }, h)
  157. }
  158. // LvlFilterHandler returns a Handler that only writes
  159. // records which are less than the given verbosity
  160. // level to the wrapped Handler. For example, to only
  161. // log Error/Crit records:
  162. //
  163. // log.LvlFilterHandler(log.LvlError, log.StdoutHandler)
  164. //
  165. func LvlFilterHandler(maxLvl Lvl, h Handler) Handler {
  166. return FilterHandler(func(r *Record) (pass bool) {
  167. return r.Lvl <= maxLvl
  168. }, h)
  169. }
  170. // A MultiHandler dispatches any write to each of its handlers.
  171. // This is useful for writing different types of log information
  172. // to different locations. For example, to log to a file and
  173. // standard error:
  174. //
  175. // log.MultiHandler(
  176. // log.Must.FileHandler("/var/log/app.log", log.LogfmtFormat()),
  177. // log.StderrHandler)
  178. //
  179. func MultiHandler(hs ...Handler) Handler {
  180. return FuncHandler(func(r *Record) error {
  181. for _, h := range hs {
  182. // what to do about failures?
  183. h.Log(r)
  184. }
  185. return nil
  186. })
  187. }
  188. // A FailoverHandler writes all log records to the first handler
  189. // specified, but will failover and write to the second handler if
  190. // the first handler has failed, and so on for all handlers specified.
  191. // For example you might want to log to a network socket, but failover
  192. // to writing to a file if the network fails, and then to
  193. // standard out if the file write fails:
  194. //
  195. // log.FailoverHandler(
  196. // log.Must.NetHandler("tcp", ":9090", log.JsonFormat()),
  197. // log.Must.FileHandler("/var/log/app.log", log.LogfmtFormat()),
  198. // log.StdoutHandler)
  199. //
  200. // All writes that do not go to the first handler will add context with keys of
  201. // the form "failover_err_{idx}" which explain the error encountered while
  202. // trying to write to the handlers before them in the list.
  203. func FailoverHandler(hs ...Handler) Handler {
  204. return FuncHandler(func(r *Record) error {
  205. var err error
  206. for i, h := range hs {
  207. err = h.Log(r)
  208. if err == nil {
  209. return nil
  210. } else {
  211. r.Ctx = append(r.Ctx, fmt.Sprintf("failover_err_%d", i), err)
  212. }
  213. }
  214. return err
  215. })
  216. }
  217. // ChannelHandler writes all records to the given channel.
  218. // It blocks if the channel is full. Useful for async processing
  219. // of log messages, it's used by BufferedHandler.
  220. func ChannelHandler(recs chan<- *Record) Handler {
  221. return FuncHandler(func(r *Record) error {
  222. recs <- r
  223. return nil
  224. })
  225. }
  226. // BufferedHandler writes all records to a buffered
  227. // channel of the given size which flushes into the wrapped
  228. // handler whenever it is available for writing. Since these
  229. // writes happen asynchronously, all writes to a BufferedHandler
  230. // never return an error and any errors from the wrapped handler are ignored.
  231. func BufferedHandler(bufSize int, h Handler) Handler {
  232. recs := make(chan *Record, bufSize)
  233. go func() {
  234. for m := range recs {
  235. _ = h.Log(m)
  236. }
  237. }()
  238. return ChannelHandler(recs)
  239. }
  240. // LazyHandler writes all values to the wrapped handler after evaluating
  241. // any lazy functions in the record's context. It is already wrapped
  242. // around StreamHandler and SyslogHandler in this library, you'll only need
  243. // it if you write your own Handler.
  244. func LazyHandler(h Handler) Handler {
  245. return FuncHandler(func(r *Record) error {
  246. // go through the values (odd indices) and reassign
  247. // the values of any lazy fn to the result of its execution
  248. hadErr := false
  249. for i := 1; i < len(r.Ctx); i += 2 {
  250. lz, ok := r.Ctx[i].(Lazy)
  251. if ok {
  252. v, err := evaluateLazy(lz)
  253. if err != nil {
  254. hadErr = true
  255. r.Ctx[i] = err
  256. } else {
  257. if cs, ok := v.(stack.CallStack); ok {
  258. v = cs.TrimBelow(r.Call).TrimRuntime()
  259. }
  260. r.Ctx[i] = v
  261. }
  262. }
  263. }
  264. if hadErr {
  265. r.Ctx = append(r.Ctx, errorKey, "bad lazy")
  266. }
  267. return h.Log(r)
  268. })
  269. }
  270. func evaluateLazy(lz Lazy) (interface{}, error) {
  271. t := reflect.TypeOf(lz.Fn)
  272. if t.Kind() != reflect.Func {
  273. return nil, fmt.Errorf("INVALID_LAZY, not func: %+v", lz.Fn)
  274. }
  275. if t.NumIn() > 0 {
  276. return nil, fmt.Errorf("INVALID_LAZY, func takes args: %+v", lz.Fn)
  277. }
  278. if t.NumOut() == 0 {
  279. return nil, fmt.Errorf("INVALID_LAZY, no func return val: %+v", lz.Fn)
  280. }
  281. value := reflect.ValueOf(lz.Fn)
  282. results := value.Call([]reflect.Value{})
  283. if len(results) == 1 {
  284. return results[0].Interface(), nil
  285. } else {
  286. values := make([]interface{}, len(results))
  287. for i, v := range results {
  288. values[i] = v.Interface()
  289. }
  290. return values, nil
  291. }
  292. }
  293. // DiscardHandler reports success for all writes but does nothing.
  294. // It is useful for dynamically disabling logging at runtime via
  295. // a Logger's SetHandler method.
  296. func DiscardHandler() Handler {
  297. return FuncHandler(func(r *Record) error {
  298. return nil
  299. })
  300. }
  301. // The Must object provides the following Handler creation functions
  302. // which instead of returning an error parameter only return a Handler
  303. // and panic on failure: FileHandler, NetHandler, SyslogHandler, SyslogNetHandler
  304. var Must muster
  305. func must(h Handler, err error) Handler {
  306. if err != nil {
  307. panic(err)
  308. }
  309. return h
  310. }
  311. type muster struct{}
  312. func (m muster) FileHandler(path string, fmtr Format) Handler {
  313. return must(FileHandler(path, fmtr))
  314. }
  315. func (m muster) NetHandler(network, addr string, fmtr Format) Handler {
  316. return must(NetHandler(network, addr, fmtr))
  317. }