/usr/share/gocode/src/go.pedge.io/lion/gin/gin.go is in golang-go.pedge-lion-dev 0.0~git20171203.2a81062-5.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | /*
Package ginlion defines functionality to integrate lion with gin.
https://github.com/gin-gonic/gin
Full typical use:
import (
"go.pedge.io/lion/env"
"go.pedge.io/lion/gin"
)
func setupGin() error {
if err := envlion.Setup(); err != nil {
return err
}
engine := ginlion.Default()
...
}
Some of the code here is copied from the gin repository.
This code is under the MIT License that can be found at https://github.com/gin-gonic/gin/blob/master/LICENSE.
*/
package ginlion // import "go.pedge.io/lion/gin"
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"runtime"
"strings"
"time"
"github.com/gin-gonic/gin"
"go.pedge.io/lion/proto"
)
var (
dunno = []byte("???")
centerDot = []byte("·")
dot = []byte(".")
slash = []byte("/")
)
// Default is the equivalent of gin's Default function.
func Default() *gin.Engine {
engine := gin.New()
engine.Use(GlobalLoggerAndRecovery())
return engine
}
// GlobalLoggerAndRecovery returns LoggerAndRecovery on the global proto Logger.
func GlobalLoggerAndRecovery() gin.HandlerFunc {
return LoggerAndRecovery(protolion.GlobalLogger)
}
// LoggerAndRecovery is the equivalent of both gin's Logger and Recovery middlewares.
func LoggerAndRecovery(protoLoggerProvider func() protolion.Logger) gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
var path string
if c.Request.URL != nil {
path = c.Request.URL.Path
}
defer func() {
call := &Call{
Method: c.Request.Method,
Path: path,
UserAgent: c.Request.Header.Get("User-Agent"),
RequestForm: valuesMap(c.Request.Form),
ClientIp: c.ClientIP(),
StatusCode: uint32(statusCode(c.Writer.Status())),
Error: c.Errors.Errors(),
}
if c.Request.URL != nil {
call.Query = valuesMap(c.Request.URL.Query())
}
call.Duration = fmt.Sprintf("%v", time.Since(start))
protoLogger := protoLoggerProvider()
if recoverErr := recover(); recoverErr != nil {
stack := stack(3)
call.Error = append(call.Error, fmt.Sprintf("panic: %s\n%s", recoverErr, string(stack)))
protoLogger.Error(call)
c.AbortWithStatus(http.StatusInternalServerError)
} else {
protoLogger.Info(call)
}
}()
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
}
func valuesMap(values map[string][]string) map[string]string {
if values == nil {
return nil
}
m := make(map[string]string)
for key, value := range values {
m[key] = strings.Join(value, " ")
}
return m
}
func statusCode(code int) int {
if code == 0 {
return http.StatusOK
}
return code
}
|