time="2018-08-11T19:10:15+08:00" level=warning msg="postgres_exporter is ready for scraping on 0.0.0.0:9295..." source="postgres_exporter/main.go:60:main()"
time="2018-08-11T19:10:17+08:00" level=error msg="!!!msb info not found" source="postgres/postgres_query.go:63:QueryPostgresInfo()"
time="2018-08-11T19:10:17+08:00" level=error msg="get postgres instances info failed, scrape metrics failed, error:msb env not found" source="collector/exporter.go:71:Scrape()"
日志本地文件分割
logrus本身不带日志本地文件分割功能,但是我们可以通过file-rotatelogs进行日志本地文件分割。 每次当我们写入日志的时候,logrus都会调用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",
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
使用上述本地日志文件切割的效果如下:

将日志发送到elasticsearch
将日志发送到elasticsearch是很多日志监控系统的选择,将logrus日志发送到elasticsearch的原理是在hook的每次fire调用时,使用golang的es客户端将日志信息写到elasticsearch。elasticsearch官方没有提供golang客户端,但是有很多第三方的go语言客户端可供使用,我们选择elastic。elastic提供了丰富的文档,以及Java中的流式接口,使用起来非常方便。
client, err := elastic.NewClient(elastic.SetURL("http://localhost:9200"))
if err != nil {
log.Panic(err)
tweet1 := Tweet{User: "olivere", Message: "Take Five", Retweets: 0}
put1, err := client.Index().
Index("twitter").
Type("tweet").
Id("1").
BodyJson(tweet1).
Do(context.Background())
考虑到logrus的Fields机制,可以实现如下数据格式:
msg := struct {
Host string
Timestamp string `json:"@timestamp"`
Message string
Data logrus.Fields
Level string
其中Host记录产生日志主机信息,在创建hook是指定。其他数据需要从logrus.Entry中取得。测试过程我们选择按照此原理实现的第三方HOOK:elogrus
。其使用如下:
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)
从Elasticsearch查询得到日志存储,效果如下:
GET http://localhost:9200/mylog/_search
HTTP/1.1 200 OK
content-type: application/json; charset=UTF-8
transfer-encoding: chunked
"took": 1,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
"hits": {
"total": 2474,
"max_score": 1.0,
"hits": [
"_index": "mylog",
"_type": "log",
"_id": "AWUw13jWnMZReb-jHQup",
"_score": 1.0,
"_source": {
"Host": "localhost",
"@timestamp": "2018-08-13T01:12:32.212818666Z",
"Message": "!!!msb info not found",
"Data": {},
"Level": "ERROR"
"_index": "mylog",
"_type": "log",
"_id": "AWUw13jgnMZReb-jHQuq",
"_score": 1.0,
"_source": {
"Host": "localhost",
"@timestamp": "2018-08-13T01:12:32.223103348Z",
"Message": "get postgres instances info failed, scrape metrics failed, error:msb env not found",
"Data": {
"source": "collector/exporter.go:71:Scrape()"
"Level": "ERROR"
//...
"_index": "mylog",
"_type": "log",
"_id": "AWUw2f1enMZReb-jHQu_",
"_score": 1.0,
"_source": {
"Host": "localhost",
"@timestamp": "2018-08-13T01:15:17.212546892Z",
"Message": "!!!msb info not found",
"Data": {
"source": "collector/exporter.go:71:Scrape()"
"Level": "ERROR"
"_index": "mylog",
"_type": "log",
"_id": "AWUw2NhmnMZReb-jHQu1",
"_score": 1.0,
"_source": {
"Host": "localhost",
"@timestamp": "2018-08-13T01:14:02.21276903Z",
"Message": "!!!msb info not found",
"Data": {},
"Level": "ERROR"
Response code: 200 (OK); Time: 16ms; Content length: 3039 bytes
将日志发送到其他位置
将日志发送到日志中心也是logrus所提倡的,虽然没有提供官方支持,但是目前Github上有很多第三方hook可供使用:
- 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)。
等等,上述第三方hook我这里没有具体验证,大家可以根据需要自行尝试。
其他注意事项
- Fatal处理
和很多日志框架一样,logrus的Fatal系列函数会执行os.Exit(1)。但是logrus提供可以注册一个或多个fatal handler函数的接口logrus.RegisterExitHandler(handler func() {} ),让logrus在执行os.Exit(1)之前进行相应的处理。fatal handler可以在系统异常时调用一些资源释放api等,让应用正确的关闭。
- 线程安全
默认情况下,logrus的api都是线程安全的,其内部通过互斥锁来保护并发写。互斥锁工作于调用hooks或者写日志的时候,如果不需要锁,可以调用logger.SetNoLock()来关闭之。可以关闭logrus互斥锁的情形包括:
- 没有设置hook,或者所有的hook都是线程安全的实现。
- 写日志到logger.Out已经是线程安全的了,如logger.Out已经被锁保护,或者写文件时,文件是以O_APPEND方式打开的,并且每次写操作都小于4k。
文件名与行号logrus的一个很致命的问题就是没有提供文件名和行号,这在大型项目中通过日志定位问题时有诸多不便。Github上的logrus的issue#63:Log filename and line number创建于2014年,四年过去了仍是open状态~~~网上给出的解决方案分位两类,一就是自己实现一个hook;二就是通过装饰器包装logrus.Entry。两种方案网上都有很多代码,但...
日志是程序中必不可少的一个环节,由于Go语言内置的日志库功能比较简洁,我们在实际开发中通常会选择使用第三方的日志库来进行开发。本文介绍了logrus这个日志库的基本使用。
logrus介绍
Logrus是Go(golang)的结构化logger,与标准库logger完全API兼容。
它有以下特点:
完全兼容标准日志库,拥有七种日志级别:Trace,Debug,Info,Warning,Error,FatalandPanic。
可扩展的Hook机制,允许使用者通过Hook的方式将日志分发...
下面示例代码中的一些import我没做校验,我只是从我的一个测试代码里抠出来的,出现一些错误自己简单处理下就可以用。
logrus简介
logrus是一个可插拔的、结构化的日志框架。
logrus拥有六种日志级别:debug、info、warn、error、fatal和panic
可扩展的Hook机制:
允许使用者通过hook的方式将日志分发到任意地方,如本地文件系统、标准输出、logs...
logrus的初始化启动,详细使用
今天也是初次接触这个组件,来进行日志存储,自己也是俺就半天,想要所有的错误日志放到一个错误日志中,所首先创建一个日志文件。
自己也是没有找到相关的官方文档,就在gitee上直接查看的文档,
package log
import (
"fmt"
"github.com/sirupsen/logrus"
"time"
var log = logrus.New()
func Init() {
file,err := os.OpenFile
logrus是go的一个日志框架,它最让人激动的应该是hook机制,可以在初始化时为logrus添加hook,logrus可以实现各种扩展功能,可以将日志输出到elasticsearch和activemq等中间件去,甚至可以输出到你的email和叮叮中去,不要问为为什么可以发现可以输入到叮叮中去,都是泪,手动笑哭!
言归正传,这里就简单的通过hook机制将文件输出到本地磁盘。
go get github.com/sirupsen/logrus
logrus和go lib里面一样有6个等级,可以直接调用
logrus.Debug("Useful debugging inform
```go
logrus.SetLevel(logrus.DebugLevel)
logrus.SetFormatter(&logrus.TextFormatter{})
logrus.SetOutput(os.Stdout)
最后,在代码中使用logrus记录日志:
```go
logrus.Info("This is an info message")
logrus.Warn("This is a warning message")
logrus.Error("This is an error message")
以上就是一个基本的logrus使用示例。当然,logrus还提供了其他丰富的功能,如日志文件的输出、钩子函数等,可以根据自己的需求进行选择和使用。