handler.go 11 KB

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