4 ms·
One error handling pattern I’d like to figure out how to implement in Rust is where you trace the error out from the point it was created rather than capturing
by wallacoloo 7y ago
One error handling pattern I’d like to figure out how to implement in Rust is where you trace the error out from the point it was created rather than capturing a stack trace at creation time. Tracing the error this way is impactful when your application spans multiple processes or machines. Client/server systems, for sure (you can know what the server did to error, without extra noise in the trace from below where it received the command, and you also get a trace of the client’s side. It’s substantially more useful when the workload is distributed more.
The best I’ve come up with is using a custom ResultExt class which implements std::op::Try, marks its trait methods as inline(always), and then captures the program counter whenever you use `?` on it in order to build a trace. It’s not the worst, but it still feels a bit odd — particularly the forced inlining since that will surely break if you’re working with std::ops::Try from behind a trait object.
- shepmaster 7y agoCould you provide a deeper example of the difference you mean? Additionally, have you seen tracing (https://docs.rs/tracing/0.1.10/tracing/ https://docs.rs/tracing/0.1.10/tracing/)?
- AndyKelley 7y agoYou can also make it never inline, and use the return address instead of program counter. That's what zig does to implement this feature ("error return traces").
- wallacoloo 7y agoThis would mean an extra function call for _every _ use of `?` (rather than a conditional jump that the branch predictor has been well-primed for), even in the non-error path. My Rust code for some projects use `?` pretty frequently, to the point that I’d be concerned about perf. Of course, the only way to be sure is to profile. Do you have any perf measurements with this technique in zig?
- AndyKelley 7y agoBy default this feature is enabled in the Debug build mode only, so its perf impact isn't a concern in release builds. But that being said, the function call only happens in the error path, when returning an error from a function, right? Are you concerned about the perf of the error path? Maybe I'm not understanding something about your implementation. But yeah the way to be sure is to profile. When I get around to it I'll add a flag to allow enabling this feature in release builds and do some profiling.
- wallacoloo 7y ago> But that being said, the function call only happens in the error path, when returning an error from a function, right? std::ops::Try looks like: - fn into_result(self) -> Result<Self::Ok, Self::Error>; // called on `x` whenever you use the `x?` syntax. - fn from_error(v: Self::Error) -> Self; - fn from_ok(v: Self::Ok) -> Self; It's been a while since I explored this. I was thinking you'd `#[inline(always)]` the `into_result` method, but now that I look at the trait again, I think you would only force inline the `from_error` method and it should still work but without impacting the non-error path much.