Logging for Go (Golang): Best Solutions
Logging is a fundamental part of any serious application. In the Go (Golang) ecosystem, there are many libraries, each offering its own balance between performance, flexibility, and convenience. In this article, we will look at the best solutions for logging in Go, starting from the standard library to high-performance tools such as zerolog and zap.
Standard Library: log
Go comes with a built-in log package. It is simple but has limitations: no logging levels (Debug, Info, Warn, Error), no support for structured output (JSON), and minimal formatting capabilities. However, for small projects or quick debugging, it is quite suitable.
package main
import ( "log")
func main() { log.Println("This is an informational message") log.Fatalln("Fatal error, application will exit")}Pros: no installation required, zero dependencies.
Cons: low flexibility, no logging levels, no structured logs.
Logrus — Classic with Extensive Capabilities
Logrus was the de facto standard for logging in Go for a long time. It provides logging levels, JSON format support, and many hooks for integration with external systems (Logstash, Sentry, etc.).
package main
import ( "github.com/sirupsen/logrus")
func main() { log := logrus.New() log.SetFormatter(&logrus.JSONFormatter{})
log.WithFields(logrus.Fields{ "user_id": 123, "action": "login", }).Info("User logged into the system")}Pros: rich API, many hooks, support for structured logs.
Cons: relatively low performance, large binary file size.
Zerolog — High Performance and Zero Allocations
Zerolog (from the creators of RSocket) is a library that puts performance first. It uses the "zero allocation" principle for hot paths, making it one of the fastest in Go. Zerolog is ideal for microservices and high-load systems.
package main
import ( "github.com/rs/zerolog" "github.com/rs/zerolog/log")
func main() { // Configure global logger zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
log.Info(). Str("service", "auth"). Int("user_id", 456). Msg("Request authorized")
// Error logging err := someFunction() if err != nil { log.Error().Err(err).Msg("Failed to perform operation") }}
func someFunction() error { return nil}Pros: record performance, low memory consumption, simple API.
Cons: less flexible than Logrus, requires getting used to chained syntax.
Zap — Industry Standard from Uber
Zap (Zap Awesome Performance) was developed by engineers at Uber. It offers two modes: SugaredLogger (convenient but with slight overhead) and Logger (maximum speed). Zap supports structured logs, levels, and custom encoders.
package main
import ( "go.uber.org/zap")
func main() { // Create logger (Production mode) logger, _ := zap.NewProduction() defer logger.Sync() // flushes buffer, if any
// SugaredLogger — convenient syntax sugar := logger.Sugar() sugar.Infow("Server started", "port", 8080, "env", "production", )
// Logger — maximum performance logger.Info("Key event", Also in library
Cryptography in Rust with the RustCrypto Library
Data Validation in Go: Libraries, Examples, and Best Practices
Task Queues in Swift: GCD, OperationQueue and Swift Concurrency
Geolocation and Maps in PHP: Libraries, API, and Code Examples
Monitoring C# (.NET) Applications with OpenTelemetry and Prometheus