package gig

import (

"fmt"

"runtime"

)

type (

// RecoverConfig defines the config for Recover middleware.

RecoverConfig struct {

// Skipper defines a function to skip middleware.

Skipper Skipper

// Size of the stack to be printed.

// Optional. Default value 4KB.

StackSize int

// DisableStackAll disables formatting stack traces of all other goroutines

// into buffer after the trace for the current goroutine.

// Optional. Default value false.

DisableStackAll bool

// DisablePrintStack disables printing stack trace.

// Optional. Default value as false.

DisablePrintStack bool

}

)

var (

// DefaultRecoverConfig is the default Recover middleware config.

DefaultRecoverConfig = RecoverConfig{

Skipper: DefaultSkipper,

StackSize: 4 << 10, // 4 KB

DisableStackAll: false,

DisablePrintStack: false,

}

)

// Recover returns a middleware which recovers from panics anywhere in the chain

// and handles the control to the centralized GeminiErrorHandler.

func Recover() MiddlewareFunc {

return RecoverWithConfig(DefaultRecoverConfig)

}

// RecoverWithConfig returns a Recover middleware with config.

// See: `Recover()`.

func RecoverWithConfig(config RecoverConfig) MiddlewareFunc {

// Defaults

if config.Skipper == nil {

config.Skipper = DefaultRecoverConfig.Skipper

}

if config.StackSize == 0 {

config.StackSize = DefaultRecoverConfig.StackSize

}

return func(next HandlerFunc) HandlerFunc {

return func(c Context) error {

if config.Skipper(c) {

return next(c)

}

defer func() {

if r := recover(); r != nil {

err, ok := r.(error)

if !ok {

err = fmt.Errorf("%v", r)

}

if !config.DisablePrintStack {

stack := make([]byte, config.StackSize)

length := runtime.Stack(stack, !config.DisableStackAll)

fmt.Fprintf(DefaultWriter, "[PANIC RECOVER] %v %s\n", err, stack[:length])

}

c.Error(err)

}

}()

return next(c)

}

}

}


Source