The landscape of logging in Go has undergone a significant transformation with the introduction of the log/slog package in Go 1.21. This pivotal addition to the standard library ushers in structured logging, a paradigm shift that enables developers to process, filter, search, and analyze log data with unprecedented speed and reliability. For complex server environments, where logs often represent the first line of defense for debugging and system observation, the sheer volume of data necessitates efficient handling – a task slog is purpose-built to address.
For over a decade, Go developers relied on the basic log package. However, the demand for structured logging grew steadily, consistently ranking high in community surveys. This led to a proliferation of third-party packages, such as the highly popular logrus, used in over 100,000 other packages. While these solutions were effective, they often introduced dependency management challenges, forcing large applications to configure multiple logging systems for consistent output. slog aims to resolve this by providing a unified, standard framework that existing and future logging packages can leverage.
A Deep Dive into slog‘s Capabilities
Getting Started: Simplicity and Power
At its core, slog is designed for ease of use. The simplest implementation demonstrates its straightforward nature:
package main
import “log/slog”
func main() {
slog.Info(“hello, world”)
}
This code, when executed, produces an output strikingly similar to that of the traditional log package, adding only the “INFO” level designation. This seamless integration ensures a gentle learning curve for developers transitioning from the older logging system.
Beyond the Info level, slog provides functions for Debug, Warn, and Error. Its flexible design allows for custom log levels, as levels are simply integers, enabling granular control over logging intensity. The true power of structured logging, however, emerges when incorporating key-value pairs directly into log entries:
slog.Info(“hello, world”, “user”, os.Getenv(“USER”))
This simple addition transforms the log output into parsable data, a fundamental aspect of structured logging. While top-level functions utilize a default logger, developers can explicitly access and interact with slog.Logger instances for greater control.
Customizing Output with Handlers
The versatility of slog shines through its handler mechanism. Initially, slog logs through the default log.Logger. However, developers can easily change the output format by configuring a different handler. The package includes two built-in options:
TextHandler: Emits log information askey=valuepairs, quoting strings as needed to maintain structure.
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
logger.Info(“hello, world”, “user”, os.Getenv(“USER”))
JSONHandler: Produces a stream of JSON objects, ideal for machine parsing and integration with logging platforms.
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
logger.Info(“hello, world”, “user”, os.Getenv(“USER”))
Beyond these built-in options, slog‘s extensible slog.Handler interface allows developers to create custom handlers. This enables bespoke output formats, or even the ability to wrap existing handlers to add functionality, such as dynamic log level adjustments.
Optimized Logging with Attrs and Context
For high-performance scenarios, especially in frequently executed code paths, slog offers the Attr type and the LogAttrs method. These are designed to minimize memory allocations, significantly enhancing logging efficiency:
slog.LogAttrs(context.Background(), slog.LevelInfo, “hello, world”,
slog.String(“user”, os.Getenv(“USER”)))
Furthermore, slog integrates with context.Context, allowing handlers to extract valuable contextual information like trace IDs. Other powerful features include:
Logger.With: Attaches common attributes to a logger instance, which are then included in all subsequent log outputs from that logger. This not only streamlines code but also boosts performance by pre-formatting attributes once.- Attribute Grouping: Organizes related attributes into logical groups, enhancing log readability and preventing key ambiguity.
LogValuerInterface: Provides granular control over how values are serialized into logs, enabling advanced use cases such as logging struct fields as a group or redacting sensitive data.
Engineering for Speed: slog‘s Performance Focus
Performance was a core tenet in slog‘s design. The Handler interface was meticulously crafted to offer critical optimization points. The Enabled method, invoked at the start of every log event, allows handlers to quickly discard irrelevant messages, preventing unnecessary processing. Methods like WithAttrs and WithGroup enable handlers to format common attributes once, rather than repeatedly with each log call. This pre-formatting yields substantial speedups, particularly when large data structures, such as HTTP requests, are attached to a logger.
Extensive research into real-world logging patterns in open-source projects informed these optimizations. Findings revealed that over 95% of logging calls involve five or fewer attributes, with a handful of common data types dominating. By focusing on these typical scenarios and prioritizing memory allocation efficiency through rigorous benchmarking, the Go team achieved significant performance gains for slog.
The Collaborative Journey: Designing slog
slog stands as one of the largest additions to the Go standard library since its inception in 2012. Its development was a deliberate, iterative process, heavily reliant on community feedback. Beginning in April 2022, the Go team researched existing structured logging packages and analyzed their real-world usage. The initial design aimed for an API that was simple, intuitive, and performant, embodying Go’s minimalist philosophy.
A crucial decision was to design slog not as a replacement for existing third-party solutions, but as a common backend framework. By dividing the API into a Logger frontend and a Handler backend interface, existing packages like Zap, logr, and hclog can integrate with slog, fostering interoperability across the ecosystem.
Navigating Design Debates
The design journey was marked by robust community discussion and refinement. An experimental implementation was made public in August 2022, sparking a GitHub discussion that led to significant improvements, including the addition of groups and the LogValuer interface. Even fundamental aspects like log level to integer mappings underwent revisions.
The proposal phase, garnering over 800 comments, further shaped the API. Notable debates included:
- Context in Loggers: The initial idea of adding loggers to a
context.Contextfor implicit plumbing was ultimately removed due to concerns about introducing hidden dependencies and making code harder to reason about. - Context in Logging Methods: The team grappled with passing a context to logging methods. While initially resistant to making it a mandatory first argument, the eventual solution involved providing two sets of methods: one with a context and one without.
- Alternating Key-Value Syntax: The syntax
slog.Info("message", "k1", v1, "k2", v2)generated significant debate. Critics argued it was prone to errors and less readable than explicit attribute construction (e.g.,slog.Info("message", slog.Int("k1", v1), slog.String("k2", v2))). However, drawing inspiration from other successful Go logging packages, the lighter syntax was retained to keep Go approachable, especially for new programmers. A static analysisvetcheck was introduced to mitigate common mistakes.
Following the proposal’s acceptance in March 2023 and several weeks of resolving minor issues, the log/slog package, alongside testing/slogtest for handler verification and the vet check, was completed by early July. Its official release coincided with Go 1.21 on August 8.
Resources and Community Contributions
For those eager to delve deeper, comprehensive documentation for log/slog is available, offering examples and usage guidelines. The Go community has further enriched the ecosystem with a wiki page compiling additional resources and various handler implementations. Developers looking to craft their own handlers can consult a dedicated handler writing guide.

Image: Navigating the modern logging landscape with slog.
The journey of slog from concept to a standard library staple underscores the Go team’s commitment to community-driven development and the evolving needs of modern software systems. With its robust features, performance focus, and extensible design, slog is poised to standardize and elevate the logging experience for Go developers worldwide.
As slog integrates more deeply into the Go ecosystem, how will its presence reshape the development of debugging tools and observability platforms?




