logrus日志配置

代码

package log

import (
	"bytes"
	"net/http"
	"os"
	"runtime"
	"strconv"
	"strings"
	"time"

	"raysync-ftp/common"
	"raysync-ftp/config"

	"github.com/gin-gonic/gin"
	rotatelogs "github.com/lestrrat-go/file-rotatelogs"
	"github.com/sirupsen/logrus"
)

// -ldflags "-X raysync-ftp/log.mode=release"

const (
	green   = "\033[97;42m"
	white   = "\033[90;47m"
	yellow  = "\033[90;43m"
	red     = "\033[97;41m"
	blue    = "\033[97;44m"
	magenta = "\033[97;45m"
	cyan    = "\033[97;46m"
	reset   = "\033[0m"
)

func getLogLevelWithConsoleColor(level logrus.Level, writer *bytes.Buffer) {
	switch level {
	case logrus.PanicLevel, logrus.FatalLevel, logrus.ErrorLevel:
		writer.WriteString("\033[91m") // 红色
	case logrus.WarnLevel:
		writer.WriteString("\033[93m") // 黄色
	case logrus.InfoLevel:
		writer.WriteString("\033[92m") // 绿色
	case logrus.DebugLevel:
		writer.WriteString("\033[96m") // 蓝色
	case logrus.TraceLevel:
		writer.WriteString("\033[96m") // 蓝色
	}
	writer.WriteString(strings.ToUpper(level.String()))
	writer.WriteString("\033[0m")
}

type Formatter struct {
	TimestampFormat string
	ForceColor      bool
}

func (f *Formatter) Format(entry *logrus.Entry) ([]byte, error) {
	buffer := entry.Buffer
	if buffer == nil {
		buffer = &bytes.Buffer{}
	}

	buffer.WriteString("[")
	buffer.WriteString(entry.Time.Format(f.TimestampFormat))
	buffer.WriteString("] [")

	if f.ForceColor {
		getLogLevelWithConsoleColor(entry.Level, buffer)
	} else {
		buffer.WriteString(strings.ToUpper(entry.Level.String()))
	}

	buffer.WriteString("] ")

	if entry.Caller != nil {
		idx := strings.LastIndexByte(entry.Caller.File, '/')
		idx = strings.LastIndexByte(entry.Caller.File[:idx], '/')

		buffer.WriteString("[")
		buffer.WriteString(entry.Caller.File[idx+1:])
		buffer.WriteByte(':')
		buffer.WriteString(strconv.Itoa(entry.Caller.Line))
		buffer.WriteString("] ")

		//idx = strings.LastIndexByte(entry.Caller.Function, '/')
		//buffer.WriteByte('[')
		//buffer.WriteString(entry.Caller.Function[idx+1:])
		//buffer.WriteString("] ")
	}

	buffer.WriteString(entry.Message)
	buffer.WriteByte('\n')
	return buffer.Bytes(), nil
}

// 日志初始化
func Init(dir string) {
	if common.Mode == "release" && dir != "" {
		logs, _ := rotatelogs.New(dir+"/raysync-ftp_%Y-%m-%d.log",
			rotatelogs.WithMaxAge(30*24*time.Hour),
			rotatelogs.WithLinkName(dir+"/raysync-ftp.log"),
		)
		logrus.SetOutput(logs)
	} else {
		logrus.SetOutput(os.Stdout)
	}

	logrus.SetFormatter(&Formatter{
		TimestampFormat: "2006-01-02 15:04:05.000 UTC-07:00",
		ForceColor:      runtime.GOOS != "windows",
	})

	if common.Mode != "release" {
		logrus.SetLevel(logrus.DebugLevel)
	} else {
		l, err := logrus.ParseLevel(config.GetLogLevel())
		if err != nil {
			logrus.SetLevel(l)
		}
	}

	logrus.SetReportCaller(true)

	logrus.Infof(`build information: build time %v, go version %v, platform %v/%v`, common.BuildDate, runtime.Version(), runtime.GOOS, runtime.GOARCH)

}

// StatusCodeColor is the ANSI color for appropriately logging http status code to a terminal.
func StatusCodeColor(code int) string {
	switch {
	case code >= http.StatusOK && code < http.StatusMultipleChoices:
		return green
	case code >= http.StatusMultipleChoices && code < http.StatusBadRequest:
		return white
	case code >= http.StatusBadRequest && code < http.StatusInternalServerError:
		return yellow
	default:
		return red
	}
}

// MethodColor is the ANSI color for appropriately logging http method to a terminal.
func MethodColor(method string) string {
	switch method {
	case http.MethodGet:
		return blue
	case http.MethodPost:
		return cyan
	case http.MethodPut:
		return yellow
	case http.MethodDelete:
		return red
	case http.MethodPatch:
		return green
	case http.MethodHead:
		return magenta
	case http.MethodOptions:
		return white
	default:
		return reset
	}
}

func GinLogrus() gin.HandlerFunc {
	return func(c *gin.Context) {
		// Start timer
		start := time.Now()
		path := c.Request.URL.Path
		raw := c.Request.URL.RawQuery

		// Process request
		c.Next()

		// Log only when path is not being skipped

		// Stop timer
		timeStamp := time.Now()
		latency := timeStamp.Sub(start)

		clientIP := c.ClientIP()
		method := c.Request.Method
		statusCode := c.Writer.Status()
		errorMessage := c.Errors.ByType(gin.ErrorTypePrivate).String()

		if raw != "" {
			path = path + "?" + raw
		}

		var statusColor, methodColor, resetColor string
		if runtime.GOOS != "windows" {
			statusColor = StatusCodeColor(statusCode)
			methodColor = MethodColor(method)
			resetColor = reset
		}

		// IP Method Path StatusCode UseTime Error
		logrus.Infof("[%s] [%s %s %s] [%s] [%s %d %s] | %v | %s",
			clientIP,
			methodColor, method, resetColor,
			path,
			statusColor, statusCode, resetColor,
			latency,
			errorMessage,
		)
	}
}

输出效果

image-20210829235028202