preface

Gin framework logs are output on the console by default. This article uses the RecoveryWithWriter() method provided by Gin to encapsulate a middleware, and uses the Lumberjack as a writer to write error logs to files. At the same time, use github.com/gin-contrib/cors for cross-domain processing.

The installation

go get -u gopkg.in/natefinch/lumberjack.v2
go get github.com/gin-contrib/cors
Copy the code

Recovery middleware

In the app/common/response/response. Go file, add ServerError () method, as RecoveryFunc

package response

import (
    "github.com/gin-gonic/gin"
    "jassue-gin/global"
    "net/http"
    "os"
)

// ...

func ServerError(c *gin.Context, err interface{}) {
    msg := "Internal Server Error"
    // Specific error information is displayed in non-production environments
    ifglobal.App.Config.App.Env ! ="production"&& os.Getenv(gin.EnvGinMode) ! = gin.ReleaseMode {if _, ok := err.(error); ok {
            msg = err.(error).Error()
        }
    }
    c.JSON(http.StatusInternalServerError, Response{
        http.StatusInternalServerError,
        nil,
        msg,
    })
    c.Abort()
}
// ...
Copy the code

New app/middleware/recovery. Go file, write:

package middleware

import (
    "github.com/gin-gonic/gin"
    "gopkg.in/natefinch/lumberjack.v2"
    "jassue-gin/app/common/response"
    "jassue-gin/global"
)

func CustomRecovery(a) gin.HandlerFunc {
    return gin.RecoveryWithWriter(
        &lumberjack.Logger{
            Filename:   global.App.Config.Log.RootDir + "/" + global.App.Config.Log.Filename,
            MaxSize:    global.App.Config.Log.MaxSize,
            MaxBackups: global.App.Config.Log.MaxBackups,
            MaxAge:     global.App.Config.Log.MaxAge,
            Compress:   global.App.Config.Log.Compress,
        },
        response.ServerError)
}
Copy the code

CORS is processed across domains

Create app/ Middleware/cers. go and write:

package middleware

import (
    "github.com/gin-contrib/cors"
    "github.com/gin-gonic/gin"
)

func Cors(a) gin.HandlerFunc {
    config := cors.DefaultConfig()
    config.AllowAllOrigins = true
    config.AllowHeaders = []string{"Origin"."Content-Length"."Content-Type"."Authorization"}
    config.AllowCredentials = true
    config.ExposeHeaders = []string{"New-Token"."New-Expires-In"."Content-Disposition"}

    return cors.New(config)
}
Copy the code

Using middleware

In the bootstrap/router.go file, write:

func setupRouter(a) *gin.Engine {
    if global.App.Config.App.Env == "production" {
        gin.SetMode(gin.ReleaseMode)
    }
    router := gin.New()
    router.Use(gin.Logger(), middleware.CustomRecovery())

    // cross-domain processing
    // router.Use(middleware.Cors())

    // ...
}
Copy the code

test

To demonstrate, here I deliberately write the database configuration wrong, request login interface, middleware successfully effect

Log/storage/logs/app.log

[31m2019/11/21 20:40:18 [Recovery] 2021/11/21-20:40:18 Panic recovered: POST/API /auth/login HTTP/1.1 Host: localhost:8888 Accept: */* Accept-Encoding: gzip, deflate Cache-Control: no-cache Connection: keep-alive Content-Length: 51 Content-Type: application/json Postman-Token: 30136d3a-9a7d-43ff-bd6e-8f408dd20a7e User-agent: PostmanRuntime/7.18.0 Runtime Error: invalid memory address or nil pointer dereference /usr/local/go/src/runtime/panic.go:221 (0x104a9c6) panicmem: panic(memoryError) /usr/local/go/src/runtime/signal_unix.go:735 (0x104a996) sigpanic: Panicmem ()/Users/SJJ/go/PKG/mod/gorm. IO/[email protected] / gorm. Go: 355 (0 x1537ed8) (* DB). The getInstance: If the clone > 0 {/ Users/SJJ/go/PKG/mod/gorm. IO/[email protected] / chainable_api. Go: 146 (0 x152efdb) (* db). The Where: tx = db.getInstance() /Users/sjj/go/src/jassue-gin/app/services/user.go:31 (0x17a963e) (*userService).Login: err = global.App.DB.Where("mobile = ?", params.Mobile).First(&user).Error /Users/sjj/go/src/jassue-gin/app/controllers/app/auth.go:37 (0x17aab7b) Login: if err, user := services.UserService.Login(form); err ! = nil {/ Users/sjj/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:165 (0 x1797681) Context (*). Next: C. andlers [c.i ndex] (c)/Users/sjj/go/pkg/mod/github.com/gin-gonic/[email protected]/recovery.go:99 (0 x179766c) CustomRecoveryWithWriter.func1: C.N ext ()/Users/sjj/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:165 (0 x17968e6) Context (*). Next: C. andlers [c.i ndex] (c)/Users/sjj/go/pkg/mod/github.com/gin-gonic/[email protected]/logger.go:241 (0 x17968c9) LoggerWithConfig.func1: C.N ext ()/Users/sjj/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:165 (0 x1795e1d) Context (*). Next: C. andlers [c.i ndex] (c)/Users/sjj/go/pkg/mod/github.com/gin-gonic/[email protected]/gin.go:489 (0 x1795aa5) (*Engine).handleHTTPRequest: C.N ext ()/Users/sjj/go/pkg/mod/github.com/gin-gonic/[email protected]/gin.go:445 (0 x1795604) Engine (*). ServeHTTP: engine.handleHTTPRequest(c) /usr/local/go/src/net/http/server.go:2878 (0x129e49a) serverHandler.ServeHTTP: handler.ServeHTTP(rw, req) /usr/local/go/src/net/http/server.go:1929 (0x1299b47) (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req) /usr/local/go/src/runtime/asm_amd64.s:1581 (0x1065ac0) goexit: BYTE $0x90 // NOP [0mCopy the code