4 ms·
My biggest gripe with slog is that there is no clear guidance on supported types of attributes. One could argue that supported types are the ones provided by A
by aleksi 1y ago
My biggest gripe with slog is that there is no clear guidance on supported types of attributes.
One could argue that supported types are the ones provided by Attr "construct" functions (like slog.String, slog.Duration, etc), but it is not enough. For example, there is no function for int32 – does it mean it is not supported? Then there is slog.Any and some support in some handlers for error and fmt.Stringer interfaces. The end result is a bit of a mess.
- 0x696C6961 1y agoAll values are supported.
- aleksi 1y agoWell, is fmt.Stringer supported? The result might surprise you: req := expvar.NewInt("requests") req.Add(1) attr := slog.Any("requests", req) slog.New(slog.NewTextHandler(os.Stderr, nil)).Info("text", attr) slog.New(slog.NewJSONHandler(os.Stderr, nil)).Info("json", attr) This code produces time=2025-09-12T13:15:42.125+02:00 level=INFO msg=text requests=1 {"time":"2025-09-12T13:15:42.125555+02:00","level":"INFO","msg":"json","requests":{}} So the code that uses slog but does not know what handler will be used can't rely on it lazily calling the `String() string` method: half of the standard handlers do that, half don't.
- 0x696C6961 1y agoIf you need more control, you can create a wrapper type that implements `slog.LogValuer` type StringerValue struct { fmt.Stringer } func (v StringerValue) LogValue() slog.Value { return slog.StringValue(v.String()) } Usage example: slog.Any("requests", StringerValue{req}) There might be a case for making the expvar types implement `slog.LogValuer` directly.
- aleksi 1y agoSo clearly not all values are supported. And I know that I can create a wrapper for unsupported types. My problem is exactly that – I don't know what types are supported. Is error supported, for example? Should I create a wrapper for it? And, as a handler author, should I support it directly or not?
- 0x696C6961 1y agoNot sure what your definition of "supported" is, but I'm afraid you're going to have to bite the bullet and ... gasp ... read the documentation https://pkg.go.dev/log/slog https://pkg.go.dev/log/slog
- aleksi 1y agoNot sure I understand your sarcasm. I read the documentation, source code, handler writing guide, and issues in the Go repository multiple times over two years, and I use slog extensively. Go is my primary language since r60. I think I know how to read Go docs. Now, please point me to the place in the documentation that says if I can or can't use a value implementing the error interface as an attribute value, and will the handler or something else would call the `Error() string` method. My definition of "supported" is simple – I could pass a supported value to the logger and get a reasonable representation from any handler. In my example, the JSON handler does not provide it for the fmt.Stringer.
- arccy 1y agohttps://pkg.go.dev/log/slog#JSONHandler.Handle https://pkg.go.dev/log/slog#JSONHandler.Handle > Values are formatted as with an encoding/json.Encoder with SetEscapeHTML(false), with two exceptions. > First, an Attr whose Value is of type error is formatted as a string, by calling its Error method. Only errors in Attrs receive this special treatment, not errors embedded in structs, slices, maps or other data structures that are processed by the encoding/json package. So the json handler more or less works as if you called json.Marshal, which sounds pretty reasonable.
- 1y ago
- Philip-J-Fry 1y agoThat seems to work as expected? The output of data is handled by the handler. Such behaviour is clearly outlined in the documentation by the JSONHandler. I wouldn't expect a JSONHandler to use Stringer. I'd expect it to use the existing JSON interfaces, which it does. I'd expect the Text handler to use TextMarshaller. Which it does. Or Stringer, which it does implicitly via fmt.Sprintf.
- aleksi 1y agoMy problem with that is that it makes it impossible to use slog logger safely without knowing what handler is being used. Which kind of defeats the purpose of defining the common structured logging interface.