Logging in Go Applications: Best Practices for Beginners
\n\nLogging is one of the key components of any serious application. It helps track errors, analyze system behavior, and understand what is happening "under the hood." In this article, we will cover the best practices for logging in Go (Golang) for beginner developers. You will learn which libraries to use, how to organize logs, and how to avoid common mistakes.
\n\nWhy is Logging Important in Go?
\n\nGo is a language focused on building high-load server applications and microservices. In such systems, without quality logging, it is impossible to:
\n\n- \n
- Quickly find the cause of a failure \n
- Understand the sequence of events \n
- Collect metrics for monitoring \n
- Debug code in a production environment \n
Poorly configured logging can lead to the loss of critical data or, conversely, to disk overflow with millions of useless messages. Therefore, it is important to establish the correct architecture from the very beginning.
\n\nThe Standard log Library
\n\nGo provides a built-in log package, which is suitable for simple projects. It can output messages to stdout/stderr, add timestamps, and terminate the program on fatal errors.
package main\n\nimport (\n "log"\n)\n\nfunc main() {\n log.Println("Application started")\n log.Printf("User %s logged in", "admin")\n // log.Fatal("Critical error") // terminates the program\n}\n\nDisadvantages of the standard logger:
\n- \n
- No logging levels (debug, info, warn, error) \n
- No structured output (text only) \n
- Difficult to change the format and output destination \n
This is sufficient for educational projects and simple utilities, but for production applications, it is better to use more powerful libraries.
\n\nPopular Logging Libraries
\n\nLet's look at three of the most common options.
\n\n1. Logrus
\n\nLogrus is one of the first third-party libraries for Go. It supports logging levels, structured fields, and multiple output formats (JSON, text).
\n\npackage main\n\nimport (\n "github.com/sirupsen/logrus"\n)\n\nfunc main() {\n log := logrus.New()\n log.SetFormatter(&logrus.JSONFormatter{})\n log.SetLevel(logrus.InfoLevel)\n\n log.WithFields(logrus.Fields{\n "user": "ivan",\n "action": "login",\n }).Info("User logged in")\n}\n\nLogrus is easy to use but has high memory consumption and is slightly slower than modern alternatives.
\n\n2. Zerolog
\n\nZerolog is a modern library focused on performance and minimal memory allocation. It uses a zero-allocation approach and is ideal for high-load systems.
\n\npackage main\n\nimport (\n "github.com/rs/zerolog"\n "github.com/rs/zerolog/log"\n)\n\nfunc main() {\n zerolog.TimeFieldFormat = zerolog.TimeFormatUnix\n\n log.Info().\n Str("user", "ivan").\n Str("action", "login").\n Msg("User logged in")\n\n log.Error().\n Err(fmt.Errorf("connection refused")).\n Msg("Database connection error")\n}\n\nZerolog outputs logs in JSON format by default, which simplifies parsing by monitoring systems (ELK, Grafana Loki).
\n\n3. Zap
\n\nZap from Uber is another high-performance logger. It operates in two modes: SugaredLogger (convenient but slightly slower) and Logger (maximum speed).
package main\n\nimport (\n "go.uber.org/zap"\n)\n\nfunc main() {\n logger, _ := zap.NewProduction()\n defer logger.Sync()\n\n logger.Info("Server started",\n zap.String("port", "8080"),\n zap.Int("workers", 10),\n )\n}\n\nFor n