9
log "gopkg.in/inconshreveable/log15.v2"
12
// EscalateErrHandler wraps another handler and passes all records through
13
// unchanged except if the logged context contains a non-nil error
14
// value in its context. In that case, the record's level is raised
15
// to LvlError unless it was already more serious (LvlCrit).
17
// This allows you to log the result of all functions for debugging
18
// and still capture error conditions when in production with a single
19
// log line. As an example, the following the log record will be written
20
// out only if there was an error writing a value to redis:
22
// logger := logext.EscalateErrHandler(
23
// log.LvlFilterHandler(log.LvlInfo, log.StdoutHandler))
25
// reply, err := redisConn.Do("SET", "foo", "bar")
26
// logger.Debug("Wrote value to redis", "reply", reply, "err", err)
31
func EscalateErrHandler(h log.Handler) log.Handler {
32
return log.FuncHandler(func(r *log.Record) error {
33
if r.Lvl > log.LvlError {
34
for i := 1; i < len(r.Ctx); i++ {
35
if v, ok := r.Ctx[i].(error); ok && v != nil {
45
// SpeculativeHandler is a handler for speculative logging. It
46
// keeps a ring buffer of the given size full of the last events
47
// logged into it. When Flush is called, all buffered log records
48
// are written to the wrapped handler. This is extremely for
49
// continuosly capturing debug level output, but only flushing those
50
// log records if an exceptional condition is encountered.
51
func SpeculativeHandler(size int, h log.Handler) *Speculative {
54
recs: make([]*log.Record, size),
58
type Speculative struct {
66
func (h *Speculative) Log(r *log.Record) error {
70
h.idx = (h.idx + 1) % len(h.recs)
71
h.full = h.full || h.idx == 0
75
func (h *Speculative) Flush() {
76
recs := make([]*log.Record, 0)
81
recs = append(recs, h.recs[h.idx:]...)
83
recs = append(recs, h.recs[:h.idx]...)
90
// don't hold the lock while we flush to the wrapped handler
91
for _, r := range recs {
96
// HotSwapHandler wraps another handler that may swapped out
97
// dynamically at runtime in a thread-safe fashion.
98
// HotSwapHandler is the same functionality
99
// used to implement the SetHandler method for the default
100
// implementation of Logger.
101
func HotSwapHandler(h log.Handler) *HotSwap {
107
type HotSwap struct {
108
handler unsafe.Pointer
111
func (h *HotSwap) Log(r *log.Record) error {
112
return (*(*log.Handler)(atomic.LoadPointer(&h.handler))).Log(r)
115
func (h *HotSwap) Swap(newHandler log.Handler) {
116
atomic.StorePointer(&h.handler, unsafe.Pointer(&newHandler))
119
// FatalHandler makes critical errors exit the program
120
// immediately, much like the log.Fatal* methods from the
121
// standard log package
122
func FatalHandler(h log.Handler) log.Handler {
123
return log.FuncHandler(func(r *log.Record) error {
125
if r.Lvl == log.LvlCrit {