Last time we looked at slog.Group, which accepts the variadic ...any as arguments. But there’s also a version that accepts slog.Attr values:
func GroupAttrs
func GroupAttrs(key string, attrs ...Attr) AttrGroupAttrs returns an Attr for a Group Value consisting of the given Attrs.
GroupAttrs is a more efficient version of Group that accepts only Attr values.
But notice there’s no mixed form of this, like there is for the standard logging functions. That means one must choose between passing all untyped arguments, or all slog.Attr arguments. We can’t mix them, as we can for slog.Info, for example.
And if you’re ever building your own slog utilities, this same issue is likely to bite you. How do you create a slog wrapper that accepts both any key/value pairs and slog.Attr values, as slog.Info does?
Unfortunately, the slog package doesn’t export this mapping. But you can extract it into your own function. And I’ve found myself doing that enough, that I think it’s worth offering you the function I use for just that (see it in action in one of my libraries here)
// toAttrs converts args into a slice of [slog.Attr], using the
// same rules employed by [slog].
func toAttrs(args ...any) []slog.Attr {
attrs := make([]slog.Attr, 0, len(args)/2)
var i int
for i < len(args) {
switch t := args[i].(type) {
case slog.Attr:
attrs = append(attrs, t)
i++
continue
case string:
if i+1 < len(args) {
attrs = append(attrs, slog.Any(t, args[i+1]))
i += 2
continue
}
}
attrs = append(attrs, slog.Any("!BADKEY", args[i]))
i++
}
return attrs
}