podman
98 строк · 2.4 Кб
1package handlers2
3import (4"log"5"net/http"6"runtime/debug"7)
8
9// RecoveryHandlerLogger is an interface used by the recovering handler to print logs.
10type RecoveryHandlerLogger interface {11Println(...interface{})12}
13
14type recoveryHandler struct {15handler http.Handler16logger RecoveryHandlerLogger
17printStack bool18}
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.
23type RecoveryOption func(http.Handler)24
25func parseRecoveryOptions(h http.Handler, opts ...RecoveryOption) http.Handler {26for _, option := range opts {27option(h)28}29
30return h31}
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))
45func RecoveryHandler(opts ...RecoveryOption) func(h http.Handler) http.Handler {46return func(h http.Handler) http.Handler {47r := &recoveryHandler{handler: h}48return parseRecoveryOptions(r, opts...)49}50}
51
52// RecoveryLogger is a functional option to override
53// the default logger.
54func RecoveryLogger(logger RecoveryHandlerLogger) RecoveryOption {55return func(h http.Handler) {56r := h.(*recoveryHandler) //nolint:errcheck //TODO:57// @bharat-rajani should return type-assertion error but would break the API?58r.logger = logger59}60}
61
62// PrintRecoveryStack is a functional option to enable
63// or disable printing stack traces on panic.
64func PrintRecoveryStack(shouldPrint bool) RecoveryOption {65return func(h http.Handler) {66r := h.(*recoveryHandler) //nolint:errcheck //TODO:67// @bharat-rajani should return type-assertion error but would break the API?68r.printStack = shouldPrint69}70}
71
72func (h recoveryHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {73defer func() {74if err := recover(); err != nil {75w.WriteHeader(http.StatusInternalServerError)76h.log(err)77}78}()79
80h.handler.ServeHTTP(w, req)81}
82
83func (h recoveryHandler) log(v ...interface{}) {84if h.logger != nil {85h.logger.Println(v...)86} else {87log.Println(v...)88}89
90if h.printStack {91stack := string(debug.Stack())92if h.logger != nil {93h.logger.Println(stack)94} else {95log.Println(stack)96}97}98}
99