高性能、零内存分配的Go日志库--Zerolog

news/2025/1/14 18:58:37/文章来源:https://www.cnblogs.com/guangdelw/p/18671412

简介

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") // 如果启动失败,记录错误日志}
}
  1. 初始化日志:使用 zerolog 初始化日志,并添加时间戳和服务信息。
  2. 中间件链:使用 alice 创建中间件链,逐步添加日志处理器。
  3. 访问日志:记录每个请求的关键信息,如方法、URL、状态码等。
  4. 额外日志:记录客户端 IP、User-Agent、Referer 和请求 ID,丰富日志内容。
  5. 请求处理:在请求处理函数中记录自定义日志信息。
  6. 启动服务:注册路由并启动 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) // 模拟日志间隔}
}

输出结果

  1. 每秒的前 5 条 Debug 日志会被记录。
  2. 超过 5 条后,每 100 条 Debug 日志记录一次。
  3. 其他级别的日志不受影响(如果有)。

示例输出:

{"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")
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/869205.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jar Analyzer:JAR包分析工具

工具介绍 一个JAR包分析工具,批量分析,SCA漏洞分析,方法调用关系搜索,字符串搜索,Spring组件分析,信息泄露检查,CFG程序分析,JVM栈帧分析,进阶表达式搜索,字节码指令级的动态调试分析,反编译JAR包一键导出,一键提取序列化数据恶意代码,一键分析BCEL字节码。 Jar A…

第二十次作业

1、对bluecms进行代码审计,分析复现文件上传、ssti模板注入、文件删除等漏洞 文件上传:ssti模板注入: bluecms采⽤了smarty模板引擎可以在模板中插⼊恶意的代码,从⽽执⾏任意命令。此处可知smarty使⽤的界定符为{#和#},参考smarty官⽅⽂档可知,可以使⽤{#php#}code{#/php…

【JAVA开发】企业Java开发:七款提升开发者工作效率的Java分析工具

一、引言 编写正确的代码至关重要,但同样重要的是理解代码在实际环境中的表现。Java 分析工具在这方面提供了极大的便利,它们可以帮助您深入了解程序的内部运作。虽然进行性能分析可能需要额外的时间投入,但它最终能够为您节省大量调试时间。 Java 分析器提供了关于 CPU 使用…

JS-32 数组方法_shift()/unshift()

shift方法用于删除数组的第一个元素,并返回该元素。注意,该方法会改变原数组 var arr=[字符串,zifuchuan,前端]; arr.shift()//字符串 arr//[zifuchuan,前端] shift方法可以遍历并清空一个数组 var list=[1,2,3,4,5,6]; var item;while(item=list.shift()){ console.log(ite…

【勒索病☠】盘点全球主流Linux平台的勒索病毒

前言 美国网络信息安全公司CrowdStrike在2021年的攻击数据报告中,总结与2020年度相比,2021年度针对Linux系统的恶意软件增加了35%,其实最近几年针对Linux平台下的恶意软件数据一直在不断的增加,这些恶意软件主要包含僵尸网络、挖矿病毒、勒索病毒、远控木马等,随着云计算平…

再谈Redux

2025年再聊前端状态管理似乎是一件不必要的事,毕竟相关文章已堆积得如山如海。但在这些文章或视频内容中,我并没有找到自己喜欢的方案,准确的说是使用方式。所以这篇文章不做技术分析,主要聊聊个人对状态管理的理解,并分享独特的redux使用的方式。 状态管理 先分享一个有趣…

中考英语优秀范文-热点话题-传统文化-005 Our Schools Food Festival 我们学校的美食节

1 写作要求 中国饮食文化博大精深。假如你是李明,上周你校开展了以“品中华美食,传承中华文化”为主题的校园美食节活动。请你根据以下图示提示,用英语给你的英国笔友Mike写一封电子邮件,分享本次活动的过程和感受。 要求: 1 电子邮件的内容必须包括图示中的所有要点,可适…

嵌入Embedding-计算理解语言的钥匙

定义: 将人类语言与数字建立联系的强大方法 嵌入技术的演变: Wod2VecCBOW(Continuous Bag of Words):根据上下文词汇预测目标词汇(情感分析、文本分类、词相似性) Skip-Gram:根据目标单词预测周围单词 在训练Word2Vec模型时,包含词典和词向量模型的训练 词典的构建是训…

ExcelConvert【Excel转换为XML JSON HTML CSV TXT】

ExcelConverter是用VB6开发的应用软件。 界面如下 第一部分:转换为XML 首先在Excel选择一部分数据。 软件里面勾选“首列作为元素名称”,单击“转换” 勾选与不勾选,得到如下XML数据,注意对比。<root><金龙宇 性别="男" 年龄="29" 民族=&qu…

Kyutai开源端侧模型Helium -1 preview;FoloToy内测「超级智能体」,支持联网查询和语音调整音量语速

开发者朋友们大家好:这里是 「RTE 开发者日报」 ,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE(Real-Time Engagement) 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文章 」、「有看点的 会议 」,但内容仅代表编辑…

多模态大模型InterVL2.5使用记录

本文记录在本地安装和测试InterVL2.5(26B版本) 论文:https://arxiv.org/abs/2412.05271 Huggingface模型权重下载页:https://huggingface.co/collections/OpenGVLab/internvl25-673e1019b66e2218f68d7c1c Github: https://github.com/OpenGVLab/InternVL 本地硬件:RTX3090 1…

JR九州列车播放收听

JR Kyushu 是一款用VB.NET开发的软件。启动软件时大约需要等待10分钟。 以树形结构显示各个站台,鼠标点击每个节点,可以听到播放声音。 效果图如下