github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/web/middlewares/recover.go (about)

     1  package middlewares
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net/http"
     7  	"runtime"
     8  
     9  	"github.com/cozy/cozy-stack/pkg/logger"
    10  	"github.com/labstack/echo/v4"
    11  	"github.com/labstack/echo/v4/middleware"
    12  )
    13  
    14  // RecoverConfig defines the config for Recover middleware.
    15  type RecoverConfig struct {
    16  	// Skipper defines a function to skip middleware.
    17  	Skipper middleware.Skipper
    18  
    19  	// Size of the stack to be printed.
    20  	// Optional. Default value 4KB.
    21  	StackSize int `json:"stack_size"`
    22  }
    23  
    24  // RecoverWithConfig returns a Recover middleware with config.
    25  func RecoverWithConfig(config RecoverConfig) echo.MiddlewareFunc {
    26  	// Defaults
    27  	if config.Skipper == nil {
    28  		config.Skipper = middleware.DefaultSkipper
    29  	}
    30  	if config.StackSize == 0 {
    31  		config.StackSize = 4 << 10 // 4 KB
    32  	}
    33  
    34  	return func(next echo.HandlerFunc) echo.HandlerFunc {
    35  		return func(c echo.Context) error {
    36  			if config.Skipper(c) {
    37  				return next(c)
    38  			}
    39  
    40  			defer func() {
    41  				if r := recover(); r != nil {
    42  					var err error
    43  					switch r := r.(type) {
    44  					case error:
    45  						err = r
    46  					default:
    47  						err = fmt.Errorf("%v", r)
    48  					}
    49  					// We don't want to log panic with ErrAbortHandler, as it
    50  					// is just noise (http.Server does that too).
    51  					// See https://golang.org/pkg/net/http/#ErrAbortHandler
    52  					if !errors.Is(err, http.ErrAbortHandler) {
    53  						stack := make([]byte, config.StackSize)
    54  						length := runtime.Stack(stack, false)
    55  						log := logger.WithDomain(c.Request().Host).WithField("panic", true)
    56  						log.Errorf("PANIC RECOVER %s: %s", err.Error(), stack[:length])
    57  						c.Error(err)
    58  					}
    59  				}
    60  			}()
    61  			return next(c)
    62  		}
    63  	}
    64  }