preface

This is my third day to participate in the challenge, hello everyone, I am a composer Kind of Sun. The last article talked about using Viper to parse YAML files, this article we will do route initialization and Zap log management. Log management is essential on the server side, operation and maintenance troubleshooting,debug analysis needs log management

1. Introduction

A very fast and powerful log management module Zap official website

Requirements analysis (understanding requirements makes it easier to think clearly)

Routing:

  1. Routing group
  2. Stream to the Controll layer
  3. Add ZAP middleware

Log:

  1. Outputs logs to the specified location by day and log level
  2. You can see it on the console
  3. Received HTTP request response stored log (GinLogger middleware)
  4. When the server is down, it can record the abnormal information (GinRecovery middleware)

2. Install

go get -u go.uber.org/zap
Copy the code

3. Initialize the route

(1). Router /user

package router
import (
	"github.com/gin-gonic/gin"
)

func UserRouter(Router *gin.RouterGroup) {
	UserRouter := Router.Group("user")
	{
		UserRouter.GET("list".func(context *gin.Context) {
			context.JSON(200, gin.H{
				"message": "pong",})})}}Copy the code

(2) write in initialize/ Router

package initialize
import (
	"github.com/gin-gonic/gin"
	"go_gin/middlewares"
	"go_gin/router"
)
func Routers(a) *gin.Engine {
	Router := gin.Default()
	// Route grouping
	ApiGroup := Router.Group("/v1/")
	router.UserRouter(ApiGroup)
	return Router
}
Copy the code

Ps: The route group can fix the request prefix

(3). Add in main.go

package main
import (
	"fmt"
	"github.com/fatih/color"
	"go.uber.org/zap"
	"go_gin/global"
	"go_gin/initialize"
	"go_gin/utils"
)
func main(a) {
	//1. Initialize yamL configuration
	initialize.InitConfig()
	//2. Initialize the Routers
	Router := initialize.Routers()
	color.Cyan("Go-gin service has begun.")
	// Start gin and configure the Port, global.settings. Port is yamL configured
	err := Router.Run(fmt.Sprintf(":%d", global.Settings.Port))
	iferr ! =nil {
		zap.L().Info("this is hello func", zap.String("error"."Startup error!"))}}Copy the code

Ps: Initial routers(Router := initialize.Routers()) in Main. go

Verify that the route configuration is successful

When you restart the service, no error is reported, indicating that the above link is ok, you can continue ~

4. Initialize logger

(1) Write in initialize/ Logger

package initialize
import (
	"fmt"
	"github.com/fatih/color"
	"go.uber.org/zap"
	"go_gin/global"
	"go_gin/utils"
)
// InitLogger Initializes Logger
func InitLogger(a) {
        // instantiate zAP configuration
	cfg := zap.NewDevelopmentConfig()
        / / pay attention to the global Settings. LogsAddress is in Settings - dev. Yaml configuration
        // Set an output address for logs
	cfg.OutputPaths = []string{
		fmt.Sprintf("%slog_%s.log", global.Settings.LogsAddress, utils.GetNowFormatTodayTime()), //
		"stdout",}// Create logger instance
	logg, _ := cfg.Build()
	zap.ReplaceGlobals(logg) // Replace the global logger instance in the Zap package with the zap.l () call later in other packages
        global.Lg = logg  // Register with global variables
}
Copy the code

Ps :GetNowFormatTodayTime this function is my utils to get the day of the day, month and year function (2).

package utils

import (
	"fmt"
	"time"
)
func GetNowFormatTodayTime(a) string {

	now := time.Now()
	dateStr := fmt.Sprintf("%02d-%02d-%02d", now.Year(), int(now.Month()),
		now.Day())

	return dateStr
}
Copy the code

Add to global variables add to global/ globalvar. go

var (
    Lg *zap.Logger)
)    
Copy the code

5. Take a look at middleware

According to our requirements analysis, log management involves archiving HTTP request exceptions, so we need to consider using middleware

We do a layer of interception in the middleware, and record the resonse anomalies. I also found a good article, if you are interested, you can follow along and learn about how to use juejin.cn/post/684490…

6. Use the middleware Logger to record HTTP exceptions

package middlewares

import (
   "time"

   "github.com/gin-gonic/gin"
   "go.uber.org/zap"
)



// GinLogger receives the default logs from the gin framework
func GinLogger(a) gin.HandlerFunc {
   return func(c *gin.Context) {
   	start := time.Now()
               // Request path
   	path := c.Request.URL.Path
               // Request parameters
   	query := c.Request.URL.RawQuery
   	c.Next()

   	cost := time.Since(start)
               // If the status code of response is not 200, it is an exception
   	ifc.Writer.Status() ! =200 {
                       // Record the exception information
   		zap.L().Info(path,
   			zap.Int("statusxixixixi", c.Writer.Status()),
   			zap.String("method", c.Request.Method),
   			zap.String("path", path),
   			zap.String("query", query),
   			zap.String("ip", c.ClientIP()),
   			zap.String("user-agent", c.Request.UserAgent()),
   			zap.String("errors", c.Errors.ByType(gin.ErrorTypePrivate).String()),
   			zap.Duration("cost", cost),
   		)
   	}
   }
}
Copy the code

6. Use the middleware to record the fault information

// GinRecovery recovers any panic that may occur in the project and logs it using zAP
func GinRecovery(stack bool) gin.HandlerFunc {
   return func(c *gin.Context) {
   	defer func(a) {
   		if err := recover(a); err ! =nil {
   			// Check for a broken connection, as it is not really a
   			// condition that warrants a panic stack trace.
   			var brokenPipe bool
   			if ne, ok := err.(*net.OpError); ok {
   				if se, ok := ne.Err.(*os.SyscallError); ok {
   					if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
   						brokenPipe = true
   					}
   				}
   			}

   			httpRequest, _ := httputil.DumpRequest(c.Request, false)
   			if brokenPipe {
   				global.Lg.Error(c.Request.URL.Path,
   					zap.Any("error", err),
   					zap.String("request".string(httpRequest)),
   				)
   				// If the connection is dead, we can't write a status to it.
   				c.Error(err.(error)) // nolint: errcheck
   				c.Abort()
   				return
   			}

   			if stack {
   				zap.L().Error("[Recovery from panic]",
   					zap.Any("error", err),
   					zap.String("request".string(httpRequest)),
   					zap.String("stack".string(debug.Stack())),
   				)
   			} else {
   				zap.L().Error("[Recovery from panic]",
   					zap.Any("error", err),
   					zap.String("request".string(httpRequest)),
   				)
   			}
   			c.AbortWithStatus(http.StatusInternalServerError)
   		}
   	}()
   	c.Next()
   }
}

Copy the code

7. Main.go initializes Zap and middleware additions

InitLogger is initialized with GinLogger middleware \ in main.go

(1). Add in main.go

   // 3. Initialize log information
   initialize.InitLogger()
Copy the code

(2) add GinLogger and GinRecovery middleware to initialize/router

    Router.Use(middlewares.GinLogger(), middlewares.GinRecovery(true))
Copy the code

Ps: Use is gin to add middleware functions

Finally – verification of results

(1). To start the main. Go

(2). Enter the url: 127.0.0.1:8021 / v1 / user/list to return the result is:This step indicates that your initial route was successful, but the log printing function has not been tested yet

(3) Enter a non-existent URL and see if the file below./log/ has output log

(4) calls

zap.L().Info("this is hello func", zap.String("test"."test--------->"))  

Copy the code

Check whether the log is printed this step indicates that you initialized the route, the log printing function is successful, continue the journey ~

If you found any of these articles useful, please give them a thumbs up and leave a comment