handler.go 13 KB

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