aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/gin-gonic/gin/recovery.go
diff options
context:
space:
mode:
authorVidhu Kant Sharma <bokuwakanojogahoshii@yahoo.com>2020-10-19 11:05:36 +0530
committerVidhu Kant Sharma <bokuwakanojogahoshii@yahoo.com>2020-10-19 11:05:36 +0530
commit9c2ad91230d72fe6d661450cc78300ea223ae2bc (patch)
tree17bd774b3f972359dfbb46248f085bbf1c6dae98 /vendor/github.com/gin-gonic/gin/recovery.go
make it better
Diffstat (limited to 'vendor/github.com/gin-gonic/gin/recovery.go')
-rw-r--r--vendor/github.com/gin-gonic/gin/recovery.go106
1 files changed, 106 insertions, 0 deletions
diff --git a/vendor/github.com/gin-gonic/gin/recovery.go b/vendor/github.com/gin-gonic/gin/recovery.go
new file mode 100644
index 0000000..e296e33
--- /dev/null
+++ b/vendor/github.com/gin-gonic/gin/recovery.go
@@ -0,0 +1,106 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package gin
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "runtime"
+)
+
+var (
+ dunno = []byte("???")
+ centerDot = []byte("·")
+ dot = []byte(".")
+ slash = []byte("/")
+)
+
+// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one.
+func Recovery() HandlerFunc {
+ return RecoveryWithWriter(DefaultWriter)
+}
+
+func RecoveryWithWriter(out io.Writer) HandlerFunc {
+ var logger *log.Logger
+ if out != nil {
+ logger = log.New(out, "", log.LstdFlags)
+ }
+ return func(c *Context) {
+ defer func() {
+ if err := recover(); err != nil {
+ if logger != nil {
+ stack := stack(3)
+ logger.Printf("Panic recovery -> %s\n%s\n", err, stack)
+ }
+ c.AbortWithStatus(500)
+ }
+ }()
+ c.Next()
+ }
+}
+
+// stack returns a nicely formated stack frame, skipping skip frames
+func stack(skip int) []byte {
+ buf := new(bytes.Buffer) // the returned data
+ // As we loop, we open files and read them. These variables record the currently
+ // loaded file.
+ var lines [][]byte
+ var lastFile string
+ for i := skip; ; i++ { // Skip the expected number of frames
+ pc, file, line, ok := runtime.Caller(i)
+ if !ok {
+ break
+ }
+ // Print this much at least. If we can't find the source, it won't show.
+ fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc)
+ if file != lastFile {
+ data, err := ioutil.ReadFile(file)
+ if err != nil {
+ continue
+ }
+ lines = bytes.Split(data, []byte{'\n'})
+ lastFile = file
+ }
+ fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line))
+ }
+ return buf.Bytes()
+}
+
+// source returns a space-trimmed slice of the n'th line.
+func source(lines [][]byte, n int) []byte {
+ n-- // in stack trace, lines are 1-indexed but our array is 0-indexed
+ if n < 0 || n >= len(lines) {
+ return dunno
+ }
+ return bytes.TrimSpace(lines[n])
+}
+
+// function returns, if possible, the name of the function containing the PC.
+func function(pc uintptr) []byte {
+ fn := runtime.FuncForPC(pc)
+ if fn == nil {
+ return dunno
+ }
+ name := []byte(fn.Name())
+ // The name includes the path name to the package, which is unnecessary
+ // since the file name is already included. Plus, it has center dots.
+ // That is, we see
+ // runtime/debug.*T·ptrmethod
+ // and want
+ // *T.ptrmethod
+ // Also the package path might contains dot (e.g. code.google.com/...),
+ // so first eliminate the path prefix
+ if lastslash := bytes.LastIndex(name, slash); lastslash >= 0 {
+ name = name[lastslash+1:]
+ }
+ if period := bytes.Index(name, dot); period >= 0 {
+ name = name[period+1:]
+ }
+ name = bytes.Replace(name, centerDot, dot, -1)
+ return name
+}