[Серия] Gin Framework — Ведение журнала с помощью Logrus

Go

Обзор

В предыдущей статье была описана конфигурация маршрутизации среды Gin, а в этой — ведение журнала.

После проверки большого количества информации ведение журнала Go является наиболее часто используемым.github.com/sirupsen/logrus.

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

Лог фреймворка Gin по умолчанию будет выводиться только в консоль, мы используемLogrusОбертывает промежуточное ПО, которое ведет журнал в файл.

Эта статья посвящена изучению и использованиюLogrus.

формат журнала

Например, договариваемся, что формат лога Текстовый, а поля такие:

请求时间,日志级别,状态码,执行时间,请求IP,请求方式,请求路由.

Далее мы используемLogrusПойми.

Логрус использует

использоватьdepспособ установки.

существуетGopkg.tomlДополнения к файлам:

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

Импорт в проект:

import "github.com/sirupsen/logrus"

Выполните в командной строке проекта:

dep ensure

В это время вvendor/github.com/вы увидите в каталогеsirupsenсодержание.

Готовы начать, давайте спланируем перед началом работы и установим эту функцию в качестве промежуточного программного обеспечения, например:logger.go.

Журналы можно записывать в файл, определитьLoggerToFileметод.

Журналы могут быть зарегистрированы в MongoDB, определитеLoggerToMongoметод.

Журналы могут быть зарегистрированы в ES, определитьLoggerToESметод.

Журналы могут быть зарегистрированы в MQ, определитьLoggerToMQметод.

...

На этот раз мы сначала реализуем запись в файл, реализуемLoggerToFileметод, и другие могут быть реализованы в соответствии с их собственными потребностями.

этоloggerПромежуточное программное обеспечение, однажды созданное, может быть перенесено и использовано в других проектах по желанию.

Без лишних слов, просто посмотрите на код.

package middleware

import (
	"fmt"
	"ginDemo/config"
	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
	"os"
	"path"
	"time"
)

// 日志记录到文件
func LoggerToFile() gin.HandlerFunc {

	logFilePath := config.Log_FILE_PATH
	logFileName := config.LOG_FILE_NAME

	//日志文件
	fileName := path.Join(logFilePath, logFileName)

	//写入文件
	src, err := os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY, os.ModeAppend)
	if err != nil {
		fmt.Println("err", err)
	}

	//实例化
	logger := logrus.New()

	//设置输出
	logger.Out = src

	//设置日志级别
	logger.SetLevel(logrus.DebugLevel)

	//设置日志格式
	logger.SetFormatter(&logrus.TextFormatter{})

	return func(c *gin.Context) {
		// 开始时间
		startTime := time.Now()

		// 处理请求
		c.Next()

		// 结束时间
		endTime := time.Now()

		// 执行时间
		latencyTime := endTime.Sub(startTime)

		// 请求方式
		reqMethod := c.Request.Method

		// 请求路由
		reqUri := c.Request.RequestURI

		// 状态码
		statusCode := c.Writer.Status()

		// 请求IP
		clientIP := c.ClientIP()

		// 日志格式
		logger.Infof("| %3d | %13v | %15s | %s | %s |",
			statusCode,
			latencyTime,
			clientIP,
			reqMethod,
			reqUri,
		)
	}
}

// 日志记录到 MongoDB
func LoggerToMongo() gin.HandlerFunc {
	return func(c *gin.Context) {
		
	}
}

// 日志记录到 ES
func LoggerToES() gin.HandlerFunc {
	return func(c *gin.Context) {

	}
}

// 日志记录到 MQ
func LoggerToMQ() gin.HandlerFunc {
	return func(c *gin.Context) {

	}
}

В журнале middleware написано, как его назвать?

Просто добавьте в main.go:

engine := gin.Default() //在这行后新增
engine.Use(middleware.LoggerToFile())

Запустите его и посмотрите лог:

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

этоtime="2019-07-17T22:10:45+08:00", этот формат времени не тот, что нам нужен, что нам делать?

Время должно быть отформатировано и измененоlogger.SetFormatter

//设置日志格式
logger.SetFormatter(&logrus.TextFormatter{
	TimestampFormat:"2006-01-02 15:04:05",
})

Выполните следующее, а затем просмотрите журнал:

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

Время стало нормальным.

Мне не нравится текстовый формат, мне нравится формат JSON, что мне делать?

//设置日志格式
logger.SetFormatter(&logrus.JSONFormatter{
	TimestampFormat:"2006-01-02 15:04:05",
})

Выполните следующее, а затем просмотрите журнал:

{"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"}

В msg слишком много информации, неудобно просматривать, что делать?

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

Выполните следующее, а затем просмотрите журнал:

{"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"}

Объяснять:time,msg,levelЭти параметры автоматически добавляются logrus.

Поддерживает ли logrus выходные имена файлов и номера строк?

Не поддерживается, ответ автора слишком требователен к производительности.

Тем не менее, некоторые люди в Интернете реализовали его с помощью Hook, поэтому, решив использовать его в производственной среде, не забудьте провести тестирование производительности.

Поддерживает ли logrus разделение логов?

Не поддерживается, но есть способы добиться этого.

1. Можно использоватьLinux logrotate, который обрабатывается единообразно при эксплуатации и обслуживании.

2, можно использоватьfile-rotatelogsвыполнить.

Пакеты необходимо импортировать:

github.com/lestrrat-go/file-rotatelogs

github.com/rifflock/lfshook

Вот полный код:

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"
)

// 日志记录到文件
func LoggerToFile() gin.HandlerFunc {

	logFilePath := config.Log_FILE_PATH
	logFileName := config.LOG_FILE_NAME

	// 日志文件
	fileName := path.Join(logFilePath, logFileName)

	// 写入文件
	src, err := os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY, os.ModeAppend)
	if err != nil {
		fmt.Println("err", err)
	}

	// 实例化
	logger := logrus.New()

	// 设置输出
	logger.Out = src

	// 设置日志级别
	logger.SetLevel(logrus.DebugLevel)

	// 设置 rotatelogs
	logWriter, err := rotatelogs.New(
		// 分割后的文件名称
		fileName + ".%Y%m%d.log",

		// 生成软链,指向最新日志文件
		rotatelogs.WithLinkName(fileName),

		// 设置最大保存时间(7天)
		rotatelogs.WithMaxAge(7*24*time.Hour),

		// 设置日志切割时间间隔(1天)
		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",
	})

	// 新增 Hook
	logger.AddHook(lfHook)

	return func(c *gin.Context) {
		// 开始时间
		startTime := time.Now()

		// 处理请求
		c.Next()

		// 结束时间
		endTime := time.Now()

		// 执行时间
		latencyTime := endTime.Sub(startTime)

		// 请求方式
		reqMethod := c.Request.Method

		// 请求路由
		reqUri := c.Request.RequestURI

		// 状态码
		statusCode := c.Writer.Status()

		// 请求IP
		clientIP := c.ClientIP()

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

// 日志记录到 MongoDB
func LoggerToMongo() gin.HandlerFunc {
	return func(c *gin.Context) {
		
	}
}

// 日志记录到 ES
func LoggerToES() gin.HandlerFunc {
	return func(c *gin.Context) {

	}
}

// 日志记录到 MQ
func LoggerToMQ() gin.HandlerFunc {
	return func(c *gin.Context) {

	}
}

Будет создан новый файлsystem.log.20190717.log, содержимое журнала соответствует приведенному выше формату.

Наконец,logrusЕсть много расширяемых хуков, вы можете найти их в Интернете.

Некоторые читатели предположили, что просматривать код на мобильном телефоне неудобно, и рекомендуется обновить его на GitHub.

Теперь обновлено, адрес выглядит следующим образом:

GitHub.com/Бессердечный не…

Рекомендуемое чтение

Джин каркас

Основы

Эту статью можно переслать, пожалуйста, укажите автора и источник для пересылки, спасибо!