golang echo 程式碼詳解之 log 篇
阿新 • • 發佈:2018-12-21
echo 自帶的 log 庫
log 結構
echo 框架的 log 結構體是 echo.Echo 結構體的一個屬性
type Echo struct {
...
Logger Logger
}
而 logger 是個這樣的介面
type ( // Logger defines the logging interface. Logger interface { Output() io.Writer SetOutput(w io.Writer) Prefix() string SetPrefix(p string) Level() log.Lvl SetLevel(v log.Lvl) Print(i ...interface{}) Printf(format string, args ...interface{}) Printj(j log.JSON) Debug(i ...interface{}) Debugf(format string, args ...interface{}) Debugj(j log.JSON) Info(i ...interface{}) Infof(format string, args ...interface{}) Infoj(j log.JSON) Warn(i ...interface{}) Warnf(format string, args ...interface{}) Warnj(j log.JSON) Error(i ...interface{}) Errorf(format string, args ...interface{}) Errorj(j log.JSON) Fatal(i ...interface{}) Fatalj(j log.JSON) Fatalf(format string, args ...interface{}) Panic(i ...interface{}) Panicj(j log.JSON) Panicf(format string, args ...interface{}) } )
一般的 log 也都實現了這些方法,所以我們可以使用自己的 log 包替換這個。而作者是使用的 github.com/labstack/gommon/log
這個包。
到這裡,自定義 log 級別,輸出位置都一目瞭然了。
預設的 log
在生成 echo.Echo 例項的時候,會初始化一個預設的 log。
// 初始化一個 Echo 例項 func New() (e *Echo) { e = &Echo{ ... Logger: log.New("echo"), } ... e.Logger.SetLevel(log.ERROR) // 預設日誌級別 ... return } // log.New() 方法是這樣的 func New(prefix string) (l *Logger) { l = &Logger{ level: INFO, prefix: prefix, template: l.newTemplate(defaultHeader), color: color.New(), // 這個是讓不同級別的日誌在控制檯顯示不用顏色的。 bufferPool: sync.Pool{ New: func() interface{} { return bytes.NewBuffer(make([]byte, 256)) }, }, } l.initLevels() // 同樣是處理顏色 l.SetOutput(output()) // 預設是 os.Stdout return }
這裡的 template 是 github.com/valyala/fasttemplate
包的物件,是一個簡單的模版引擎,用來控制 log 的輸出樣式。
預設的樣式是這樣的
defaultHeader = `{"time":"${time_rfc3339_nano}","level":"${level}","prefix":"${prefix}",` +
`"file":"${short_file}","line":"${line}"}`
這裡的很多配置都和官方 log 的配置類似,也顯示了檔名和行號。這裡預設支援的時間格式只有兩種
time_rfc3339 // "2006-01-02T15:04:05Z07:00" time_rfc3339_nano // "2006-01-02T15:04:05.999999999Z07:00"
需要更深層次的定製的話就需要修改或者替換 log 包了。
log 中介軟體
通過這樣的方法來註冊 log 中介軟體,這個中介軟體主要用來針對 http 請求列印日誌。
// 使用預設的配置
e.Use(middleware.Logger())
// 自定義配置
// 自定義配置只支援 Format 和 Output 兩個屬性
e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
Format: "method=${method}, uri=${uri}, status=${status}\n",
Output os.Stdout,
}))
預設的配置是這樣的
DefaultLoggerConfig = LoggerConfig{
...
Format: `{"time":"${time_rfc3339_nano}","id":"${id}","remote_ip":"${remote_ip}","host":"${host}",` +
`"method":"${method}","uri":"${uri}","status":${status}, "latency":${latency},` +
`"latency_human":"${latency_human}","bytes_in":${bytes_in},` +
`"bytes_out":${bytes_out}}` + "\n",
Output: os.Stdout,
colorer: color.New(),
}
自定義配置支援下面這些欄位
- time_unix
- time_unix_nano
- time_rfc3339
- time_rfc3339_nano
// 時間上多了兩個 unix 時間戳型別
- id (Request ID)
- remote_ip
- uri
- host
- method
- path
- referer
- user_agent
- status
// 常規的 http 請求內容
- latency (In nanoseconds)
- latency_human (Human readable)
// 這個可以算作處理日誌花的時間
- bytes_in (Bytes received)
- bytes_out (Bytes sent)
// request 請求和 response 響應的大小
- header:<NAME>
- query:<NAME>
- form:<NAME>
- cookie:<NAME>
// 這幾個可以拿到具體內容,分別用下面的方法取得
// tag 就是上面的欄位
// c.Request().Header.Get(tag[7:])
// c.QueryParam(tag[6:])
// c.FormValue(tag[5:])
// c.Cookie(tag[7:]
整個日誌中介軟體在這裡 https://github.com/labstack/echo/blob/master/middleware/logger.go
,不符合也可以根據需要重新實現一個。
後記
之前翻譯了 echo 的中文文件 http://go-echo.org,發現文件有很多地方沒有說清楚,就萌生了邊看程式碼邊補充使用文件的想法。拖了很久終於開工了,拿最簡單的 log 開篇,後面會陸續更新關於 echo 其他模組的介紹。