Go strings are not marshallers
So, you’ve built a nifty custom slog.Handler
in Go. It’s dutifully processing your application’s logs, maybe even shipping them off to a service like BigQuery. Things are great, until… fatal error: stack overflow
. What gives?
This was precisely the situation I found myself in. My CologHandler
had a method, uploadToBigQuery
, responsible for, well, uploading logs. Inside this method, I was iterating through log attributes. If an attribute wasn’t a json.Marshaler
, I’d log a warning using slog.Warn
. I was aware that the new slog would call itself and therefore also trigger a new upload. Since I converted the value, that wasn’t suitable for JSON marshalling, to a string, I thought everything was safe. Because strings can be marshalled to JSON, right? Well, not quite.
``go r.Attrs(func(a slog.Attr) bool { value, ok := a.Value.Any().(json.Marshaler) if ok { params[a.Key] = value } else { slog.Warn(“non-json-marshaler value in log attributes”, “key”, a.Key, “value”, a.Value.String()) } return true })
Primitive types, including strings, do not implement the `json.Marshaler` interface directly. They can be marshalled to JSON, but they don't explicitly declare that they can be marshalled.
This of course caused another call to `slog.Warn`, and another, and another... until the stack overflowed.