零分配 JSON 日志器
The zerolog package provides a fast and simple logger dedicated to JSON output.
Zerolog's API is designed to provide both a great developer experience and stunning performance. Its unique chaining API allows zerolog to write JSON (or CBOR) log events by avoiding allocations and reflection.
Uber's zap library pioneered this approach. Zerolog is taking this concept to the next level with a simpler to use API and even better performance.
To keep the code base and the API simple, zerolog focuses on efficient structured logging only. Pretty logging on the console is made possible using the provided (but inefficient) zerolog.ConsoleWriter.
Find out who uses zerolog and add your company / project to the list.
context.Context integrationnet/httplog/slog integrationgo get -u github.com/rs/zerolog/logFor simple logging, import the global logger package github.com/rs/zerolog/log
package main
import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
func main() {
// UNIX Time is faster and smaller than most timestamps
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
log.Print("hello world")
}
// Output: {"time":1516134303,"level":"debug","message":"hello world"}Note: By default log writes to
os.StderrNote: The default log level forlog.Printis trace
zerolog allows data to be added to log messages in the form of key:value pairs. The data added to the message adds "context" about the log event that can be critical for debugging as well as myriad other purposes. An example of this is below:
package main
import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
log.Debug().
Str("Scale", "833 cents").
Float64("Interval", 833.09).
Msg("Fibonacci is everywhere")
log.Debug().
Str("Name", "Tom").
Send()
}
// Output: {"level":"debug","Scale":"833 cents","Interval":833.09,"time":1562212768,"message":"Fibonacci is everywhere"}
// Output: {"level":"debug","Name":"Tom","time":1562212768}You'll note in the above example that when adding contextual fields, the fields are strongly typed. You can find the full list of supported fields here
package main
import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
log.Info().Msg("hello world")
}
// Output: {"time":1516134303,"level":"info","message":"hello world"}It is very important to note that when using the zerolog chaining API, as shown above (
log.Info().Msg("hello world"), the chain must have either theMsgorMsgfmethod call. If you forget to add either of these, the log will not occur and there is no compile time error to alert you of this.
zerolog allows for logging at the following levels (from highest to lowest):
zerolog.PanicLevel, 5)zerolog.FatalLevel, 4)zerolog.ErrorLevel, 3)zerolog.WarnLevel, 2)zerolog.InfoLevel, 1)zerolog.DebugLevel, 0)zerolog.TraceLevel, -1)You can set the Global logging level to any of these options using the SetGlobalLevel function in the zerolog package, passing in one of the given constants above, e.g. zerolog.InfoLevel would be the "info" level. Whichever level is chosen, all logs with a level greater than or equal to that level will be written. To turn off logging entirely, pass the zerolog.Disabled constant.
Default level. If you never call
SetGlobalLevel, the global logger writes toos.Stderrat thetracelevel (the lowest level), so every event -trace,debug,info,warn,error,fatal,panic- is written to stderr by default. In particular, a plainlog.Info(...)call will appear on stderr out of the box. Callingzerolog.SetGlobalLevel(zerolog.InfoLevel)raises the minimum level sotraceanddebugmessages are suppressed.
This example uses command-line flags to demonstrate various outputs depending on the chosen log level.
…Info Output (no flag)
$ ./logLevelExample
{"time":1516387492,"level":"info","message":"This message appears when log level set to Debug or Info"}Debug Output (debug flag set)
$ ./logLevelExample -debug
{"time":1516387573,"level":"debug","message":"This message appears only when log level set to Debug"}
{"time":1516387573,"level":"info","message":"This message appears when log level set to Debug or Info"}
{"time":1516387573,"level":"debug","foo":"bar","message":"some debug message"}You may choose to log without a specific level by using the Log method. You may also write without a message by setting an empty string in the msg string parameter of the Msg method. Both are demonstrated in the example below.
package main
import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
log.Log().
Str("foo", "bar").
Msg("")
}
// Output: {"time":1494567715,"foo":"bar"}You can log errors using the Err method
package main
import (
"errors"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
err := errors.New("seems we have an error here")
log.Error().Err(err).Msg("")
}
// Output: {"level":"error","error":"seems we have an error here","time":1609085256}The default field name for errors is
error, you can change this by settingzerolog.ErrorFieldNameto meet your needs.
Using github.com/pkg/errors, you can add a formatted stacktrace to your errors.
…zerolog.ErrorStackMarshaler must be set in order for the stack to output anything.
package main
import (
"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
log.Fatal().
Err(err).
Str("service", service).
Msgf("Cannot start %s", service)
}
// Output: {"time":1516133263,"level":"fatal","error":"A repo man spends his life getting into tense situations","service":"myservice","message":"Cannot start myservice"}
// exit status 1NOTE: Using
Msgfgenerates one allocation even when the logger is disabled.
logger := zerolog.New(os.Stderr).With().Timestamp().Logger()
logger.Info().Str("foo", "bar").Msg("hello world")
// Output: {"level":"info","time":1494567715,"message":"hello world","foo":"bar"}sublogger := log.With().
Str("component", "foo").
Logger()
sublogger.Info().Msg("hello world")
// Output: {"level":"info","time":1494567715,"message":"hello world","component":"foo"}To log a human-friendly, colorized output, use zerolog.ConsoleWriter:
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
log.Info().Str("foo", "bar").Msg("Hello world")
// Output: 3:04PM INF Hello World foo=barTo customize the configuration and formatting:
…To use custom advanced formatting:
…log.Info().
Str("foo", "bar").
Dict("dict", zerolog.Dict().
Str("bar", "baz").
Int("n", 1),
).Msg("hello world")
// Output: {"level":"info","time":1494567715,"foo":"bar","dict":{"bar":"baz","n":1},"message":"hello world"}zerolog.TimestampFieldName = "t"
zerolog.LevelFieldName = "l"
zerolog.MessageFieldName = "m"
log.Info().Msg("hello world")
// Output: {"l":"info","t":1494567715,"m":"hello world"}log.Logger = log.With().Str("foo", "bar").Logger()Equivalent of Llongfile:
log.Logger = log.With().Caller().Logger()
log.Info().Msg("hello world")
// Output: {"level": "info", "message": "hello world", "caller": "/go/src/your_project/some_file:21"}Equivalent of Lshortfile:
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": "some_file:21"}If your writer might be slow or not thread-safe and you need your log producers to never get slowed down by a slow writer, you can use a diode.Writer as follows:
wr := diode.NewWriter(os.Stdout, 1000, 10*time.Millisecond, func(missed int) {
fmt.Printf("Logger Dropped %d messages", missed)
})
log := zerolog.New(wr)
log.Print("test")You will need to install code.cloudfoundry.org/go-diodes to use this feature.
sampled := log.Sample(&zerolog.BasicSampler{N: 10})
sampled.Info().Msg("will be logged every 10 messages")
// Output: {"time":1494567715,"level":"info","message":"will be logged every 10 messages"}More advanced sampling:
// Will let 5 debug messages per period of 1 second.
// Over 5 debug message, 1 every 100 debug messages are logged.
// Other levels are not sampled.
sampled := log.Sample(zerolog.LevelSampler{
DebugSampler: &zerolog.BurstSampler{
Burst: 5,
Period: 1*time.Second,
NextSampler: &zerolog.BasicSampler{N: 100},
},
})
sampled.Debug().Msg("hello world")
// Output: {"time":1494567715,"level":"debug","message":"hello world"}type SeverityHook struct{}
func (h SeverityHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {
if level != zerolog.NoLevel {
e.Str("severity", level.String())
}
}
hooked := log.Hook(SeverityHook{})
hooked.Warn().Msg("")
// Output: {"level":"warn","severity":"warn"}ctx := log.With().Str("component", "module").Logger().WithContext(ctx)
log.Ctx(ctx).Info().Msg("hello world")
// Output: {"component":"module","level":"info","message":"hello world"}log := zerolog.New(os.Stdout).With().
Str("foo", "bar").
Logger()
stdlog.SetFlags(0)
stdlog.SetOutput(log)
stdlog.Print("hello world")
// Output: {"foo":"bar","message":"hello world"}Go contexts are commonly passed throughout Go code, and this can help you pass your Logger into places it might otherwise be h
ConsoleWriter 写入实现在 CBOR/-binary_log 构建中表现不佳
在使用 ConsoleWriter 时如何设置时区?
log.Ctx 和事件上下文的问题
栈: 移除 `GitHub.com/pkg/errors` 作为依赖项
SlogHandler 违反了 slog.Handler 协议的多个部分
代码健康审计 — 136 个发现 (94 个文件)
是否考虑让 Stringers 函数具有通用性?
[问题] 如何在钩子中访问 `with` 字段
写完后加钩
问题:我是否总是应该使用 (*Event).Str、(*Event).Uint 等返回值?