/usr/share/gocode/src/github.com/tendermint/log15/ext/handler.go is in golang-github-tendermint-log15-dev 2.3-67-g9545b24-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | package ext
import (
"os"
"sync"
"sync/atomic"
"unsafe"
log "github.com/tendermint/log15"
)
// EscalateErrHandler wraps another handler and passes all records through
// unchanged except if the logged context contains a non-nil error
// value in its context. In that case, the record's level is raised
// to LvlError unless it was already more serious (LvlCrit).
//
// This allows you to log the result of all functions for debugging
// and still capture error conditions when in production with a single
// log line. As an example, the following the log record will be written
// out only if there was an error writing a value to redis:
//
// logger := logext.EscalateErrHandler(
// log.LvlFilterHandler(log.LvlInfo, log.StdoutHandler))
//
// reply, err := redisConn.Do("SET", "foo", "bar")
// logger.Debug("Wrote value to redis", "reply", reply, "err", err)
// if err != nil {
// return err
// }
//
func EscalateErrHandler(h log.Handler) log.Handler {
return log.FuncHandler(func(r *log.Record) error {
if r.Lvl > log.LvlError {
for i := 1; i < len(r.Ctx); i++ {
if v, ok := r.Ctx[i].(error); ok && v != nil {
r.Lvl = log.LvlError
break
}
}
}
return h.Log(r)
})
}
// SpeculativeHandler is a handler for speculative logging. It
// keeps a ring buffer of the given size full of the last events
// logged into it. When Flush is called, all buffered log records
// are written to the wrapped handler. This is extremely for
// continuosly capturing debug level output, but only flushing those
// log records if an exceptional condition is encountered.
func SpeculativeHandler(size int, h log.Handler) *Speculative {
return &Speculative{
handler: h,
recs: make([]*log.Record, size),
}
}
type Speculative struct {
mu sync.Mutex
idx int
recs []*log.Record
handler log.Handler
full bool
}
func (h *Speculative) Log(r *log.Record) error {
h.mu.Lock()
defer h.mu.Unlock()
h.recs[h.idx] = r
h.idx = (h.idx + 1) % len(h.recs)
h.full = h.full || h.idx == 0
return nil
}
func (h *Speculative) Flush() {
recs := make([]*log.Record, 0)
func() {
h.mu.Lock()
defer h.mu.Unlock()
if h.full {
recs = append(recs, h.recs[h.idx:]...)
}
recs = append(recs, h.recs[:h.idx]...)
// reset state
h.full = false
h.idx = 0
}()
// don't hold the lock while we flush to the wrapped handler
for _, r := range recs {
h.handler.Log(r)
}
}
// HotSwapHandler wraps another handler that may swapped out
// dynamically at runtime in a thread-safe fashion.
// HotSwapHandler is the same functionality
// used to implement the SetHandler method for the default
// implementation of Logger.
func HotSwapHandler(h log.Handler) *HotSwap {
hs := new(HotSwap)
hs.Swap(h)
return hs
}
type HotSwap struct {
handler unsafe.Pointer
}
func (h *HotSwap) Log(r *log.Record) error {
return (*(*log.Handler)(atomic.LoadPointer(&h.handler))).Log(r)
}
func (h *HotSwap) Swap(newHandler log.Handler) {
atomic.StorePointer(&h.handler, unsafe.Pointer(&newHandler))
}
// FatalHandler makes critical errors exit the program
// immediately, much like the log.Fatal* methods from the
// standard log package
func FatalHandler(h log.Handler) log.Handler {
return log.FuncHandler(func(r *log.Record) error {
err := h.Log(r)
if r.Lvl == log.LvlCrit {
os.Exit(1)
}
return err
})
}
|