github.com/tuingking/flamingo@v0.0.0-20220403134817-2796ae0e84ca/pkg/panics/panics.go (about)

     1  package panics
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net/http"
     7  	"net/http/httputil"
     8  	"os"
     9  	"runtime/debug"
    10  
    11  	"github.com/eapache/go-resiliency/breaker"
    12  )
    13  
    14  var (
    15  	// circuit breaker
    16  	cb *breaker.Breaker
    17  )
    18  
    19  // HTTPRecoveryMiddleware act as middleware that capture panics standard in http handler
    20  func HTTPRecoveryMiddleware(next http.Handler) http.Handler {
    21  	fn := func(w http.ResponseWriter, r *http.Request) {
    22  		_, _ = httputil.DumpRequest(r, true)
    23  		defer func() {
    24  			if !recoveryBreak() {
    25  				rcv := panicRecover(recover())
    26  				if rcv != nil {
    27  					// log the panic
    28  					fmt.Fprintf(os.Stderr, "Panic: %+v\n", rcv)
    29  					debug.PrintStack()
    30  					// publishError(rcv, request, true)
    31  					http.Error(w, rcv.Error(), http.StatusInternalServerError)
    32  				}
    33  			}
    34  		}()
    35  
    36  		next.ServeHTTP(w, r)
    37  	}
    38  
    39  	return http.HandlerFunc(fn)
    40  }
    41  
    42  func recoveryBreak() bool {
    43  	if cb == nil {
    44  		return false
    45  	}
    46  
    47  	if err := cb.Run(func() error {
    48  		return nil
    49  	}); err == breaker.ErrBreakerOpen {
    50  		return true
    51  	}
    52  	return false
    53  }
    54  
    55  func panicRecover(rc interface{}) error {
    56  	if cb != nil {
    57  		r := cb.Run(func() error {
    58  			return recovery(rc)
    59  		})
    60  		return r
    61  	}
    62  	return recovery(rc)
    63  }
    64  
    65  func recovery(r interface{}) error {
    66  	var err error
    67  	if r != nil {
    68  		switch t := r.(type) {
    69  		case string:
    70  			err = errors.New(t)
    71  		case error:
    72  			err = t
    73  		default:
    74  			err = errors.New("Unknown error")
    75  		}
    76  	}
    77  	return err
    78  }