1.logrus特點
golang標准庫的日志框架很簡單,logrus框架的特點:
1)完全兼容標准日志庫
六種日志級別:debug, info, warn, error, fatal, panic
2)可擴展的Hook機制
允許使用者通過Hook的方式將日志分發到任意地方,如本地文件系統,logstash,elasticsearch或者mq等,或者通過Hook定義日志內容和格式等
3)可選的日志輸出格式
內置了兩種日志格式JSONFormater和TextFormatter,還可以自定義日志格式
4)Field機制
通過Filed機制進行結構化的日志記錄
5)線程安全
logrus不提供的功能如下:
1)沒有提供行號和文件名的支持
2)輸出到本地文件系統沒有提供日志分割功能
3)沒有提供輸出到ELK等日志處理中心的功能
這些功能都可以通過自定義hook來實現
2.使用示例
package main
import (
log "github.com/sirupsen/logrus"
)
func main() {
log.WithFields(log.Fields{
"animal": "walrus",
}).Info("a walrus appears")
}
運行結果:
time="2019-01-24T18:43:57+08:00" level=info msg="a walrus appears" animal=walrus
3.設置log的參數
func init(){
log.SetFormatter(&log.JSONFormatter{})
log.SetOutput(os.Stdout)
log.SetLevel(log.InfoLevel)
}
運行結果:
{"animal":"walrus","level":"info","msg":"a walrus appears","time":"2019-01-24T18:51:00+08:00"}
4.創建Logger實例
logrus有一個默認的Logger
當一個應用中,需要向多個地方輸出時,需要不同的Logger實例
var log = logrus.New()
可以使用以上語句,創建Logger實例
package main
import (
"github.com/sirupsen/logrus"
"os"
)
var log = logrus.New()
func main() {
file ,err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666)
if err == nil{
log.Out = file
}else{
log.Info("Failed to log to file")
}
log.WithFields(logrus.Fields{
"filename": "123.txt",
}).Info("打開文件失敗")
}
運行結果:
logrus.log文件
time="2019-01-24T19:02:21+08:00" level=info msg="打開文件失敗" filename=123.txt
5.Fields
1)作用
結構化信息記錄,傳統的記錄方式如:
log.Fatalf("Failed to send event %s to topic %s with key %d", event, topic, key)
在logrus中不提倡這樣寫,鼓勵使用Fields結構化日志內容,如:
log.WithFields(log.Fields{
"event": event,
"topic": topic,
"key": key,
}).Fatal("Failed to send event")
2)固定Fields
可以固定Fields不用每次都寫
package main
import (
"github.com/sirupsen/logrus"
)
var log = logrus.New()
func main() {
entry := logrus.WithFields(logrus.Fields{
"name": "test",
})
entry.Info("message1")
entry.Info("message2")
}
運行結果:
time="2019-01-24T19:04:51+08:00" level=info msg=message1 name=test
time="2019-01-24T19:04:51+08:00" level=info msg=message2 name=test
6.hook
hook的原理是,在logrus寫入日志時攔截,修改logrus.Entry
type Hook interface {
Levels() []Level
Fire(*Entry) error
}
使用示例:
自定義一個hook DefaultFieldHook,在所有級別的日志消息中加入默認字段appName="myAppName"
type DefaultFieldHook struct {
}
func (hook *DefaultFieldHook) Fire(entry *log.Entry) error {
entry.Data["appName"] = "MyAppName"
return nil
}
func (hook *DefaultFieldHook) Levels() []log.Level {
return log.AllLevels
}
在初始化時,調用logrus.AddHook(hook)添加響應的hook即可
7.記錄文件名和行號
8.日志文件本地分割
通過hook插件file-rotatelogs進行日志本地文件分割
import (
"github.com/lestrrat-go/file-rotatelogs"
"github.com/rifflock/lfshook"
log "github.com/sirupsen/logrus"
"time"
)
func newLfsHook(logLevel *string, maxRemainCnt uint) log.Hook {
writer, err := rotatelogs.New(
logName+".%Y%m%d%H",
// WithLinkName為最新的日志建立軟連接,以方便隨着找到當前日志文件
rotatelogs.WithLinkName(logName),
// WithRotationTime設置日志分割的時間,這里設置為一小時分割一次
rotatelogs.WithRotationTime(time.Hour),
// WithMaxAge和WithRotationCount二者只能設置一個,
// WithMaxAge設置文件清理前的最長保存時間,
// WithRotationCount設置文件清理前最多保存的個數。
//rotatelogs.WithMaxAge(time.Hour*24),
rotatelogs.WithRotationCount(maxRemainCnt),
)
if err != nil {
log.Errorf("config local file system for logger error: %v", err)
}
level, ok := logLevels[*logLevel]
if ok {
log.SetLevel(level)
} else {
log.SetLevel(log.WarnLevel)
}
lfsHook := lfshook.NewHook(lfshook.WriterMap{
log.DebugLevel: writer,
log.InfoLevel: writer,
log.WarnLevel: writer,
log.ErrorLevel: writer,
log.FatalLevel: writer,
log.PanicLevel: writer,
}, &log.TextFormatter{DisableColors: true})
return lfsHook
}
9.日志文件發送到elasticsearch
將logrus日志發送到elasticsearch的原理是在hook的每次fire調用時,使用golang的es客戶端將日志信息寫入elasticsearch
import (
"github.com/olivere/elastic"
"gopkg.in/sohlich/elogrus"
)
func initLog() {
client, err := elastic.NewClient(elastic.SetURL("http://localhost:9200"))
if err != nil {
log.Panic(err)
}
hook, err := elogrus.NewElasticHook(client, "localhost", log.DebugLevel, "mylog")
if err != nil {
log.Panic(err)
}
log.AddHook(hook)
}
10.將日志發送到其他位置
logrus_amqp:Logrus hook for Activemq。
logrus-logstash-hook:Logstash hook for logrus。
mgorus:Mongodb Hooks for Logrus。
logrus_influxdb:InfluxDB Hook for Logrus。
logrus-redis-hook:Hook for Logrus which enables logging to RELK stack (Redis, Elasticsearch, Logstash and Kibana)。
11.Fatal處理
和很多日志框架一樣,logrus的Fatal系列函數會執行os.Exit(1)。但是logrus提供可以注冊一個或多個fatal handler函數的接口logrus.RegisterExitHandler(handler func() {} ),讓logrus在執行os.Exit(1)之前進行相應的處理。fatal handler可以在系統異常時調用一些資源釋放api等,讓應用正確的關閉。
