简介
Zerolog
是一个高性能、零内存分配的 Go 日志库。
它为不需要垃圾回收的延迟敏感型应用程序提供结构化日志记录功能。
您可以以完全零分配的方式使用,这样在初始化记录器对象后,堆上不会再分配其他对象,从而防止触发垃圾回收。
Zerolog 包提供了一个专用于 JSON 输出的快速而简单的记录器。
Zerolog 的 API 旨在提供出色的开发人员体验和惊人的性能。其独特的链接 API 允许 zerolog 通过避免分配和反射来编写 JSON(或 CBOR)日志事件。
Uber 的zap库率先采用了这种方法。Zerolog 正在通过更易于使用的 API 和更出色的性能将这一概念提升到一个新的水平。
为了保持代码库和 API 的简单性,zerolog 只专注于高效的结构化日志记录。使用提供的(但效率低下)可以实现控制台上的漂亮日志记录zerolog.ConsoleWriter
。
官网
https://github.com/rs/zerolog
性能
基准测试结果
所有操作均无需分配(这些数字包括JSON 编码)
BenchmarkLogEmpty-8 100000000 19.1 ns/op 0 B/op 0 allocs/op
BenchmarkDisabled-8 500000000 4.07 ns/op 0 B/op 0 allocs/op
BenchmarkInfo-8 30000000 42.5 ns/op 0 B/op 0 allocs/op
BenchmarkContextFields-8 30000000 44.9 ns/op 0 B/op 0 allocs/op
BenchmarkLogFields-8 10000000 184 ns/op 0 B/op 0 allocs/op
记录一条消息和 10 个字段:
Library | Time | Bytes Allocated | Objects Allocated |
---|---|---|---|
zerolog | 767 ns/op | 552 B/op | 6 allocs/op |
⚡ zap | 848 ns/op | 704 B/op | 2 allocs/op |
⚡ zap (sugared) | 1363 ns/op | 1610 B/op | 20 allocs/op |
go-kit | 3614 ns/op | 2895 B/op | 66 allocs/op |
lion | 5392 ns/op | 5807 B/op | 63 allocs/op |
logrus | 5661 ns/op | 6092 B/op | 78 allocs/op |
apex/log | 15332 ns/op | 3832 B/op | 65 allocs/op |
log15 | 20657 ns/op | 5632 B/op | 93 allocs/op |
使用已经有10个上下文字段的记录器记录消息:
Library | Time | Bytes Allocated | Objects Allocated |
---|---|---|---|
zerolog | 52 ns/op | 0 B/op | 0 allocs/op |
⚡ zap | 283 ns/op | 0 B/op | 0 allocs/op |
⚡ zap (sugared) | 337 ns/op | 80 B/op | 2 allocs/op |
lion | 2702 ns/op | 4074 B/op | 38 allocs/op |
go-kit | 3378 ns/op | 3046 B/op | 52 allocs/op |
logrus | 4309 ns/op | 4564 B/op | 63 allocs/op |
apex/log | 13456 ns/op | 2898 B/op | 51 allocs/op |
log15 | 14179 ns/op | 2642 B/op | 44 allocs/op |
记录一个静态字符串,没有任何上下文或printf风格的模板:
Library | Time | Bytes Allocated | Objects Allocated |
---|---|---|---|
zerolog | 50 ns/op | 0 B/op | 0 allocs/op |
⚡ zap | 236 ns/op | 0 B/op | 0 allocs/op |
standard library | 453 ns/op | 80 B/op | 2 allocs/op |
⚡ zap (sugared) | 337 ns/op | 80 B/op | 2 allocs/op |
go-kit | 508 ns/op | 656 B/op | 13 allocs/op |
lion | 771 ns/op | 1224 B/op | 10 allocs/op |
logrus | 1244 ns/op | 1505 B/op | 27 allocs/op |
apex/log | 2751 ns/op | 584 B/op | 11 allocs/op |
log15 | 5181 ns/op | 1592 B/op | 26 allocs/op |
安装
go get -u github.com/rs/zerolog/log
缺省Logger
简单打印
package mainimport ("github.com/rs/zerolog/log"
)func main() {// 简单打印 默认是debug级别log.Print("Hello, World!") // {"level":"debug","time":"2025-01-14T16:35:03+08:00","message":"Hello, World!"}
}
带日志级别的日志
package mainimport ("github.com/rs/zerolog/log"
)func main() {// 带日志级别的日志// debuglog.Debug().Msg("Hello, World!") // {"level":"debug","time":"2025-01-14T16:35:03+08:00","message":"Hello, World!"}// infolog.Info().Msg("Hello, World!") // {"level":"info","time":"2025-01-14T16:35:03+08:00","message":"Hello, World!"}// warnlog.Warn().Msg("Hello, World!") // {"level":"warn","time":"2025-01-14T16:35:03+08:00","message":"Hello, World!"}// errorlog.Error().Msg("Hello, World!") // {"level":"error","time":"2025-01-14T16:35:03+08:00","message":"Hello, World!"}
}
设置日志级别
级别
- panic (
zerolog.PanicLevel
, 5) - fatal (
zerolog.FatalLevel
, 4) - error (
zerolog.ErrorLevel
, 3) - warn (
zerolog.WarnLevel
, 2) - info (
zerolog.InfoLevel
, 1) - debug (
zerolog.DebugLevel
, 0) - trace (
zerolog.TraceLevel
, -1)
package mainimport ("github.com/rs/zerolog""github.com/rs/zerolog/log"
)func main() {// 设置日志级别log.Logger = log.Level(zerolog.InfoLevel)log.Debug().Msg("Hello, World!") // 不会输出log.Info().Msg("Hello, World!") // {"level":"info","time":"2025-01-14T16:35:03+08:00","message":"Hello, World!"}log.Warn().Msg("Hello, World!") // {"level":"warn","time":"2025-01-14T16:35:03+08:00","message":"Hello, World!"}
}
设置时间格式
package mainimport ("github.com/rs/zerolog""github.com/rs/zerolog/log"
)func main() {log.Info().Msg("Hello, World!") // {"level":"info","time":"2025-01-14T16:46:32+08:00","message":"Hello, World!"}// 设置时间格式zerolog.TimeFieldFormat = "2006/01/02T15:04:05.9999"log.Info().Msg("Hello, World!") // {"level":"info","time":"2025/01/14T16:46:32.6623","message":"Hello, World!"}// 设置时间为时间戳zerolog.TimeFieldFormat = zerolog.TimeFormatUnixMslog.Info().Msg("Hello, World!") // {"level":"info","time":1736844392662,"message":"Hello, World!"}
}
自定义添加字段
在输出日志的时候添加字段
package mainimport ("github.com/rs/zerolog""github.com/rs/zerolog/log""time"
)func main() {// 在输出日志的时候添加字符串字段log.Info().Str("foo", "bar").Msg("Hello, World!")// {"level":"info","foo":"bar","time":"2025-01-14T16:56:49+08:00","message":"Hello, World!"}// 在输出日志的时候添加整型字段log.Info().Int("foo", 1).Msg("Hello, World!")// {"level":"info","foo":1,"time":"2025-01-14T16:56:49+08:00","message":"Hello, World!"}// 在输出日志的时候添加浮点型字段log.Info().Float64("foo", 1.2).Msg("Hello, World!")// {"level":"info","foo":1.2,"time":"2025-01-14T16:56:49+08:00","message":"Hello, World!"}// 在输出日志的时候添加布尔型字段log.Info().Bool("foo", true).Msg("Hello, World!")// {"level":"info","foo":true,"time":"2025-01-14T16:56:49+08:00","message":"Hello, World!"}// 在输出日志的时候添加时间字段log.Info().Time("foo", time.Now()).Msg("Hello, World!")// {"level":"info","foo":"2025-01-14T16:56:49+08:00","time":"2025-01-14T16:56:49+08:00","message":"Hello, World!"}// 在输出日志的时候字典log.Info().Dict("foo", zerolog.Dict().Str("bar", "baz")).Msg("Hello, World!")// {"level":"info","foo":{"bar":"baz"},"time":"2025-01-14T16:56:49+08:00","message":"Hello, World!"}
}
将上下文字段添加到全局记录器
package mainimport ("github.com/rs/zerolog/log"
)func main() {// 修改logger,在全局中添加字段,后面的日志都会携带这个字段log.Logger = log.With().Str("foo", "bar").Logger()log.Info().Msg("Hello, World!")// {"level":"info","foo":"bar","time":"2025-01-14T17:01:58+08:00","message":"Hello, World!"}
}
无级别或者无消息日志
无消息
package mainimport ("github.com/rs/zerolog/log"
)func main() {log.Info().Msg("") // {"level":"info","time":"2025-01-14T16:49:28+08:00"}log.Info().Send() // {"level":"info","time":"2025-01-14T16:49:28+08:00"}
}
无级别
package mainimport ("github.com/rs/zerolog/log"
)func main() {log.Log().Msg("") // {"time":"2025-01-14T16:49:28+08:00"}log.Log().Send() // {"time":"2025-01-14T16:49:28+08:00"}
}
错误日志
package mainimport ("fmt""github.com/rs/zerolog/log"
)func main() {// 普通错误日志log.Error().Msg("Hello World") // {"level":"error","time":"2025-01-14T17:05:07+08:00","message":"Hello World"}// 创建异常对象err := fmt.Errorf("Hello World")// 直接传出异常对象生成日志 有error字段,没有 message 字段的错误日志log.Err(err).Send()// {"level":"error","error":"Hello World","time":"2025-01-14T17:05:07+08:00"}// 直接传出异常对象生成日志 有error字段,有 message 字段的错误日志log.Err(err).Msg("这是错误消息的message字段值")// {"level":"error","error":"Hello World","time":"2025-01-14T17:05:07+08:00","message":"这是错误消息的message字段值"}
}
将文件和行号添加到日志中
长文件名格式
package mainimport ("github.com/rs/zerolog/log"
)func main() {log.Logger = log.With().Caller().Logger()log.Info().Msg("hello world")// Output: {"level": "info", "message": "hello world", "caller": "/go/src/your_project/main.go:21"}
}
短文件格式
package mainimport ("github.com/rs/zerolog""github.com/rs/zerolog/log""path/filepath""strconv"
)func main() {// 设置 行号序列化的方法zerolog.CallerMarshalFunc = func(pc uintptr, file string, line int) string {return filepath.Base(file) + ":" + strconv.Itoa(line)}log.Logger = log.With().Caller().Logger()log.Info().Msg("hello world")// Output: {"level": "info", "message": "hello world", "caller": "main.go:21"}
}
根据上下文传递子Logger
package mainimport ("context""github.com/rs/zerolog/log"
)func main() {ctx := log.With().Str("component", "module").Logger().WithContext(context.TODO())log.Ctx(ctx).Info().Msg("hello world")// Output: {"component":"module","level":"info","message":"hello world"}
}
自定义主要字段的名称
package mainimport ("github.com/rs/zerolog""github.com/rs/zerolog/log"
)func main() {zerolog.TimestampFieldName = "t"zerolog.LevelFieldName = "l"zerolog.MessageFieldName = "m"log.Info().Msg("hello world")// Output: {"l":"info","t":"2025-01-14T17:38:55+08:00","m":"hello world"}
}
集成 net/http
package mainimport ("github.com/rs/zerolog""github.com/rs/zerolog/hlog""github.com/justinas/alice""net/http""os""time"
)func main() {host := "local-hostname" // 定义主机名// 初始化 zerolog,添加时间戳和服务信息log := zerolog.New(os.Stdout).With().Timestamp().Str("role", "my-service").Str("host", host).Logger()// 创建 alice 中间件链c := alice.New()// 添加日志处理器,将日志输出到控制台c = c.Append(hlog.NewHandler(log))// 添加访问日志处理器,记录请求方法、URL、状态码、响应大小和耗时c = c.Append(hlog.AccessHandler(func(r *http.Request, status, size int, duration time.Duration) {hlog.FromRequest(r).Info().Str("method", r.Method).Str("url", r.URL.String()).Int("status", status).Int("size", size).Dur("duration", duration).Msg("")}))// 添加额外日志处理器,记录客户端 IP、User-Agent、Referer 和请求 IDc = c.Append(hlog.RemoteAddrHandler("ip"))c = c.Append(hlog.UserAgentHandler("user_agent"))c = c.Append(hlog.RefererHandler("referer"))c = c.Append(hlog.RequestIDHandler("req_id", "Request-Id"))// 最终请求处理器,记录自定义日志信息h := c.Then(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {hlog.FromRequest(r).Info().Str("user", "current user").Str("status", "ok").Msg("Something happened")}))// 注册路由并启动 HTTP 服务http.Handle("/", h)if err := http.ListenAndServe(":8080", nil); err != nil {log.Fatal().Err(err).Msg("Startup failed") // 如果启动失败,记录错误日志}
}
- 初始化日志:使用
zerolog
初始化日志,并添加时间戳和服务信息。 - 中间件链:使用
alice
创建中间件链,逐步添加日志处理器。 - 访问日志:记录每个请求的关键信息,如方法、URL、状态码等。
- 额外日志:记录客户端 IP、User-Agent、Referer 和请求 ID,丰富日志内容。
- 请求处理:在请求处理函数中记录自定义日志信息。
- 启动服务:注册路由并启动 HTTP 服务,处理启动失败的情况。
运行后,只要有访问8080端口的,都会打印日志
{"level": "info","role": "my-service","host": "local-hostname","ip": "127.0.0.1:30305","user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36","req_id": "cu33ouao7p78o742c5t0","user": "current user","status": "ok","time": "2025-01-14T18:29:13+08:00","message": "Something happened"
}
{"level": "info","role": "my-service","host": "local-hostname","ip": "127.0.0.1:30305","user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36","req_id": "cu33ouao7p78o742c5t0","method": "GET","url": "/","status": 0,"size": 0,"duration": 15.1797,"time": "2025-01-14T18:29:13+08:00"
}
{"level": "info","role": "my-service","host": "local-hostname","ip": "127.0.0.1:30305","user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36","referer": "http://127.0.0.1:8080/","req_id": "cu33ouao7p78o742c5tg","user": "current user","status": "ok","time": "2025-01-14T18:29:13+08:00","message": "Something happened"
}
{"level": "info","role": "my-service","host": "local-hostname","ip": "127.0.0.1:30305","user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36","referer": "http://127.0.0.1:8080/","req_id": "cu33ouao7p78o742c5tg","method": "GET","url": "/favicon.ico","status": 0,"size": 0,"duration": 0,"time": "2025-01-14T18:29:13+08:00"
}
钩子
Zerolog
提供了一种通过 Hook
接口挂接到日志记录过程的方法
定义如下:
type Hook interface {// Run runs the hook with the event.Run(e *zerolog.Event, level zerolog.Level, message string)
}
在具体类型上实现 Hook
接口时,可以使用 Logger.Hook()
方法将其应用于 Logger
,以便在每次记录日志时执行其 Run()
方法。
然后,您可以根据事件的日志级别或一些其他条件运行不同的操作。
示例
package mainimport ("fmt""github.com/rs/zerolog""os"
)// SeverityHook 是一个自定义的日志钩子,用于添加日志级别到日志条目中
type SeverityHook struct{}// Run 方法实现了 zerolog.Hook 接口,会在每次日志记录时调用
func (h SeverityHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {if level != zerolog.NoLevel {e.Str("severity", level.String()) // 添加 "severity" 字段,值为日志级别}fmt.Println("=========================================", msg, level)
}func main() {// 初始化 zerolog,输出到控制台log := zerolog.New(os.Stdout).With().Timestamp().Logger()// 将自定义钩子添加到日志实例中hooked := log.Hook(SeverityHook{})// 记录一条警告日志hooked.Warn().Msg("这是告警信息")// 输出: ========================================= 这是告警信息 warn// {"level":"warn","time":"2025-01-14T18:35:31+08:00","severity":"warn","message":"这是告警信息"}hooked.Debug().Msg("这是debug信息")// 输出: ========================================= 这是debug信息 debug// {"level":"debug","time":"2025-01-14T18:35:31+08:00","severity":"debug","message":"这是debug信息"}
}
日志采样
采样是一种用于有意删除重复日志条目的技术,以便只保留和处理其中的一部分。
当您的高流量应用程序生成大量记录时,这很有帮助,并且存储每一条记录将导致过高的存储和处理成本,这可能是不可取的。
采样通过防止每秒记录数百或数千次相同的日志来解决此问题,从而防止资源浪费。
基本采样 (BasicSampler)
BasicSampler
是最简单的采样方式,它会每隔 N
条日志记录一次。
以下是使用 Zerolog
对日志进行采样的最基本方法:
package mainimport ("github.com/rs/zerolog""os""time"
)func main() {// 初始化 zerolog,输出到控制台log := zerolog.New(os.Stdout).With().Timestamp().Logger()// 使用 BasicSampler,每 10 条日志记录一次sampled := log.Sample(&zerolog.BasicSampler{N: 10})// 模拟日志输出for i := 1; i <= 30; i++ {sampled.Info().Msgf("This is log message %d", i)time.Sleep(100 * time.Millisecond) // 模拟日志间隔}
}
输出结果
由于采样设置为每 10 条日志记录一次,因此只有第 1、11、21 条日志会被输出:
{"level":"info","time":"2025-01-14T18:40:29+08:00","message":"This is log message 1"}
{"level":"info","time":"2025-01-14T18:40:30+08:00","message":"This is log message 11"}
{"level":"info","time":"2025-01-14T18:40:31+08:00","message":"This is log message 21"}
适用场景
- 适用于需要简单控制日志量的场景。
- 例如,每 100 条日志记录一次,减少日志输出。
高级采样 (LevelSampler 和 BurstSampler)
LevelSampler
允许对不同日志级别设置不同的采样策略。
BurstSampler
是一种更灵活的采样方式,允许在指定时间窗口内记录一定数量的日志,超过限制后按比例采样。
package mainimport ("github.com/rs/zerolog""os""time"
)func main() {// 初始化 zerolog,输出到控制台log := zerolog.New(os.Stdout).With().Timestamp().Logger()// 设置高级采样策略sampled := log.Sample(zerolog.LevelSampler{DebugSampler: &zerolog.BurstSampler{Burst: 5, // 每秒最多记录 5 条 Debug 日志Period: 1 * time.Second, // 时间窗口为 1 秒NextSampler: &zerolog.BasicSampler{N: 100}, // 超过 5 条后,每 100 条记录一次},},)// 模拟日志输出for i := 1; i <= 200; i++ {sampled.Debug().Msgf("This is debug log message %d", i)time.Sleep(10 * time.Millisecond) // 模拟日志间隔}
}
输出结果
- 每秒的前 5 条 Debug 日志会被记录。
- 超过 5 条后,每 100 条 Debug 日志记录一次。
- 其他级别的日志不受影响(如果有)。
示例输出:
{"level":"debug","time":"2025-01-14T18:44:55+08:00","message":"This is debug log message 1"}
{"level":"debug","time":"2025-01-14T18:44:55+08:00","message":"This is debug log message 2"}
{"level":"debug","time":"2025-01-14T18:44:55+08:00","message":"This is debug log message 3"}
{"level":"debug","time":"2025-01-14T18:44:55+08:00","message":"This is debug log message 4"}
{"level":"debug","time":"2025-01-14T18:44:56+08:00","message":"This is debug log message 5"}
{"level":"debug","time":"2025-01-14T18:44:56+08:00","message":"This is debug log message 6"}
{"level":"debug","time":"2025-01-14T18:44:56+08:00","message":"This is debug log message 95"}
{"level":"debug","time":"2025-01-14T18:44:56+08:00","message":"This is debug log message 96"}
{"level":"debug","time":"2025-01-14T18:44:56+08:00","message":"This is debug log message 97"}
{"level":"debug","time":"2025-01-14T18:44:56+08:00","message":"This is debug log message 98"}
{"level":"debug","time":"2025-01-14T18:44:56+08:00","message":"This is debug log message 99"}
{"level":"debug","time":"2025-01-14T18:44:57+08:00","message":"This is debug log message 111"}
{"level":"debug","time":"2025-01-14T18:44:57+08:00","message":"This is debug log message 191"}
{"level":"debug","time":"2025-01-14T18:44:57+08:00","message":"This is debug log message 192"}
{"level":"debug","time":"2025-01-14T18:44:57+08:00","message":"This is debug log message 193"}
{"level":"debug","time":"2025-01-14T18:44:57+08:00","message":"This is debug log message 194"}
{"level":"debug","time":"2025-01-14T18:44:58+08:00","message":"This is debug log message 195"}
适用场景
- 适用于需要精细控制日志级别的场景。
- 例如,Debug 日志量很大,但希望每秒最多记录 5 条,超过后按比例采样。
自定义Logger
logger := zerolog.New(os.Stderr).With().Timestamp().Logger()logger = logger.Level(zerolog.InfoLevel)
logger.Info().Str("foo", "bar").Msg("hello world")// Output: {"level":"info","time":1494567715,"message":"hello world","foo":"bar"}
定制漂亮的日志记录
要记录人性化的彩色输出,请使用zerolog.ConsoleWriter
:
package mainimport ("github.com/rs/zerolog""github.com/rs/zerolog/log""os"
)func main() {log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})log.Info().Str("foo", "bar").Msg("Hello world")// Output: 3:04PM INF Hello World foo=bar
}
要自定义配置和格式:
package mainimport ("fmt""github.com/rs/zerolog""os""strings""time"
)func main() {// 配置控制台日志输出格式 设置时间格式output := zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339}// 自定义日志级别显示格式,如 "| INFO |"output.FormatLevel = func(i interface{}) string {return strings.ToUpper(fmt.Sprintf("| %-6s|", i))}// 自定义日志消息显示格式,如 "***message****"output.FormatMessage = func(i interface{}) string {return fmt.Sprintf("***%s****", i)}// 自定义字段名显示格式,如 "field:"output.FormatFieldName = func(i interface{}) string {return fmt.Sprintf("%s:", i)}// 自定义字段值显示格式,转为大写,如 "VALUE"output.FormatFieldValue = func(i interface{}) string {return strings.ToUpper(fmt.Sprintf("%s", i))}// 创建日志记录器,自动添加时间戳log := zerolog.New(output).With().Timestamp().Logger()log.Info().Str("foo", "bar").Msg("Hello World")// Output: 2025-01-14T17:18:53+08:00 | INFO | ***Hello World**** foo:BAR
}
在开发环境中,您可能会发现以更易于阅读的格式从应用程序输出日志条目会很有帮助,这样就可以轻松发现各种事件,而不会被不相关的符号和字段分散注意力。
Zerolog
提供了一个 ConsoleWriter
类型,用于解析原始 JSON 条目,并将其以彩色格式输出到控制台。
package mainimport ("github.com/rs/zerolog""os""runtime/debug""time"
)func main() {buildInfo, _ := debug.ReadBuildInfo()logger := zerolog.New(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}).Level(zerolog.TraceLevel).With().Timestamp().Caller().Int("pid", os.Getpid()).Str("go_version", buildInfo.GoVersion).Logger()logger.Trace().Msg("trace message")logger.Debug().Msg("debug message")logger.Info().Msg("info message")logger.Warn().Msg("warn message")logger.Error().Msg("error message")logger.WithLevel(zerolog.FatalLevel).Msg("fatal message")logger.WithLevel(zerolog.PanicLevel).Msg("panic message")
}
将日志写入到文件
package mainimport ("github.com/rs/zerolog""github.com/rs/zerolog/log""os"
)func main() {file, err := os.OpenFile("log.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)if err != nil {log.Fatal().Err(err).Msg("Failed to open log file")}defer file.Close()logger := zerolog.New(file).Level(zerolog.ErrorLevel).With().Timestamp().Logger()logger.Info().Msg("Hello, world!")
}
多日志输出
zerolog.MultiLevelWriter
可用于将日志消息发送到多个输出。
在此示例中,我们将日志消息发送到os.Stdout
内置 ConsoleWriter。
package mainimport ("github.com/rs/zerolog""github.com/rs/zerolog/log""os"
)func main() {file, err := os.OpenFile("log.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)if err != nil {log.Fatal().Err(err).Msg("Failed to open log file")}defer file.Close()// 创建一个日志记录器,将多个写入器组合在一起writer := zerolog.MultiLevelWriter(file, os.Stdout)logger := zerolog.New(writer).With().Timestamp().Logger()// 设置日志级别为InfoLevellogger = logger.Level(zerolog.InfoLevel)logger.Info().Msg("Hello, world!")
}
使用Lumberjack进行日志切割归档
这个日志程序中唯一缺少的就是日志切割归档功能。
Zerolog本身不支持切割归档日志文件
为了添加日志切割归档功能,我们将使用第三方库Lumberjack来实现。
安装
执行下面的命令安装Lumberjack
go get -u gopkg.in/natefinch/lumberjack.v2
zap logger中加入Lumberjack
infoLumberIO := &lumberjack.Logger{Filename: "./server/info.log",MaxSize: 10, // megabytesMaxBackups: 10,MaxAge: 28, // daysCompress: false, //Compress确定是否应该使用gzip压缩已旋转的日志文件。默认值是不执行压缩。
}
writer := zapcore.AddSync(infoLumberIO)
Lumberjack Logger采用以下属性作为输入:
- Filename: 日志文件的位置 如果文件目录不存在,会自动创建
- MaxSize:最大文件大小,日志文件达到多少的时候切割(以MB为单位)
- MaxBackups:保留旧文件的最大个数
- MaxAges:保留旧文件的最大天数
- Compress:是否压缩/归档旧文件
存档的状态
在zerolog中使用lumberjack
package mainimport ("github.com/rs/zerolog""gopkg.in/natefinch/lumberjack.v2""os"
)func main() {// 配置 lumberjack 实现日志切割logFile := &lumberjack.Logger{Filename: "app.log", // 日志文件路径MaxSize: 5, // 每个日志文件的最大大小(MB)MaxBackups: 5, // 保留旧日志文件的最大数量MaxAge: 30, // 保留旧日志文件的最大天数Compress: true, // 是否压缩旧日志文件}// 创建 zerolog 的 MultiLevelWriter,同时输出到文件和控制台multiWriter := zerolog.MultiLevelWriter(zerolog.ConsoleWriter{Out: os.Stdout}, // 输出到控制台logFile, // 输出到文件)// 创建 Loggerlogger := zerolog.New(multiWriter).With().Timestamp().Logger()// 记录日志for i := 0; i < 1000000; i++ {logger.Info().Int("index", i).Msg("This is a log message")}
}
错误日志与普通日志分开的logger
package mainimport ("os""time""github.com/rs/zerolog""gopkg.in/natefinch/lumberjack.v2"
)func main() {// 配置普通日志的切割normalLogFile := &lumberjack.Logger{Filename: "normal.log", // 普通日志文件路径MaxSize: 10, // 每个日志文件的最大大小(MB)MaxBackups: 3, // 保留旧日志文件的最大数量MaxAge: 30, // 保留旧日志文件的最大天数Compress: true, // 是否压缩旧日志文件}// 配置错误日志的切割errorLogFile := &lumberjack.Logger{Filename: "error.log", // 错误日志文件路径MaxSize: 10, // 每个日志文件的最大大小(MB)MaxBackups: 3, // 保留旧日志文件的最大数量MaxAge: 30, // 保留旧日志文件的最大天数Compress: true, // 是否压缩旧日志文件}// 创建控制台输出器consoleWriter := zerolog.ConsoleWriter{Out: os.Stdout}// 创建普通日志 Logger,输出到控制台和普通日志文件normalLogger := zerolog.New(zerolog.MultiLevelWriter(consoleWriter, // 输出到控制台normalLogFile, // 输出到普通日志文件)).With().Timestamp().Logger()// 创建错误日志 Logger,输出到控制台和错误日志文件errorLogger := zerolog.New(zerolog.MultiLevelWriter(consoleWriter, // 输出到控制台errorLogFile, // 输出到错误日志文件)).With().Timestamp().Logger()// 记录普通日志normalLogger.Info().Msg("This is a normal log message")// 记录错误日志errorLogger.Error().Msg("This is an error log message")
}