Yuxuan Wang created THRIFT-5745:
-----------------------------------
Summary: go: Implement slog.LogValuer for exceptions and/or structs
Key: THRIFT-5745
URL: https://issues.apache.org/jira/browse/THRIFT-5745
Project: Thrift
Issue Type: Task
Components: Go - Compiler
Reporter: Yuxuan Wang
To follow up on THRIFT-5744, implement
[slog.LogValuer|https://pkg.go.dev/log/slog#LogValuer] on compiler generated
exceptions, and maybe also structs.
The current problem is that when logging an exception, the Stringer
implementation will be used, but that usually gives you quite unhelpful string,
especially when optional fields are used.
For example we have [this exception
defined|https://github.com/reddit/baseplate.py/blob/8c446337dab6a1692900decf9cd01f3f4e39d764/baseplate/thrift/baseplate.thrift#L197]:
{code:java}
exception Error {
1: optional i32 code
2: optional string message
3: optional map<string, string> details
4: optional bool retryable
}
{code}
When you create an instance of it:
{code:go}
return &baseplate.Error{
Code: thrift.Int32Ptr(404),
Message: thrift.Pointer("no such id"),
}
{code}
And then log that error, instead of getting something useful with the code
(404) and message ("no such id") in it, you get something like this instead
because this is how we implemented fmt.Stringer from the compiler:
{code:go}
Error({Code:0xc000426648 Message:0xc00041ca10 Details:map[] Retryable:<nil>})
{code}
The compiler generates implementation for json.Marshaler for all exceptions,
which will be much more helpful. The marshaled json for such error would be:
{code:json}
{"code":400,"message":"no such id"}
{code}
They are also much more expensive, so probably not suitable to replace the
current Stringer implementation, but when logging them, it's probably worth it
to implement slog.LogValuer so we can log something more useful, probably like
this:
{code:go}
func (p *Error) LogValue() slog.Value{
var sb strings.Builder
sb.WriteString("baseplate.Error")
bytes, err := json.Marshal(p)
if err != nil {
// should not happen
return slog.StringValue(fmt.Sprintf("baseplate.Error.LogValue: failed to
marshal json: %v", err))
}
sb.Write(bytes)
return slog.StringValue(sb.String())
}
{code}
Which will make the error logged show as:
{code:json}
baseplate.Error{"code":400,"message":"no such id"}
{code}
Some open questions:
# Is this also useful for structs?
# Do we want to make this optional (e.g. only generate LogValue function when a
compiler flag is passed in)?
--
This message was sent by Atlassian Jira
(v8.20.10#820010)