Zerolog
Zero Allocation JSON Logger
Install / Use
/learn @rs/ZerologREADME
Zero Allocation JSON Logger
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.

Who uses zerolog
Find out who uses zerolog and add your company / project to the list.
Features
- Blazing fast
- Low to zero allocation
- Leveled logging
- Sampling
- Hooks
- Contextual fields
context.Contextintegration- Integration with
net/http - JSON and CBOR encoding formats
- Pretty logging for development
- Error Logging (with optional Stacktrace)
log/slogintegration
Installation
go get -u github.com/rs/zerolog/log
Getting Started
Simple Logging Example
For 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
Contextual Logging
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
Leveled Logging
Simple Leveled Logging Example
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):
- 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)
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.
Setting Global Log Level
This example uses command-line flags to demonstrate various outputs depending on the chosen log level.
package main
import (
"flag"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
debug := flag.Bool("debug", false, "sets log level to debug")
flag.Parse()
// Default level for this example is info, unless debug flag is present
zerolog.SetGlobalLevel(zerolog.InfoLevel)
if *debug {
zerolog.SetGlobalLevel(zerolog.DebugLevel)
}
log.Debug().Msg("This message appears only when log level set to Debug")
log.Info().Msg("This message appears when log level set to Debug or Info")
if e := log.Debug(); e.Enabled() {
// Compute log output only if enabled.
value := "bar"
e.Str("foo", value).Msg("some debug message")
}
}
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"}
Logging without Level or 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"}
Error Logging
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.
Error Logging with Stacktrace
Using github.com/pkg/errors, you can add a formatted stacktrace to your errors.
package main
import (
"github.com/pkg/errors"
"github.com/rs/zerolog/pkgerrors"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack
err := 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
}
// Output: {"level":"error","stack":[{"func":"inner","line":"20","source":"errors.go"},{"func":"middle","line":"24","source":"errors.go"},{"func":"outer","line":"32","source":"errors.go"},{"func":"main","line":"15","source":"errors.go"},{"func":"main","line":"204","source":"proc.go"},{"func":"goexit","line":"1374","source":"asm_amd64.s"}],"error":"seems we have an error here","time":1609086683}
zerolog.ErrorStackMarshaler must be set in order for the stack to output anything.
Logging Fatal Messages
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 1
NOTE: Using
Msgfgenerates one allocation even when the logger is disabled.
Create logger instance to manage different outputs
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"}
Sub-loggers let you chain loggers with additional context
sublogger := log.With().
Str("component", "foo").
Logger()
sublogger.Info().Msg("hello world")
// Output: {"level":"info","time":1494567715,"message":"hello world","component":"foo"}
Pretty logging
T
