Go语言日志库zerolog

在开发大型项目时,将日志进行结构化以提高可读性、可查询性和速度是非常重要的。

为什么你选择不使用其他结构化日志库,如logrus或zap?

Zerolog 是一款高性能且极易使用的日志库,zerolog 只专注于记录 JSON 格式的日志,号称 0 内存分配。

除了其卓越的性能外,Zerolog 还提供了许多有用的工具。

Github 官方地址:https://github.com/rs/zerolog

官方文档:https://pkg.go.dev/github.com/rs/zerolog

1、安装

go get -u github.com/rs/zerolog/log

2、简单使用案例

package mainimport ("github.com/rs/zerolog""github.com/rs/zerolog/log"
)func main() {// UNIX Time is faster and smaller than most timestampszerolog.TimeFieldFormat = zerolog.TimeFormatUnix// {"level":"debug","time":1686128038,"message":"hello world"}log.Print("hello world")
}

常规使用与标准库 log 非常相似,只不过输出的是 JSON 格式的日志。

3、上下文Logging

zerolog 允许以键值对的形式将数据添加到日志消息中,添加到消息中的数据添加了关于日志事件的上下文,这对

于调试和问题追踪都是至关重要的。与 zap 一样, zerolog 也区分字段类型,不同的是 zerolog 采用链式调用的

方式:

package mainimport ("github.com/rs/zerolog""github.com/rs/zerolog/log"
)func main() {zerolog.TimeFieldFormat = zerolog.TimeFormatUnix// {"level":"debug","Scale":"833 cents","Interval":833.09,"time":1686130340,"message":"Fibonacci is everywhere"}log.Debug().Str("Scale", "833 cents").Float64("Interval", 833.09).Msg("Fibonacci is everywhere")// {"level":"debug","Name":"Tom","time":1686130340}log.Debug().Str("Name", "Tom").Send()
}
package mainimport ("github.com/rs/zerolog""github.com/rs/zerolog/log"
)func main() {zerolog.TimeFieldFormat = zerolog.TimeFormatUnixll := log.With().Caller().Str("Author", "Tom").Logger()ll.Debug().Str("Key1", "Value1").Send()ll.Debug().Str("Key2", "Value2").Send()ll.Debug().Str("Key3", "Value3").Msg("hello")ll.Debug().Str("Key4", "Value4").Msg("world")
}
# 输出
{"level":"debug","Author":"Tom","Key1":"Value1","time":1686130826,"caller":"....../zerolog/go-zerolog/003.go:11"}
{"level":"debug","Author":"Tom","Key2":"Value2","time":1686130826,"caller":"....../zerolog/go-zerolog/003.go:12"}
{"level":"debug","Author":"Tom","Key3":"Value3","time":1686130826,"caller":"....../zerolog/go-zerolog/003.go:13","message":"hello"}
{"level":"debug","Author":"Tom","Key4":"Value4","time":1686130826,"caller":"....../zerolog/go-zerolog/003.go:14","message":"world"}

与 zap 相同的是,都定义了强类型字段。

与 zap 不同的是,zerolog 采用链式调用。

4、日志等级

zerolog 提供了从 Trace 到 Panic 七个级别:

  • 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() {zerolog.TimeFieldFormat = zerolog.TimeFormatUnix// 没有级别log.Log().Msg("hello world")log.Trace().Msg("hello world")log.Debug().Msg("hello world")log.Info().Msg("hello world")log.Warn().Msg("hello world")log.Error().Msg("hello world")log.Fatal().Msg("hello world")log.Panic().Msg("hello world")
}
# 输出
{"time":1686131728,"message":"hello world"}
{"level":"trace","time":1686131728,"message":"hello world"}
{"level":"debug","time":1686131728,"message":"hello world"}
{"level":"info","time":1686131728,"message":"hello world"}
{"level":"warn","time":1686131728,"message":"hello world"}
{"level":"error","time":1686131728,"message":"hello world"}
{"level":"fatal","time":1686131728,"message":"hello world"}

可以调用 SetGlobalLevel() 设置全局 Logger 的日志级别。

设置日志等级:

package mainimport ("github.com/rs/zerolog""github.com/rs/zerolog/log"
)func main() {zerolog.TimeFieldFormat = zerolog.TimeFormatUnixzerolog.SetGlobalLevel(zerolog.ErrorLevel)// 没有级别log.Log().Msg("hello world")log.Trace().Msg("hello world")log.Debug().Msg("hello world")log.Info().Msg("hello world")log.Warn().Msg("hello world")log.Error().Msg("hello world")log.Fatal().Msg("hello world")log.Panic().Msg("hello world")
}
# 输出
{"time":1686132006,"message":"hello world"}
{"level":"error","time":1686132006,"message":"hello world"}
{"level":"fatal","time":1686132006,"message":"hello world"}

不带级别和消息的日志记录:

您可以选择使用log方法在没有特定级别的情况下进行日志记录,也可以通过在msg方法的msg字符串参数中设置

一个空字符串来编写不带消息的内容。

package mainimport ("github.com/rs/zerolog""github.com/rs/zerolog/log"
)func main() {zerolog.TimeFieldFormat = zerolog.TimeFormatUnix// {"foo":"bar","time":1686132216}log.Log().Str("foo", "bar").Msg("")
}

5、Error Logging

您可以使用Err方法记录错误:

package mainimport ("errors""github.com/rs/zerolog""github.com/rs/zerolog/log"
)func main() {zerolog.TimeFieldFormat = zerolog.TimeFormatUnixerr := errors.New("seems we have an error here")// {"level":"error","error":"seems we have an error here","time":1686132556}log.Error().Err(err).Msg("")
}

errors 的默认字段名称是 error,您可以通过设置zerolog.ErrorFieldName来更改此名称以满足您的需要。

package mainimport ("github.com/pkg/errors""github.com/rs/zerolog/pkgerrors""github.com/rs/zerolog""github.com/rs/zerolog/log"
)func main() {zerolog.TimeFieldFormat = zerolog.TimeFormatUnixzerolog.ErrorStackMarshaler = pkgerrors.MarshalStackerr := outer()log.Error().Stack().Err(err).Msg("")
}func inner() error {return errors.New("seems we have an error here")
}func middle() error {err := inner()if err != nil {return err}return nil
}func outer() error {err := middle()if err != nil {return err}return nil
}
# 输出
{"level":"error","stack":[{"func":"inner","line":"18","source":"009.go"},{"func":"middle","line":"22","source":"009.go"},{"func":"outer","line":"30","source":"009.go"},{"func":"main","line":"13","source":"009.go"},{"func":"main","line":"250","source":"proc.go"},{"func":"goexit","line":"1571","source":"asm_amd64.s"}],"error":"seems we have an error here","time":1686133719}

必须设置 zerolog.ErrorStackMarshaller,堆栈才能输出任何内容。

6、Fatal Logging

package mainimport ("errors""github.com/rs/zerolog""github.com/rs/zerolog/log"
)func main() {err := errors.New("A repo man spends his life getting into tense situations")service := "myservice"zerolog.TimeFieldFormat = zerolog.TimeFormatUnix// {"level":"fatal","error":"A repo man spends his life getting into tense situations","service":"myservice","time":1686185774,"message":"Cannot start myservice"}log.Fatal().Err(err).Str("service", service).Msgf("Cannot start %s", service)
}

注意:使用Msgf会生成一个分配,即使logger 被禁用。

7、全局Logging

全局 Logger:上面我们使用 log.Debug()、log.Info() 调用的是全局的 Logger 。全局的 Logger 使用比较简单,不

需要额外创建。

package mainimport "github.com/rs/zerolog/log"func main(){log.Logger = log.With().Str("foo", "bar").Logger()// {"level":"info","foo":"bar","time":"2023-06-08T10:00:40+08:00","message":"Hello World!"}log.Info().Msg("Hello World!")
}

8、创建Logging实例以管理不同的输出

全局的 Logger ,这种方式有一个明显的缺点:如果在某个地方修改了设置,将影响全局的日志记录。为了消除这

种影响,我们需要创建新的 Logger。

package mainimport ("github.com/rs/zerolog""os"
)func main()  {logger := zerolog.New(os.Stderr).With().Timestamp().Logger()// {"level":"info","foo":"bar","time":"2023-06-08T09:04:46+08:00","message":"hello world"}logger.Info().Str("foo", "bar").Msg("hello world")
}

调用 zerlog.New() 传入一个 io.Writer 作为日志写入器即可。

9、子Logging

基于当前的 Logger 可以创建一个子 Logger,子 Logger 可以在父 Logger 上附加一些额外的字段。调用

logger.With() 创建一个上下文,然后为它添加字段,最后调用 Logger() 返回一个新的 Logger:

package mainimport ("github.com/rs/zerolog""os"
)func main()  {logger := zerolog.New(os.Stderr)sublogger := logger.With().Str("component", "foo").Logger()// {"level":"info","component":"foo","time":"2023-06-08T09:11:14+08:00","message":" hello world"}sublogger.Info().Msg("hello world")
}

sublogger 会额外输出 “component”:“foo” 这个字段。

10、美化Logging

zerolog 提供了多种选项定制输入日志的行为。

zerolog 提供了一个 ConsoleWriter 可输出便于我们阅读的,带颜色的日志。

调用 zerolog.Output() 来启用 ConsoleWriter。

package mainimport ("github.com/rs/zerolog""github.com/rs/zerolog/log""os"
)func main(){log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})// 9:17AM INF Hello world foo=barlog.Info().Str("foo", "bar").Msg("Hello world")
}

我们还能进一步对 ConsoleWriter 进行配置,定制输出的级别、信息、字段名、字段值的格式:

package mainimport ("fmt""github.com/rs/zerolog""os""strings""time"
)func main() {output := zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339}output.FormatLevel = func(i interface{}) string {return strings.ToUpper(fmt.Sprintf("| %-6s|", i))}output.FormatMessage = func(i interface{}) string {return fmt.Sprintf("***%s****", i)}output.FormatFieldName = func(i interface{}) string {return fmt.Sprintf("%s:", i)}output.FormatFieldValue = func(i interface{}) string {return strings.ToUpper(fmt.Sprintf("%s", i))}log := zerolog.New(output).With().Timestamp().Logger()// 2023-06-08T09:20:22+08:00 | INFO  | ***Hello World**** foo:BARlog.Info().Str("foo", "bar").Msg("Hello World")
}

ConsoleWriter的性能不够理想,建议只在开发环境中使用!

11、嵌套

记录的字段可以任意嵌套,这通过 Dict() 来实现。

package mainimport ("github.com/rs/zerolog""github.com/rs/zerolog/log"
)func main() {// {"level":"info","foo":"bar","dict":{"bar":"baz","n":1},"time":"2023-06-08T09:47:55+08:00","message":"hello world"}log.Info().Str("foo", "bar").Dict("dict", zerolog.Dict().Str("bar", "baz").Int("n", 1),).Msg("hello world")
}

12、设置自动添加的字段名

输出的日志中级别默认的字段名为 level,信息默认为 message,时间默认为 time。可以通过 zerolog 中

LevelFieldName/MessageFieldName/TimestampFieldName 来设置:

package mainimport ("github.com/rs/zerolog""os"
)func main() {zerolog.TimestampFieldName = "t"zerolog.LevelFieldName = "l"zerolog.MessageFieldName = "m"logger := zerolog.New(os.Stderr).With().Timestamp().Logger()// {"l":"info","t":"2023-06-08T09:52:34+08:00","m":"hello world"}logger.Info().Msg("hello world")
}

注意,这个设置是全局的。

13、将文件和行号添加到日志中

有时我们需要输出文件名和行号,以便能很快定位代码位置,方便找出问题。这可以通过在创建子 Logger 时带

入 Caller()选项完成:

package mainimport "github.com/rs/zerolog/log"func main(){log.Logger = log.With().Caller().Logger()// {"level":"info","time":"2023-06-08T10:04:40+08:00","caller":"....../go-zerolog/017.go:7","message":"hello world"}log.Info().Msg("hello world")
}

自己定义:

package mainimport ("github.com/rs/zerolog""github.com/rs/zerolog/log""strconv"
)func main(){zerolog.CallerMarshalFunc = func(pc uintptr, file string, line int) string {short := filefor i := len(file) - 1; i > 0; i-- {if file[i] == '/' {short = file[i+1:]break}}file = shortreturn file + ":" + strconv.Itoa(line)}log.Logger = log.With().Caller().Logger()// {"level":"info","time":"2023-06-08T10:06:09+08:00","caller":"018.go:22","message":"hello world"}log.Info().Msg("hello world")
}

14、线程安全、无锁、无阻塞写入器

如果您的编写器可能很慢或不是线程安全的,并且您需要日志生成器永远不会被慢的编写器拖慢,那么您可以使用

diode.Writer,如下所示:

package mainimport ("fmt""github.com/rs/zerolog""github.com/rs/zerolog/diode""os""time"
)func main(){wr := diode.NewWriter(os.Stdout, 1000, 10*time.Millisecond, func(missed int) {fmt.Printf("Logger Dropped %d messages", missed)})log := zerolog.New(wr)// {"level":"debug","message":"test"}log.Print("test")
}

15、日志采样

有时候日志太多了反而对我们排查问题造成干扰,zerolog 支持日志采样的功能,可以每隔多少条日志输出一

次,其他日志丢弃:

package mainimport ("github.com/rs/zerolog""github.com/rs/zerolog/log"
)func main() {sampled := log.Sample(&zerolog.BasicSampler{N: 10})for i := 0; i < 20; i++ {sampled.Info().Msg("will be logged every 10 message")}
}
# 输出
{"level":"info","time":"2023-06-08T10:25:37+08:00","message":"will be logged every 10 message"}
{"level":"info","time":"2023-06-08T10:25:37+08:00","message":"will be logged every 10 message"}

更高级的采样:

package mainimport ("github.com/rs/zerolog""github.com/rs/zerolog/log""time"
)func main(){// 只采样Debug日志,在1s内最多输出5条日志,超过5条时,每隔100条输出一条sampled := log.Sample(zerolog.LevelSampler{DebugSampler: &zerolog.BurstSampler{Burst: 5,Period: 1*time.Second,NextSampler: &zerolog.BasicSampler{N: 100},},})// {"level":"debug","time":"2023-06-08T10:55:59+08:00","message":"hello world"}// {"level":"debug","time":"2023-06-08T10:55:59+08:00","message":"hello world"}// {"level":"debug","time":"2023-06-08T10:55:59+08:00","message":"hello world"}// {"level":"debug","time":"2023-06-08T10:55:59+08:00","message":"hello world"}// {"level":"debug","time":"2023-06-08T10:55:59+08:00","message":"hello world"}// {"level":"debug","time":"2023-06-08T10:55:59+08:00","message":"hello world"}for i := 0; i < 50; i++ {sampled.Debug().Msg("hello world")}
}

16、钩子

zerolog 支持钩子,我们可以针对不同的日志级别添加一些额外的字段或进行其他的操作:

package mainimport ("github.com/rs/zerolog""github.com/rs/zerolog/log"
)type SeverityHook struct{}func (h SeverityHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {if level != zerolog.NoLevel {e.Str("severity", level.String())}
}func main(){hooked := log.Hook(SeverityHook{})// {"level":"warn","time":"2023-06-08T10:59:31+08:00","severity":"warn"}hooked.Warn().Msg("")
}

17、按Context传递子Logging

package mainimport ("context""github.com/rs/zerolog/log"
)func main(){ctx := log.With().Str("component", "module").Logger().WithContext(context.Background())// {"level":"info","component":"module","time":"2023-06-08T11:04:28+08:00","message":"hello world"}log.Ctx(ctx).Info().Msg("hello world")
}

18、设置为标准Logging输出

package mainimport ("github.com/rs/zerolog"stdlog "log""os"
)func main(){log := zerolog.New(os.Stdout).With().Str("foo", "bar").Logger()stdlog.SetFlags(0)stdlog.SetOutput(log)// {"foo":"bar","message":"hello world"}stdlog.Print("hello world")
}

19、与net/http的集成

github.com/rs/zerolog/hlog 包提供了一些帮助程序来将 zerolog 与 http.Handler 集成。

package mainimport ("github.com/justinas/alice""github.com/rs/zerolog""github.com/rs/zerolog/hlog""net/http""os""time"
)func main() {log := zerolog.New(os.Stdout).With().Timestamp().Str("role", "my-service").Str("host", "127.0.0.1").Logger()c := alice.New()// Install the logger handler with default output on the consolec = c.Append(hlog.NewHandler(log))// Install some provided extra handler to set some request's context fields.// Thanks to that handler, all our logs will come with some prepopulated fields.c = c.Append(hlog.AccessHandler(func(r *http.Request, status, size int, duration time.Duration) {hlog.FromRequest(r).Info().Str("method", r.Method).Stringer("url", r.URL).Int("status", status).Int("size", size).Dur("duration", duration).Msg("")}))c = 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"))// Here is your final handlerh := c.Then(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {// Get the logger from the request's context. You can safely assume it// will be always there: if the handler is removed, hlog.FromRequest// will return a no-op logger.hlog.FromRequest(r).Info().Str("user", "current user").Str("status", "ok").Msg("Something happened")}))http.Handle("/", h)if err := http.ListenAndServe(":8080", nil); err != nil {log.Fatal().Err(err).Msg("Startup failed")}
}
# 输出
{"level":"info","role":"my-service","host":"127.0.0.1","ip":"127.0.0.1:50189","user_agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like
Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.37","req_id":"ci0kg1n2tm03o212g3kg","user":"current user","status":"ok","time":"2023-06-08T11:16:22+08:00","messa
ge":"Something happened"}
{"level":"info","role":"my-service","host":"127.0.0.1","ip":"127.0.0.1:50189","user_agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like
Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.37","req_id":"ci0kg1n2tm03o212g3kg","method":"GET","url":"/","status":0,"size":0,"duration":16.0218,"time":"2023-
06-08T11:16:22+08:00"}
{"level":"info","role":"my-service","host":"127.0.0.1","ip":"127.0.0.1:50189","user_agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like
Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.37","referer":"http://127.0.0.1:8080/","req_id":"ci0kg1n2tm03o212g3l0","user":"current user","status":"ok","time"
:"2023-06-08T11:16:22+08:00","message":"Something happened"}
{"level":"info","role":"my-service","host":"127.0.0.1","ip":"127.0.0.1:50189","user_agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like
Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.37","referer":"http://127.0.0.1:8080/","req_id":"ci0kg1n2tm03o212g3l0","method":"GET","url":"/favicon.ico","statu
s":0,"size":0,"duration":0.997,"time":"2023-06-08T11:16:22+08:00"}

20、多Log输出

zerolog.MultiLevelWriter 可用于将日志消息发送到多个输出, 在本例中,我们将日志消息发送到os.Stdout和内

置的ConsoleWriter。

package mainimport ("github.com/rs/zerolog""os"
)func main() {consoleWriter := zerolog.ConsoleWriter{Out: os.Stdout}multi := zerolog.MultiLevelWriter(consoleWriter, os.Stdout)logger := zerolog.New(multi).With().Timestamp().Logger()// 11:26AM INF Hello World!// {"level":"info","time":"2023-06-08T11:26:21+08:00","message":"Hello World!"}logger.Info().Msg("Hello World!")
}
package mainimport ("fmt""github.com/rs/zerolog""os""strings""time"
)var Logger zerolog.Loggerfunc init() {timeFormat := "2006-01-02 15:04:05"zerolog.TimeFieldFormat = timeFormat// 创建log目录logDir := "./run_log/"err := os.MkdirAll(logDir, os.ModePerm)if err != nil {fmt.Println("Mkdir failed, err:", err)return}// 把日志同时往控制台和日志文件里输出,日志文件用日期每日分拆fileName := logDir + time.Now().Format("2006-01-02") + ".log"logFile, _ := os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)consoleWriter := zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: timeFormat}consoleWriter.FormatLevel = func(i interface{}) string {return strings.ToUpper(fmt.Sprintf("| %-6s|", i))}consoleWriter.FormatMessage = func(i interface{}) string {return fmt.Sprintf("%s", i)}consoleWriter.FormatFieldName = func(i interface{}) string {return fmt.Sprintf("%s:", i)}consoleWriter.FormatFieldValue = func(i interface{}) string {return fmt.Sprintf("%s;", i)}multi := zerolog.MultiLevelWriter(consoleWriter, logFile)Logger = zerolog.New(multi).With().Timestamp().Logger()
}func main(){// 2023-06-08 14:33:44 | INFO  | 开始登录... account:sdhhk; website:xx;Logger.Info().Str("website", "xx").Str("account", "sdhhk").Msg("开始登录...")
}

21、全局设置

某些设置可以更改并将应用于所有loggers:

  • log.Logger

  • zerolog.SetGlobalLevel

  • zerolog.DisableSampling

  • zerolog.TimestampFieldName

  • zerolog.LevelFieldName

  • zerolog.MessageFieldName

  • zerolog.ErrorFieldName

  • zerolog.TimeFieldFormat:

    zerolog.TimeFormatUnix,zerolog.TimeFormatUnixMs,zerolog.TimeFormatUnixMicro

  • zerolog.DurationFieldUnit

  • zerolog.DurationFieldInteger

  • zerolog.ErrorHandler

22、标准类型

  • Str

  • Bool

  • Int, Int8, Int16, Int32, Int64

  • Uint, Uint8, Uint16, Uint32, Uint64

  • Float32, Float64

23、高级字段

  • Err

  • Func

  • Timestamp

  • Time

  • Dur

  • Dict

  • RawJSON

  • Hex

  • Interface

大多数字段也可以使用切片格式:Strs for []string, Errs for []error。

24、注意的问题

1、zerolog 不会对重复的字段删除

package mainimport ("github.com/rs/zerolog""os"
)func main(){logger := zerolog.New(os.Stderr).With().Timestamp().Logger()// {"level":"info","time":"2023-06-08T14:08:35+08:00","time":"2023-06-08T14:08:35+08:00","message":"dup"}logger.Info().Timestamp().Msg("dup")
}

2、链式调用必须调用 Msg、Msgf、Send才能输出日志,Send 相当于调用 Msg(“”)。

3、一旦调用 Msg,Event 将会被处理(放回池中或丢掉),不允许二次调用。

Go语言日志库zerolog相关推荐

  1. Linux-C 简单的C语言日志库

    Linux-C 简单的C语言日志库 一.简述         记--C语言实现的简单的日志库,可循环覆盖滚动记录日志文件,达到限制就另记一个日志文件,可控制日志文件个数,可控制日志文件大小. 打包下载 ...

  2. 【C/C++开源库】单片机/嵌入式中的C语言日志库

    日志系统在系统开发和调整过程中的重要性,大家应该都清楚,特别是项目出问题之后,却没有日志可以帮忙定位问题,就非常令人痛苦. 因为我们不可能一直通过调试器去单步调试程序,所以设备的运行日志显得尤为重要. ...

  3. 【CC++开源库】单片机嵌入式中的C语言日志库

    日志系统在系统开发和调整过程中的重要性,大家应该都清楚,特别是项目出问题之后,却没有日志可以帮忙定位问题,就非常令人痛苦. 因为我们不可能一直通过调试器去单步调试程序,所以设备的运行日志显得尤为重要. ...

  4. golang日志库zerolog使用记录

    目录 效果 安装 配置 使用 效果 安装 github官方地址:https://github.com/rs/zerolog go get -u github.com/rs/zerolog/log 配置 ...

  5. go 日志库 zap

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.zap是什么? 二.使用步骤 1.基本使用 2.写入文件 前言 zap日志 Zap提供了两种类型的日志记录器-Su ...

  6. 在Go语言项目中使用Zap日志库

    在Go语言项目中使用Zap日志库 Go语言原生的日志库的使用,然后详细介绍了非常流行的Uber开源的zap日志库,同时介绍了如何搭配Lumberjack实现日志的切割和归档. 一.在Go语言项目中使用 ...

  7. go语言 gin框架中集成zap日志库

    在go语言gin框架中,日志是默认输出到终端的,但是我们在实际工作中,一般来说是需要记录服务器日志的.而最常用的日志库就是zap日志库,我们需要将gin在终端输出的内容通过zap日志库记录到文件中,首 ...

  8. 介绍一个使用 Go 语言开发的高性能可配置可扩展的日志库 logit

    这是一个使用 Go 语言开发的高性能可配置可扩展的日志库,名字叫 logit. logit 是一个高性能的日志库,从测试结果来看,比主流日志库 zap.logrus 这些要快不少. logit 支持配 ...

  9. Go 语言中的 logger 和 zap 日志库

    目录 Go 语言中的 logger 和 zap 日志库 Go Logger Zap Logger Logger Sugared Logger 定制 Logger 记录到文件中 Zap logger 中 ...

最新文章

  1. Fragment Injection漏洞杂谈
  2. 详解MOS管、IGBT管,不看就亏大了!
  3. 使用maven构建的Spring boot项目在开始搭建的时候出的一些错误
  4. linux 大数字 进制转换,Linux下用bc快速进行数字进制转换
  5. Sybase数据库优化手册
  6. 白银TD盈亏计算实例介绍
  7. 86-90linux下配置javaEE环境
  8. 网络技术沙龙:主题:数据库优化、CDN、集群负载均衡(1.9日技术聚会召集)
  9. JAVA多线程--线程的同步安全
  10. JAVA语言基础-反射、特性
  11. 上周热点回顾(8.26-9.1)
  12. Matlab——噪声的检测和处理实验
  13. JavaScript数据结构与算法基础学习笔记03----链表与双向链表
  14. 华为太极magisk安装教程_华为(HUAWEI)ROM安装包合集
  15. 音频怎么转换成mp3格式
  16. 程序员转公务员之Hello World
  17. ipad未能与itunes连接到服务器,ipad无法连接itunes store怎么办
  18. 数据中心温度云图三维可视化
  19. c++动态规划法求解斐波那契数列
  20. SpringBoot 实现大文件视频转码(转码基于FFMPEG实现)

热门文章

  1. pycurl下有一个retriever-multi.py勉强可以用用
  2. 使用soapui测试接口
  3. Android11.0(R) 预置 wifi 信息自动连接
  4. 国外程序员推荐:每个程序员都应读的书(作为一个码奴,这个也留着)(转)
  5. 整合dtk + hpssacli2.4
  6. 天津一汽丰田召回18万余辆卡罗拉、花冠EX汽车
  7. 信息与通信工程学科面试——线性代数
  8. SRS源码分析-rtmp转rtc流程
  9. 一开机就提示脱机工作_电脑一开机就会跳出“脱机工作”怎么解决
  10. 表白代码爱心树html