Logrus 日志
1
| go get github.com/sirupsen/logrus
|
1 2 3 4 5 6 7 8 9 10 11
| import ( log "github.com/sirupsen/logrus" )
func main(){ log.SetFormatter(&log.JSONFormatter{ TimestampFormat:"2006-01-02 15:04:05", }) // 日志的输出级别 log.SetLevel(log.InfoLevel) }
|
1. 实现日志分割
Linux logrotate
file-rotatelogs
1
| go get github.com/lestrrat-go/file-rotatelogs
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import ( rotatelogs "github.com/lestrrat-go/file-rotatelogs" "github.com/sirupsen/logrus" )
func main() {
content, err := rotatelogs.New( "/var/log/cli.log."+"-%Y%m%d%H%M", rotatelogs.WithLinkName("/var/log/cli.log"), rotatelogs.WithMaxAge(6*time.Minute), rotatelogs.WithRotationTime(time.Minute), rotatelogs.ForceNewFile(), ) logrus.SetOutput(content) }
|
强行生成新的日志文件
1 2 3 4 5 6 7 8
| rl := rotatelogs.New(...)
signal.Notify(ch, syscall.SIGHUP)
go func(ch chan os.Signal) { <-ch rl.R }
|
2. 自定义Logger
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package main
import ( "github.com/sirupsen/logrus" "os" )
// logrus提供了New()函数来创建一个logrus的实例. // 项目中,可以创建任意数量的logrus实例. var log = logrus.New()
func main() { // 为当前logrus实例设置消息的输出,同样地, // 可以设置logrus实例的输出到任意io.writer log.Out = os.Stdout
// 为当前logrus实例设置消息输出格式为json格式. // 同样地,也可以单独为某个logrus实例设置日志级别和hook,这里不详细叙述. log.Formatter = &logrus.JSONFormatter{}
log.WithFields(logrus.Fields{ "animal": "walrus", "size": 10, }).Info("A group of walrus emerges from the ocean") }
|
3. hook接口方法
1 2 3 4 5 6
|
type Hook interface { Levels() []Level Fire(*Entry) error }
|
一个简单自定义hook如下,DefaultFieldHook定义会在所有级别的日志消息中加入默认字段appName=”myAppName”.
1 2 3 4 5 6 7 8 9 10 11
| 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 }
|
hook
的使用也很简单,在初始化前调用log.AddHook(hook)
添加相应的hook
即可.
logrus
官方仅仅内置了syslog
的hook
.
3.1 Email Hook
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| func Email(){ logger:= logrus.New() hook, err := logrus_mail.NewMailAuthHook("testapp", "smtp.163.com",25,"username@163.com","username@163.com","smtp_name","smtp_password") if err == nil { logger.Hooks.Add(hook) } var filename="123.txt" contextLogger :=logger.WithFields(logrus.Fields{ "file":filename, "content": "GG", }) contextLogger.Time=time.Now() contextLogger.Message="这是一个hook发来的邮件" contextLogger.Level=logrus.FatalLevel
hook.Fire(contextLogger) }
|
3.2 Logrus-Hook-Slack
1
| go get github.com/johntdyer/slackrus
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| package main
import ( logrus "github.com/sirupsen/logrus" "github.com/johntdyer/slackrus" "os" )
func main() {
logrus.SetFormatter(&logrus.JSONFormatter{})
logrus.SetOutput(os.Stderr)
logrus.SetLevel(logrus.DebugLevel) logrus.AddHook(&slackrus.SlackrusHook{ HookURL: "https://hooks.slack.com/services/abc123/defghijklmnopqrstuvwxyz", AcceptedLevels: slackrus.LevelThreshold(logrus.DebugLevel), Channel: "#slack-testing", IconEmoji: ":ghost:", Username: "foobot", })
logrus.Warn("warn") logrus.Info("info") logrus.Debug("debug") }
|
3.3 Logrus-Hook 日志分隔
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| 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", rotatelogs.WithLinkName(logName),
rotatelogs.WithRotationTime(time.Hour),
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 }
|
3.4 Logrus-Dingding-Hook 阿里钉钉群机器人
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
| package utils
import ( "bytes" "encoding/json" "fmt" "log" "net/http" "github.com/sirupsen/logrus" )
var allLvls = []logrus.Level{ logrus.DebugLevel, logrus.InfoLevel, logrus.WarnLevel, logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel, }
func NewDingHook(url, app string, thresholdLevel logrus.Level) *dingHook { temp := []logrus.Level{} for _, v := range allLvls { if v <= thresholdLevel { temp = append(temp, v) } } hook := &dingHook{apiUrl: url, levels: temp, appName: app} hook.jsonBodies = make(chan []byte) hook.closeChan = make(chan bool) go hook.startDingHookQueueJob() return hook }
func (dh *dingHook) startDingHookQueueJob() { for { select { case <-dh.closeChan: return case bs := <-dh.jsonBodies: res, err := http.Post(dh.apiUrl, "application/json", bytes.NewBuffer(bs)) if err != nil { log.Println(err) } if res != nil && res.StatusCode != 200 { log.Println("dingHook go chan http post error", res.StatusCode) } } }
}
type dingHook struct { apiUrl string levels []logrus.Level appName string jsonBodies chan []byte closeChan chan bool }
func (dh *dingHook) Levels() []logrus.Level { return dh.levels }
func (dh *dingHook) Fire2(e *logrus.Entry) error { msg, err := e.String() if err != nil { return err } dm := dingMsg{Msgtype: "text"} dm.Text.Content = fmt.Sprintf("%s \n %s", dh.appName, msg) bs, err := json.Marshal(dm) if err != nil { return err } dh.jsonBodies <- bs return nil } func (dh *dingHook) Fire(e *logrus.Entry) error { msg, err := e.String() if err != nil { return err } dm := dingMsg{Msgtype: "text"} dm.Text.Content = fmt.Sprintf("%s \n %s", dh.appName, msg) bs, err := json.Marshal(dm) if err != nil { return err } res, err := http.Post(dh.apiUrl, "application/json", bytes.NewBuffer(bs)) if err != nil { return err } if res != nil && res.StatusCode != 200 { return fmt.Errorf("dingHook go chan http post error %d", res.StatusCode) } return nil }
type dingMsg struct { Msgtype string `json:"msgtype"` Text struct { Content string `json:"content"` } `json:"text"` }
|
使用方法
1 2 3 4 5 6 7 8 9 10 11
| func initSlackLogrus() { lvl := logrus.InfoLevel apiUrl := viper.GetString("logrus.dingHookUrl") dingHook := utils.NewDingHook(apiUrl, "Felix", lvl)
logrus.SetLevel(lvl) logrus.SetFormatter(&logrus.JSONFormatter{TimestampFormat: "06-01-02T15:04:05"}) logrus.SetReportCaller(true) logrus.AddHook(dingHook) }
|