An overview of the

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

Check a lot of information, most of all, Go logging with github.com/sirupsen/logrus.

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

Logs from the Gin framework are only exported to the console by default. We use Logrus to encapsulate middleware and log to a file.

This article is about learning and using Logrus.

Log format

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

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

Next, let’s implement it with Logrus.

Logrus use

Install in DEP mode.

Added to gopkg.toml file:

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

Import in a project:

import "github.com/sirupsen/logrus"
Copy the code

Execute on the project command line:

dep ensure
Copy the code

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

We are ready to use it. Before we use it, let’s make a plan and set this function as a middleware, such as Logger.go.

The log can be logged to File by defining a LoggerToFile method.

Logs can be logged to MongoDB and a LoggerToMongo method defined.

Logs can be logged to ES, defining a LoggerToES method.

Logs can be logged to MQ, defining a LoggerToMQ method.

.

This time we first realize the record to the file, the implementation of LoggerToFile method, other can be implemented according to their own needs.

The Logger middleware, once created, can be migrated and used in any other project.

Without further ado, 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 := path.join (FileName := config.logFilePath, logFileName) / / write file SRC, err: = OS. The OpenFile (FileName, OS O_APPEND | OS. O_WRONLY, OS. ModeAppend)iferr ! = nil { fmt.Println("err". Logrus.new () // Set the output logger.out = SRC // Set the log level logrus.setLevel (logrus.debugLevel) // Set the log format logger.SetFormatter(&logrus.TextFormatter{})returnFunc (c *gin.Context) {// startTime startTime := time.now () // process request c.ext () // endTime endTime := time.now () // execute time LatencyTime := endtime. Sub(startTime) // Request mode reqMethod := c. request. Method // Request route reqUri := c. request.requesturi // StatusCode := c.wirit.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 {returnFunc (c * gin.context) {}} // Log to ES func LoggerToES() gin.handlerfunc {returnFunc (c * gin.context) {}} // Log to MQ func LoggerToMQ() gin.handlerFunc {return func(c *gin.Context) {

	}
}
Copy the code

Log middleware is written, how to call?

Simply add in main.go:

Engine := gin.Default() // Add engine.use (middleware.loggertofile ()) after this lineCopy the code

Run it and look at the log:

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

thistime="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

Logger.setformatter (&logrus.textFormatter {TimestampFormat:"The 2006-01-02 15:04:05",})Copy the code

Run the following command to look at the log again:

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

Time became normal.

I don’t like text format, I like JSON format, what do I do?

Logger.setformatter (& logrus.jsonformatter {TimestampFormat:"The 2006-01-02 15:04:05",})Copy the code

Run the following command to look at the log again:

{"level":"info"."msg":"| | | 24.78 (including 200 s: : 1 | GET | / v1 / product/add? name=a\u0026price=10 |"."time":"The 2019-07-17 22:23:55"}
{"level":"info"."msg":"| | | 26.946 (including 200 s: : 1 | GET | / v1 / product/add? name=a\u0026price=10 |"."time":"The 2019-07-17 22:23:56"}
Copy the code

MSG message too much, inconvenient to see, how to do?

Logger.withfields (logrus.fields {"status_code"  : statusCode,
	"latency_time" : latencyTime,
	"client_ip"    : clientIP,
	"req_method"   : reqMethod,
	"req_uri"      : reqUri,
}).Info()
Copy the code

Run the following command to look at the log again:

{"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":"The 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":"The 2019-07-17 22:37:55"}
Copy the code

Time, MSG, and level are automatically added by logrus.

Does Logrus support output file names and line numbers?

Not supported, the author replies that it is too performance intensive.

However, there are some people on the Internet who have implemented it by Hook. When you choose to use it in the production environment, remember to do performance testing.

Does Logrus support log splitting?

Not supported, but there are ways to implement it.

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

2. It can be implemented using file-rotatelogs.

Need to import packages:

github.com/lestrrat-go/file-rotatelogs

github.com/rifflock/lfshook

Send the full 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 := path.join (FileName := config.logFilePath, logFileName) / / write file SRC, err: = OS. The OpenFile (FileName, OS O_APPEND | OS. O_WRONLY, OS. ModeAppend)iferr ! = nil { fmt.Println("err". Logrus.new () // Set the output logger.out = SRC // Set the log level logrus.setLevel (logrus.debugLevel) // Set rotatelogslogWriter, err := rotatelogs.New(// Name of the split file fileName +".%Y%m%d.log", // generate a soft chain, Rotatelogs. WithLinkName(fileName), rotatelogs.WithMaxAge(7*24* time.hour), / / set log cutting time interval (1 day) rotatelogs. WithRotationTime (24 * time. The 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:"The 2006-01-02 15:04:05"}) // AddHook logger.addhook (lfHook)returnFunc (c *gin.Context) {// startTime startTime := time.now () // process request c.ext () // endTime endTime := time.now () // execute time LatencyTime := endtime. Sub(startTime) // Request mode reqMethod := c. request. Method // Request route reqUri := c. request.requesturi // StatusCode := c.wirit.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 {returnFunc (c * gin.context) {}} // Log to ES func LoggerToES() gin.handlerfunc {returnFunc (c * gin.context) {}} // Log to MQ func LoggerToMQ() gin.handlerFunc {return func(c *gin.Context) {

	}
}
Copy the code

In this case, a new file system.log.20190717.log is generated. The log content is in the same format as the preceding file.

Finally, logrus has many extendable hooks, which you can find online.

Some readers suggested updating the code to GitHub because it was inconvenient to see it on mobile.

It has been updated to the following address:

Github.com/xinliangnot…

Recommended reading

Gin framework

  • Gin framework – Data binding and validation
  • Gin framework – Use Logrus logging
  • Gin framework – Installation and routing configuration

Based on article

  • Go – function
  • Go – cycle
  • Go-map collection
  • Go-struct structure
  • Go-slice Slice
  • Go – array
  • Go – Variable declaration
  • Go-environment installation

This article is welcome to forward, forward please indicate the author and source, thank you!