1.logrus介绍:
导入包:
1
| go get -u github.com/sirupsen/logrus
|
1.1 logrus基础配置:
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
| var LogrusObj *logrus.Logger
func InitLog() { if LogrusObj != nil { file, err := setOutputFile() if err != nil { panic(err) } LogrusObj.SetOutput(file) return } logger := logrus.New() file, err := setOutputFile() if err != nil { panic(err) } logger.SetOutput(file) logger.SetLevel(logrus.DebugLevel) logger.SetFormatter(&logrus.JSONFormatter{ TimestampFormat: "2006-01-02 15:04:05", }) LogrusObj = logger }
|
setOutputFile
函数是设置日志输出的位置,这里的setOutputFile
函数如下:
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
| func setOutputFile() (*os.File, error) { now := time.Now() dir, err := os.Getwd() if err != nil { return nil, err } logFilePath := filepath.Join(dir, "/logs/")
_, err = os.Stat(logFilePath) if os.IsNotExist(err) { if err = os.MkdirAll(logFilePath, 0777); err != nil { log.Fatal(err) return nil, err } } logFileName := now.Format(FileNameLayOut) + ".log" fileName := filepath.Join(logFilePath, logFileName)
if _, err = os.Stat(fileName); err != nil { if os.IsNotExist(err) { if _, err = os.Create(fileName); err != nil { log.Fatal(err) return nil, err } } }
file, err := os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY, os.ModeAppend) if err != nil { return nil, err }
return file, err }
|
主要逻辑有以下:
- 获取项目的位置
- 使用
filepath.Join
将文件地址后加上log
- 使用
os.Stat
用于判断文件或文件夹是否存在,如果返回err是nil表明存在,如果不为nil则需要使用os.IsNotExists()
,如果返回true表明文件或文件夹不存在
- 文件夹不存在则创建,使用
os.MkdirAll(路径,权限)
。
- 文件夹存在,则可以组装日志文件的文件名,然后通过这个文件名去判断当前文件是否存在,如果不存在则创建。
- 如果文件存在则可以直接进行追加,需要注意这里需要提供flag。
os.O_APPEND|os.O_WRONLY, os.ModeAppend
分别表示以只写的方式,追加的方式,后面的os.ModeAppend
表示给写的权限并且只能写道末尾。
效果如图

1.2 logrus的其他配置:
logrus可以使用WithFields
添加自己的一个字段,如:
1 2 3 4 5 6 7
| logger := logrus.New() logger.SetLevel(logrus.DebugLevel) entry := logger.WithFields(logrus.Fields{ "作者": "cz", })
entry.Info("nihao")
|

可以使用entry.Data
返回的是一个map[string]interface{}
就是刚才设置WithFields
的值。
1.3 logrus的hook:
只需要实现hook
这个接口,就可以了。
logrus调用中添加AddHook(hook)
即可。
logrus的hook接口需要实现两个方法,如下:

其中Levels
方法是返回什么日志级别才会触发hook的,而Fire
则是具体实现hook的逻辑。
2.配置Es
引用库:
1
| github.com/elastic/go-elasticsearch
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| var EsClient *elasticsearch.Client
func InitEs() { esConn := fmt.Sprintf("http://%s:%s", "192.168.61.129", "9200") cfg := elasticsearch.Config{ Addresses: []string{esConn}, } client, err := elasticsearch.NewClient(cfg) if err != nil { log.Panic(err) } EsClient = client }
|
3.logrus实现日志推送
先定义一个结构体ElasticHook,其中需要实现Hook
接口:

ElasticHook结构体如图所示:
1 2 3 4 5 6 7 8 9
| type ElasticHook struct { Client *elasticsearch.Client Host string Index IndexNameFunc Level []logrus.Level Ctx context.Context CtxCancelFunc context.CancelFunc FireFunc FireFunc }
|
初始化es钩子:
1 2 3 4
| func NewElasticHook(client *elasticsearch.Client, host string, level logrus.Level, index string) (*ElasticHook, error) { return newElasticHookWithFunc(client, host, level, func() string { return index }) }
|
具体逻辑如图:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| func newElasticHookWithFunc(client *elasticsearch.Client, host string, level logrus.Level, indexFunc IndexNameFunc) (*ElasticHook, error) { var levels []logrus.Level for _, l := range logrus.AllLevels { if level >= l { levels = append(levels, l) } } ctx, cancelFunc := context.WithCancel(context.Background()) return &ElasticHook{ Client: client, Host: host, Index: indexFunc, Level: levels, Ctx: ctx, CtxCancelFunc: cancelFunc, FireFunc: syncFireFunc, }, nil }
|
传入的level需要进行比较,比较日志是大于或等于的才会保存在这个钩子中的Level
字段。
具体发送逻辑是syncFireFunc
这个函数,具体用法如下:
主要是操作es逻辑。
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
| func syncFireFunc(entry *logrus.Entry, hook *ElasticHook) error { msg := createMessage(entry, hook) data, err := json.Marshal(&msg) if err != nil { return err }
request := esapi.IndexRequest{ Index: hook.Index(), Body: bytes.NewReader(data), Refresh: "true", }
resp, err := request.Do(hook.Ctx, hook.Client) if err != nil { return err }
log.Println(resp.String())
return nil }
|
将这个赋值给ElasticHook
的FireFunc
,在调用钩子的时候调用即可。
最终使用curl --location 'http://localhost:9200/my_index/_search'\?pretty
即可查看到结果
4.完整代码
查看https://github.com/pow1e/es-logrus