728x90

원문 : https://programmer.help/blogs/gin-framework-logging-with-logrus.html

Gin framework - logging with Logrus

Summary

The previous article shared the routing configuration of the Gin framework, and this article shared logging.

After checking a lot of data, github.com/sirupsen/logrus is the most widely used log record in Go.

Logrus is a structured logger for Go (golang), completely API compatible with the standard library logger.

 



By default, the log of the Gin framework will only be output in the console. We use Logrus to encapsulate a middleware to record the log in the file.

This article is about learning and using Logrus.

Log format

For example, we agree that the log format is Text, including the following fields:

Request time, log level, status code, execution time, request IP, request mode and request route.

Next, we use Logrus to implement it.

Logrus use

Install in dep mode.

In Gopkg.toml file, add:

[[constraint]]    
name = "github.com/sirupsen/logrus"    
version = "1.4.2"

 



Import in project:

import "github.com/sirupsen/logrus"

 



On the project command line:

dep ensure

 



At this point, you will see the sirupsen directory in the vendor/github.com /.

We are ready to use it. Before we start, let's plan to set this function as a middleware, such as logger.go.

Logs can be recorded in a File, defining a LoggerToFile method.

Logs can be recorded in MongoDB and a LoggerToMongo method is defined.

Logs can be recorded in ES, defining a LoggerToES method.

Logs can be recorded in MQ, defining a LoggerToMQ method.

...

This time, let's first implement logging to file and LoggerToFile method. Others can be implemented according to our own needs.

The logger middleware, created, can be used for migration in other projects.

No more nonsense, just look at the code.

 

  package middleware    
    import (    
        "fmt"    
        "ginDemo/config"    
        "github.com/gin-gonic/gin"    
        "github.com/sirupsen/logrus"    
        "os"    
        "path"    
        "time"    
    )    
    // Log to file    
    func LoggerToFile() gin.HandlerFunc {    
        logFilePath := config.Log_FILE_PATH    
        logFileName := config.LOG_FILE_NAME    
        //log file    
        fileName := path.Join(logFilePath, logFileName)    
        //write file    
        src, err := os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY, os.ModeAppend)    
        if err != nil {    
            fmt.Println("err", err)    
        }    
        //instantiation    
        logger := logrus.New()    
        //Set output    
        logger.Out = src    
        //Set log level    
        logger.SetLevel(logrus.DebugLevel)    
        //Format log    
        logger.SetFormatter(&logrus.TextFormatter{})    
        return func(c *gin.Context) {    
            // start time    
            startTime := time.Now()    
            // Processing request    
            c.Next()    
            // End time    
            endTime := time.Now()    
            // execution time    
            latencyTime := endTime.Sub(startTime)    
            // Request mode    
            reqMethod := c.Request.Method    
            // Request routing    
            reqUri := c.Request.RequestURI    
            // Status code    
            statusCode := c.Writer.Status()    
            // Request IP    
            clientIP := c.ClientIP()    
            // Log format    
            logger.Infof("| %3d | %13v | %15s | %s | %s |",    
                statusCode,    
                latencyTime,    
                clientIP,    
                reqMethod,    
                reqUri,    
            )    
        }    
    }    
    // Log to MongoDB    
    func LoggerToMongo() gin.HandlerFunc {    
        return func(c *gin.Context) {    
        }    
    }    
    // Log to ES    
    func LoggerToES() gin.HandlerFunc {    
        return func(c *gin.Context) {    
        }    
    }    
    // Logging to MQ    
    func LoggerToMQ() gin.HandlerFunc {    
        return func(c *gin.Context) {    
        }    
    }

 



Log middleware is written, how to call it?

Just add in main.go:

 

  engine := gin.Default() //Add after this line    
    engine.Use(middleware.LoggerToFile())

 


Do this and look at the log:

 

  time="2019-07-17T22:10:45+08:00" level=info msg="| 200 |      27.698µs |             ::1 | GET | /v1/product/add?name=a&price=10 |"    
    time="2019-07-17T22:10:46+08:00" level=info msg="| 200 |      27.239µs |             ::1 | GET | /v1/product/add?name=a&price=10 |"

 



This time="2019-07-17T22:10:45+08:00", this time format is not what we want, what should we do?

Time needs to be formatted. Modify logger.SetFormatter

 

  //Format log    
    logger.SetFormatter(&logrus.TextFormatter{    
        TimestampFormat:"2006-01-02 15:04:05",    
    })

 



Run it, and then look at the log:

   

time="2019-07-17 22:15:57" level=info msg="| 200 |     185.027µs |             ::1 | GET | /v1/product/add?name=a&price=10 |"    
    time="2019-07-17 22:15:58" level=info msg="| 200 |      56.989µs |             ::1 | GET | /v1/product/add?name=a&price=10 |"

 


Time has become normal.

I don't like text format, like JSON format, what to do?

    //Format log    
    logger.SetFormatter(&logrus.JSONFormatter{    
        TimestampFormat:"2006-01-02 15:04:05",    
    })

 


Run it, and then look at the log:

    {"level":"info","msg":"| 200 |       24.78µs |             ::1 | GET | /v1/product/add?name=a\u0026price=10 |","time":"2019-07-17 22:23:55"}    
    {"level":"info","msg":"| 200 |      26.946µs |             ::1 | GET | /v1/product/add?name=a\u0026price=10 |","time":"2019-07-17 22:23:56"}

 


There are too many msg information, which is inconvenient to read. What should I do?

 

  // Log format    
    logger.WithFields(logrus.Fields{    
        "status_code"  : statusCode,    
        "latency_time" : latencyTime,    
        "client_ip"    : clientIP,    
        "req_method"   : reqMethod,    
        "req_uri"      : reqUri,    
    }).Info()

 



Run it, and then look at the log:

 

  {"client_ip":"::1","latency_time":26681,"level":"info","msg":"","req_method":"GET","req_uri":"/v1/product/add?name=a\u0026price=10","status_code":200,"time":"2019-07-17 22:37:54"}    
    {"client_ip":"::1","latency_time":24315,"level":"info","msg":"","req_method":"GET","req_uri":"/v1/product/add?name=a\u0026price=10","status_code":200,"time":"2019-07-17 22:37:55"}

 



Note: time, msg and level are automatically added by logrus.

Does logrus support output file names and line numbers?

No, the author's reply is too performance consuming.

However, there are also people on the Internet who have realized it through the way of Hook. When they choose to use it in the production environment, they should remember to do performance tests.

Does logrus support log segmentation?

No, but there is a way to achieve it.

1. Linux logrotate can be used for unified processing by operation and maintenance.

2. It can be realized by file rotatelogs.

Need to import package:

github.com/lestrrat-go/file-rotatelogs

github.com/rifflock/lfshook

 



Complete code:

    package middleware    
    import (    
        "fmt"    
        "ginDemo/config"    
        "github.com/gin-gonic/gin"    
        rotatelogs "github.com/lestrrat-go/file-rotatelogs"    
        "github.com/rifflock/lfshook"    
        "github.com/sirupsen/logrus"    
        "os"    
        "path"    
        "time"    
    )    
    // Log to file    
    func LoggerToFile() gin.HandlerFunc {    
        logFilePath := config.Log_FILE_PATH    
        logFileName := config.LOG_FILE_NAME    
        // log file    
        fileName := path.Join(logFilePath, logFileName)    
        // write file    
        src, err := os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY, os.ModeAppend)    
        if err != nil {    
            fmt.Println("err", err)    
        }    
        // instantiation    
        logger := logrus.New()    
        // Set output    
        logger.Out = src    
        // Set log level    
        logger.SetLevel(logrus.DebugLevel)    
        // Set rotatelogs    
        logWriter, err := rotatelogs.New(    
            // Split file name    
            fileName + ".%Y%m%d.log",    
            // Generate soft chain, point to the latest log file    
            rotatelogs.WithLinkName(fileName),    
            // Set maximum save time (7 days)    
            rotatelogs.WithMaxAge(7*24*time.Hour),    
            // Set log cutting interval (1 day)    
            rotatelogs.WithRotationTime(24*time.Hour),    
        )    
        writeMap := lfshook.WriterMap{    
            logrus.InfoLevel:  logWriter,    
            logrus.FatalLevel: logWriter,    
            logrus.DebugLevel: logWriter,    
            logrus.WarnLevel:  logWriter,    
            logrus.ErrorLevel: logWriter,    
            logrus.PanicLevel: logWriter,    
        }    
        lfHook := lfshook.NewHook(writeMap, &logrus.JSONFormatter{    
            TimestampFormat:"2006-01-02 15:04:05",    
        })    
        // Add Hook    
        logger.AddHook(lfHook)    
        return func(c *gin.Context) {    
            // start time    
            startTime := time.Now()    
            // Processing request    
            c.Next()    
            // End time    
            endTime := time.Now()    
            // execution time    
            latencyTime := endTime.Sub(startTime)    
            // Request mode    
            reqMethod := c.Request.Method    
            // Request routing    
            reqUri := c.Request.RequestURI    
            // Status code    
            statusCode := c.Writer.Status()    
            // Request IP    
            clientIP := c.ClientIP()    
            // Log format    
            logger.WithFields(logrus.Fields{    
                "status_code"  : statusCode,    
                "latency_time" : latencyTime,    
                "client_ip"    : clientIP,    
                "req_method"   : reqMethod,    
                "req_uri"      : reqUri,    
            }).Info()    
        }    
    }    
    // Log to MongoDB    
    func LoggerToMongo() gin.HandlerFunc {    
        return func(c *gin.Context) {    
        }    
    }    
    // Log to ES    
    func LoggerToES() gin.HandlerFunc {    
        return func(c *gin.Context) {    
        }    
    }    
    // Logging to MQ    
    func LoggerToMQ() gin.HandlerFunc {    
        return func(c *gin.Context) {    
        }    
    }

 



A new file system.log.20190717.log will be generated. The log content is consistent with the above format.

Finally, there are many extensible hooks in logrus, which you can search online.

Some readers suggest that it's not convenient to read the code on the mobile phone, so it's recommended to update it to GitHub.

Now updated to the following address:
https://github.com/xinliangnote/Go

728x90
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기
반응형