...
1 package handlers
2
3 import (
4 "log"
5 "net/http"
6 "runtime/debug"
7 )
8
9
10 type RecoveryHandlerLogger interface {
11 Println(...interface{})
12 }
13
14 type recoveryHandler struct {
15 handler http.Handler
16 logger RecoveryHandlerLogger
17 printStack bool
18 }
19
20
21
22
23 type RecoveryOption func(http.Handler)
24
25 func parseRecoveryOptions(h http.Handler, opts ...RecoveryOption) http.Handler {
26 for _, option := range opts {
27 option(h)
28 }
29
30 return h
31 }
32
33
34
35
36
37
38
39
40
41
42
43
44
45 func RecoveryHandler(opts ...RecoveryOption) func(h http.Handler) http.Handler {
46 return func(h http.Handler) http.Handler {
47 r := &recoveryHandler{handler: h}
48 return parseRecoveryOptions(r, opts...)
49 }
50 }
51
52
53
54 func RecoveryLogger(logger RecoveryHandlerLogger) RecoveryOption {
55 return func(h http.Handler) {
56 r := h.(*recoveryHandler)
57 r.logger = logger
58 }
59 }
60
61
62
63 func PrintRecoveryStack(print bool) RecoveryOption {
64 return func(h http.Handler) {
65 r := h.(*recoveryHandler)
66 r.printStack = print
67 }
68 }
69
70 func (h recoveryHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
71 defer func() {
72 if err := recover(); err != nil {
73 w.WriteHeader(http.StatusInternalServerError)
74 h.log(err)
75 }
76 }()
77
78 h.handler.ServeHTTP(w, req)
79 }
80
81 func (h recoveryHandler) log(v ...interface{}) {
82 if h.logger != nil {
83 h.logger.Println(v...)
84 } else {
85 log.Println(v...)
86 }
87
88 if h.printStack {
89 stack := string(debug.Stack())
90 if h.logger != nil {
91 h.logger.Println(stack)
92 } else {
93 log.Println(stack)
94 }
95 }
96 }
97
View as plain text