~juju-qa/ubuntu/xenial/juju/xenial-2.0-beta3

« back to all changes in this revision

Viewing changes to src/gopkg.in/inconshreveable/log15.v2/ext/handler.go

  • Committer: Martin Packman
  • Date: 2016-03-30 19:31:08 UTC
  • mfrom: (1.1.41)
  • Revision ID: martin.packman@canonical.com-20160330193108-h9iz3ak334uk0z5r
Merge new upstream source 2.0~beta3

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
package ext
2
 
 
3
 
import (
4
 
        "os"
5
 
        "sync"
6
 
        "sync/atomic"
7
 
        "unsafe"
8
 
 
9
 
        log "gopkg.in/inconshreveable/log15.v2"
10
 
)
11
 
 
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).
16
 
//
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:
21
 
//
22
 
//     logger := logext.EscalateErrHandler(
23
 
//         log.LvlFilterHandler(log.LvlInfo, log.StdoutHandler))
24
 
//
25
 
//     reply, err := redisConn.Do("SET", "foo", "bar")
26
 
//     logger.Debug("Wrote value to redis", "reply", reply, "err", err)
27
 
//     if err != nil {
28
 
//         return err
29
 
//     }
30
 
//
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 {
36
 
                                        r.Lvl = log.LvlError
37
 
                                        break
38
 
                                }
39
 
                        }
40
 
                }
41
 
                return h.Log(r)
42
 
        })
43
 
}
44
 
 
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 {
52
 
        return &Speculative{
53
 
                handler: h,
54
 
                recs:    make([]*log.Record, size),
55
 
        }
56
 
}
57
 
 
58
 
type Speculative struct {
59
 
        mu      sync.Mutex
60
 
        idx     int
61
 
        recs    []*log.Record
62
 
        handler log.Handler
63
 
        full    bool
64
 
}
65
 
 
66
 
func (h *Speculative) Log(r *log.Record) error {
67
 
        h.mu.Lock()
68
 
        defer h.mu.Unlock()
69
 
        h.recs[h.idx] = r
70
 
        h.idx = (h.idx + 1) % len(h.recs)
71
 
        h.full = h.full || h.idx == 0
72
 
        return nil
73
 
}
74
 
 
75
 
func (h *Speculative) Flush() {
76
 
        recs := make([]*log.Record, 0)
77
 
        func() {
78
 
                h.mu.Lock()
79
 
                defer h.mu.Unlock()
80
 
                if h.full {
81
 
                        recs = append(recs, h.recs[h.idx:]...)
82
 
                }
83
 
                recs = append(recs, h.recs[:h.idx]...)
84
 
 
85
 
                // reset state
86
 
                h.full = false
87
 
                h.idx = 0
88
 
        }()
89
 
 
90
 
        // don't hold the lock while we flush to the wrapped handler
91
 
        for _, r := range recs {
92
 
                h.handler.Log(r)
93
 
        }
94
 
}
95
 
 
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 {
102
 
        hs := new(HotSwap)
103
 
        hs.Swap(h)
104
 
        return hs
105
 
}
106
 
 
107
 
type HotSwap struct {
108
 
        handler unsafe.Pointer
109
 
}
110
 
 
111
 
func (h *HotSwap) Log(r *log.Record) error {
112
 
        return (*(*log.Handler)(atomic.LoadPointer(&h.handler))).Log(r)
113
 
}
114
 
 
115
 
func (h *HotSwap) Swap(newHandler log.Handler) {
116
 
        atomic.StorePointer(&h.handler, unsafe.Pointer(&newHandler))
117
 
}
118
 
 
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 {
124
 
                err := h.Log(r)
125
 
                if r.Lvl == log.LvlCrit {
126
 
                        os.Exit(1)
127
 
                }
128
 
                return err
129
 
        })
130
 
}