package main import ( "fmt" "net/http" "path/filepath" "time" "github.com/gin-gonic/gin" "github.com/rs/xid" "github.com/rs/zerolog" "github.com/rs/zerolog/log" ) var server *gin.Engine // var api *gin.RouterGroup func setupServer() { server = gin.New() server.Use(middleware) // api = server.Group("/api") } func middleware(c *gin.Context) { path := c.Request.URL.Path start := time.Now() defer func() { var cl *zerolog.Event err := recover() if err != nil { cl = log.Error() switch v := err.(type) { case Error: c.AbortWithStatusJSON(v.Code, v) cl.Err(v) case error: c.String(500, v.Error()) c.Abort() cl.Err(v) default: c.String(500, fmt.Sprint(err)) c.Abort() cl.Str("error", fmt.Sprint(err)) } cl.Caller(2) cl.Str("stack", Stack()) } else if c.Writer.Status() >= 400 { cl = log.Error().Strs("error", c.Errors.Errors()) } else { cl = log.Info() } if skip(c) { return } if usr, ok := c.Get("user"); ok { cl.Str("user", usr.(string)) } cl. Str("method", c.Request.Method). Str("ip", c.ClientIP()). Int("status", c.Writer.Status()). Dur("duration", time.Since(start)). Str("url", path). Msg("") }() c.Next() } func skip(c *gin.Context) bool { switch filepath.Ext(c.Request.URL.Path) { case ".css": fallthrough case ".woff2": fallthrough case ".map": fallthrough case ".ico": fallthrough case ".js": return true default: return false } } type Response struct { Status int `json:"status"` ID string `json:"id"` Code string `json:"code,omitempty"` Data interface{} `json:"data,omitempty"` } func OK(c *gin.Context, data interface{}) { c.JSON(http.StatusOK, Response{ Status: http.StatusOK, ID: xid.New().String(), Data: data, }) }