TIL Logger.LogAttrs is a thing! But what is that thing??
Yesterday I mentioned that using an slog.Attr can be marginally more efficient than using naked key/value pairs in a log call. While true, that glosses over what is likely to be a much more impactful performance consideration in certain applications…
Attrs and Values
…
The value part of an Attr is a type called Value. Like an [any], a Value can hold any Go value, but it can represent typical values, including all numbers and strings, without an allocation.
For the most efficient log output, use Logger.LogAttrs. It is similar to Logger.Log but accepts only Attrs, not alternating keys and values; this allows it, too, to avoid allocation.
The call
logger.LogAttrs(ctx, slog.LevelInfo, "hello", slog.Int("count", 3))is the most efficient way to achieve the same output as
slog.InfoContext(ctx, "hello", "count", 3)
So by using an slog.Attr and passing it to the LogAttrs method of the logger, rather than the much more convenient level-based methods (Info, Error, etc), you can avoid an extra memory allocation per attribute.
For many applications this won’t matter much. But there are applications where constructing and streaming logs adds a significant burden to the garbage collector. If this describes your application, consider using the less convenient LogAttrs—at least in hot paths.