[ https://issues.apache.org/jira/browse/THRIFT-5745?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Yuxuan Wang reassigned THRIFT-5745: ----------------------------------- Assignee: Yuxuan Wang > 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 > Assignee: Yuxuan Wang > Priority: Major > > 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)