podman

Форк
0
98 строк · 2.4 Кб
1
package handlers
2

3
import (
4
	"log"
5
	"net/http"
6
	"runtime/debug"
7
)
8

9
// RecoveryHandlerLogger is an interface used by the recovering handler to print logs.
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
// RecoveryOption provides a functional approach to define
21
// configuration for a handler; such as setting the logging
22
// whether or not to print stack traces on panic.
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
// RecoveryHandler is HTTP middleware that recovers from a panic,
34
// logs the panic, writes http.StatusInternalServerError, and
35
// continues to the next handler.
36
//
37
// Example:
38
//
39
//	r := mux.NewRouter()
40
//	r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
41
//		panic("Unexpected error!")
42
//	})
43
//
44
//	http.ListenAndServe(":1123", handlers.RecoveryHandler()(r))
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
// RecoveryLogger is a functional option to override
53
// the default logger.
54
func RecoveryLogger(logger RecoveryHandlerLogger) RecoveryOption {
55
	return func(h http.Handler) {
56
		r := h.(*recoveryHandler) //nolint:errcheck //TODO:
57
		// @bharat-rajani should return type-assertion error but would break the API?
58
		r.logger = logger
59
	}
60
}
61

62
// PrintRecoveryStack is a functional option to enable
63
// or disable printing stack traces on panic.
64
func PrintRecoveryStack(shouldPrint bool) RecoveryOption {
65
	return func(h http.Handler) {
66
		r := h.(*recoveryHandler) //nolint:errcheck //TODO:
67
		// @bharat-rajani should return type-assertion error but would break the API?
68
		r.printStack = shouldPrint
69
	}
70
}
71

72
func (h recoveryHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
73
	defer func() {
74
		if err := recover(); err != nil {
75
			w.WriteHeader(http.StatusInternalServerError)
76
			h.log(err)
77
		}
78
	}()
79

80
	h.handler.ServeHTTP(w, req)
81
}
82

83
func (h recoveryHandler) log(v ...interface{}) {
84
	if h.logger != nil {
85
		h.logger.Println(v...)
86
	} else {
87
		log.Println(v...)
88
	}
89

90
	if h.printStack {
91
		stack := string(debug.Stack())
92
		if h.logger != nil {
93
			h.logger.Println(stack)
94
		} else {
95
			log.Println(stack)
96
		}
97
	}
98
}
99

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.