logrus 剖析之 formatter


使用

logrus 通過 formatter 來定義輸出日志的格式,具體例子如下:

package main

import (
	log "github.com/Sirupsen/logrus"
)

func main() {
	formatter := &log.TextFormatter{
    // 不需要彩色日志
		DisableColors:   true, 
    // 定義時間戳格式
		TimestampFormat: "2006-01-02 15:04:05",
	}
	log.SetFormatter(formatter)
	log.Printf("hello world")
}

打印的日志內容如下:

time="2019-11-07 17:41:20" level=info msg="hello world"

說明:

  • time: 日志的打印時間
  • level: 日志的等級
  • msg: 日志內容

分析

本身 formatter 是接口類型,只要實現該結構我們就可以自定義日志輸出格式:

// Any additional fields added with `WithField` or `WithFields` are also in
// `entry.Data`. Format is expected to return an array of bytes which are then
// logged to `logger.Out`.
type Formatter interface {
	Format(*Entry) ([]byte, error)
}

logrus 提供了兩種默認的日志輸出格式, TextFormatterJSONFormatter.上面的示例使用的就是TextFormatter.

TextFormatter

type TextFormatter struct {
	// Set to true to bypass checking for a TTY before outputting colors.
	ForceColors bool
  //不使用彩色日志
	DisableColors bool
	// Override coloring based on CLICOLOR and CLICOLOR_FORCE. - https://bixense.com/clicolors/
	EnvironmentOverrideColors bool
  // 是否打印時間戳
	DisableTimestamp bool
	// Enable logging the full timestamp when a TTY is attached instead of just
  // 是否按照時間戳格式打印,置為false則只打印從程序啟動到打印日志的時間差(單位:秒)
	FullTimestamp bool
  // 時間戳格式
	TimestampFormat string
  // 設置 fields 不排序
	DisableSorting bool
  // 設置 fields 的排序規則
	SortingFunc func([]string)
	// Disables the truncation of the level text to 4 characters.
	DisableLevelTruncation bool
	// QuoteEmptyFields will wrap empty fields in quotes if true
	QuoteEmptyFields bool
  // 是否打印日志到終端
	isTerminal bool
  // fieldMap
	// As an example:
	// formatter := &TextFormatter{
	//     FieldMap: FieldMap{
	//         FieldKeyTime:  "@timestamp",
	//         FieldKeyLevel: "@level",
	//         FieldKeyMsg:   "@message"}}
	FieldMap FieldMap
  // 設置 func 和 file 這兩個 field的輸出格式
	CallerPrettyfier func(*runtime.Frame) (function string, file string)
	terminalInitOnce sync.Once
}

TextFormatter 實現 Formatter接口

// Format renders a single log entry
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
	data := make(Fields)
	for k, v := range entry.Data {
		data[k] = v
	}
  // prefixFieldClashes 刪除默認的 4 個 field,防止沖突(msg, level, time, logrus_error)
	prefixFieldClashes(data, f.FieldMap, entry.HasCaller())
	keys := make([]string, 0, len(data))
	for k := range data {
		keys = append(keys, k)
	}
// 拼接待打印日志的各個元素
	var funcVal, fileVal string
// 拼接元素過程省略 ...
	f.terminalInitOnce.Do(func() { f.init(entry) })
// 修改時間戳
	timestampFormat := f.TimestampFormat
	if timestampFormat == "" {
		timestampFormat = defaultTimestampFormat
	}
	// 以下省略 ...
  // 打印換行符
	b.WriteByte('\n')
	return b.Bytes(), nil
}

JSONFormatter

// JSONFormatter formats logs into parsable json
type JSONFormatter struct {
	// TimestampFormat sets the format used for marshaling timestamps.
	TimestampFormat string

	// DisableTimestamp allows disabling automatic timestamps in output
	DisableTimestamp bool

	// DataKey allows users to put all the log entry parameters into a nested dictionary at a given key.
	DataKey string

	// FieldMap allows users to customize the names of keys for default fields.
	// As an example:
	// formatter := &JSONFormatter{
	//   	FieldMap: FieldMap{
	// 		 FieldKeyTime:  "@timestamp",
	// 		 FieldKeyLevel: "@level",
	// 		 FieldKeyMsg:   "@message",
	// 		 FieldKeyFunc:  "@caller",
	//    },
	// }
	FieldMap FieldMap

	// CallerPrettyfier can be set by the user to modify the content
	// of the function and file keys in the json data when ReportCaller is
	// activated. If any of the returned value is the empty string the
	// corresponding key will be removed from json fields.
	CallerPrettyfier func(*runtime.Frame) (function string, file string)

	// PrettyPrint will indent all json logs
	PrettyPrint bool
}

JSONFormatter的實現方式與TextFormatter類同,這里就不再贅述。總之logrusformatter實現比較簡單,常用參數也在注釋里進行了詳細的說明。

自定義 Formatter

這里我們自定義一個 formatter,這個 formatter會在打印的日志前后分別加上前綴和后綴。

package main

import (
	"bytes"
	"fmt"

	log "github.com/Sirupsen/logrus"
)

func main() {
  // 初始化自定義 formatter
	formatter := &MyFormatter{
		Prefix: "prefix",
		Suffix: "suffix",
	}
	log.SetFormatter(formatter)
	log.Infoln("hello world")
}

// MyFormatter 自定義 formatter
type MyFormatter struct {
	Prefix string
	Suffix string
}

// Format implement the Formatter interface
func (mf *MyFormatter) Format(entry *log.Entry) ([]byte, error) {
	var b *bytes.Buffer
	if entry.Buffer != nil {
		b = entry.Buffer
	} else {
		b = &bytes.Buffer{}
	}
// entry.Message 就是需要打印的日志
	b.WriteString(fmt.Sprintf("%s - %s - %s", mf.Prefix, entry.Message, mf.Suffix))
	return b.Bytes(), nil
}

打印結果如下:

prefix - hello world - suffix


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM