Why does adding `backtrace` to thiserror/anyhow require adding debug symbols?
You'll certainly need it if you want to have human readable source code locations, but doesn't it work with addresses only? Can't you split off the debug symbols and then use `addr2line` to resolve source code locations when you get error messages from end users running release builds?
> Consequently, this also means you cannot define two error variants from the same source type. Considering you are performing some I/O operations, you won't know whether an error is generated in the write path or the read path. This is also an important reason we don't use thiserror: the context is blurred in type.
This is true only if you add #[from] attribute to a variant. Implementing std::convert::From is completely optional. Personally I don't prefer it too as it ambiguates the context. I only use it for "trivially" wrapped errors like eyre::Report.
> Then, to be able to translate the stack pointer we will need to include a large debuginfo in our binary. In GreptimeDB, this means increasing the binary size by >700MB (4x compared to 170MB without debuginfo).
Surely that's comparing full debuginfo, right? Backtraces just need symbols, not full debuginfo, and there's no way the symbols are 4x the size of the binary.
There's also split-debuginfo, which allows emission of debug info into a separate file, rather than needing to distribute it in the binary. Then they could capture stack traces, and resolve the symbols later if necessary. That would also address their concern about how long it takes to capture a stack trace, because just gathering the addresses themselves is quick.
Hey all, I’m the author of SNAFU (mentioned in the article). I’m off to bed now, but I’d be happy to try and answer any questions people might have sometime tomorrow.
What is really annoying with thiserror is the wizard refusal to give us an easy way to print the error chain. No I dont want to convert it to anyhow just to print the error...
Rust is full of these, I’ve found the community simply falls back on user error to understand rust when vexed by in my opinion basic software operations.
As someone who works extensively in cpp/java/python. I want so much to love rust, but unfortunately I haven’t found it to be productive after 6+ side projects.
Rust's community is slightly more fragmented than it should be. The community being built while the language was changing so dramatically (e.g. async) didn't help, but it also is part of what lead to Rust in the first place.
But it's still somewhat young, lots of stuff is being built. So some of the lack of productivity probably just comes from not knowing the right stacks yet.
async fn handle_request(req: Request) -> Result<Output> {
let msg = decode_msg(&req.msg).context(DecodeMessage)?; // propagate error with new stack and context
verify_msg(&msg)?; // pass error to the caller directly
process_msg(msg).await? // pass error to the caller directly
}
async fn decode_msg(msg: &RawMessage) -> Result<Message> {
serde_json::from_slice(&msg).context(SerdeJson) // propagate error with new stack and context
}
how to capture the virtual stack when `verify_msg` returns an error? Do you have some lint to make sure every error is attached with a context?
A good error report is not only about how it gets constructed, but what is more important, to tell what human can understand from its cause and trace.
In this example, we analyzed and showed how to design stacked errors and what should be considered in this process.
This seems to be a fairly common sentiment. I consider Rust's syntax fairly consistent and elegant for a curly brace language, but evidently I have some blind spots. What quibbles do you have with Rust's syntax?
To quote Tsoding, https://x.com/tsoding/status/1832631084888080750: "Rust is a very safe, unergonomic language with annoying community and atrocious syntax. Which is somehow surprisingly miles better than modern C++."
I feel like there's plenty of places to make criticisms of Rust's syntax, but the example they picked has like half a dozen places where the full path to reference an item is used instead of importing it. Sure, there are languages where you're required to import things rather than referencing them in the full path, but there are also languages where you don't have any flexibility in the paths to use something (e.g. Go and Java) or where they dump literally everything into a single namespace with no context (e.g. C and C++). Using the entire path to something instead of importing it is absurdly less common by at least an order of magnitude over importing things directly, so it's not like people are abusing it all over the place (if anything, people probably import things _more_ than they need to, like with top-level functions that might otherwise make their provenance obvious). Having an option to do things verbosely that most people don't actually do is "unergonomic"? It's like saying the problem with Unix file paths is that using absolute paths for literally everything is ugly; sure, it can be, but that's also just not how 99% of people use them.
Why does adding `backtrace` to thiserror/anyhow require adding debug symbols?
You'll certainly need it if you want to have human readable source code locations, but doesn't it work with addresses only? Can't you split off the debug symbols and then use `addr2line` to resolve source code locations when you get error messages from end users running release builds?
> Consequently, this also means you cannot define two error variants from the same source type. Considering you are performing some I/O operations, you won't know whether an error is generated in the write path or the read path. This is also an important reason we don't use thiserror: the context is blurred in type.
This is true only if you add #[from] attribute to a variant. Implementing std::convert::From is completely optional. Personally I don't prefer it too as it ambiguates the context. I only use it for "trivially" wrapped errors like eyre::Report.
Yup. I absolutely would throw `#[from]` on everything when I started using thiserror, but now only do so in incredibly obvious cases like
Even then, there’s often some additional context you can affix at that higher level.> Then, to be able to translate the stack pointer we will need to include a large debuginfo in our binary. In GreptimeDB, this means increasing the binary size by >700MB (4x compared to 170MB without debuginfo).
Surely that's comparing full debuginfo, right? Backtraces just need symbols, not full debuginfo, and there's no way the symbols are 4x the size of the binary.
There's also split-debuginfo, which allows emission of debug info into a separate file, rather than needing to distribute it in the binary. Then they could capture stack traces, and resolve the symbols later if necessary. That would also address their concern about how long it takes to capture a stack trace, because just gathering the addresses themselves is quick.
Hey all, I’m the author of SNAFU (mentioned in the article). I’m off to bed now, but I’d be happy to try and answer any questions people might have sometime tomorrow.
I’m glad to see SNAFU was useful to others!
Its looks really neat! Two questions:
* can it be used as a build dependency (i.e symbols from the snafu crate don't appear in the generated code).
* I assume you have to use one of the macros (ensure! or location!) when constructing an error that contains a location?
It's technically feasible to add SpanTrace support to thiserror fairly easily (30 mins work - Issue: https://github.com/dtolnay/thiserror/issues/400, PR: https://github.com/dtolnay/thiserror/pull/401). This would solve part of the problem in a way that is meaningfully good for that side of the ecosystem. I suspect you could probably do something similar for Snafu
What is really annoying with thiserror is the wizard refusal to give us an easy way to print the error chain. No I dont want to convert it to anyhow just to print the error...
Rust is full of these, I’ve found the community simply falls back on user error to understand rust when vexed by in my opinion basic software operations.
As someone who works extensively in cpp/java/python. I want so much to love rust, but unfortunately I haven’t found it to be productive after 6+ side projects.
Rust's community is slightly more fragmented than it should be. The community being built while the language was changing so dramatically (e.g. async) didn't help, but it also is part of what lead to Rust in the first place.
But it's still somewhat young, lots of stuff is being built. So some of the lack of productivity probably just comes from not knowing the right stacks yet.
URL changed, I think: https://greptime.com/blogs/2024-05-07-rust-error-handling
A good error report is not only about how it gets constructed, but what is more important, to tell what human can understand from its cause and trace. In this example, we analyzed and showed how to design stacked errors and what should be considered in this process.
[dead]
Rust is such a powerful yet completely disgusting language. I’m teaching myself rust out of spite at this point.
Everything about the syntax of the language is awful.
This seems to be a fairly common sentiment. I consider Rust's syntax fairly consistent and elegant for a curly brace language, but evidently I have some blind spots. What quibbles do you have with Rust's syntax?
The explosion of single character sigils and the taint of C++'s template syntax.
The only single-character sigils I can think of are '&', '*', '\'', and maybe '?'. Am I missing any?
I kinda feel like macros!() should count.
The ' for lifetimes as well.
It's probably the explosion of those characters and punctuation characters like in this example: https://x.com/AndersonAndrue/status/1864457598629540348
To quote Tsoding, https://x.com/tsoding/status/1832631084888080750: "Rust is a very safe, unergonomic language with annoying community and atrocious syntax. Which is somehow surprisingly miles better than modern C++."
> It's probably the explosion of those characters and punctuation characters like in this example: https://x.com/AndersonAndrue/status/1864457598629540348
I feel like there's plenty of places to make criticisms of Rust's syntax, but the example they picked has like half a dozen places where the full path to reference an item is used instead of importing it. Sure, there are languages where you're required to import things rather than referencing them in the full path, but there are also languages where you don't have any flexibility in the paths to use something (e.g. Go and Java) or where they dump literally everything into a single namespace with no context (e.g. C and C++). Using the entire path to something instead of importing it is absurdly less common by at least an order of magnitude over importing things directly, so it's not like people are abusing it all over the place (if anything, people probably import things _more_ than they need to, like with top-level functions that might otherwise make their provenance obvious). Having an option to do things verbosely that most people don't actually do is "unergonomic"? It's like saying the problem with Unix file paths is that using absolute paths for literally everything is ugly; sure, it can be, but that's also just not how 99% of people use them.
Anderson's example has literally one more sigil than the equivalent C++
> and the taint of C++'s template syntax.
Interestingly enough, nobody says that when talking about TypeScript…
What's mandated to be a single character? I'm not sure what the popular style is today.
Which statically typed language do you find most agreeable?
Same question for any language.
Rust's syntax is largely irrelevant to its purpose. If you don't see the need for it, might as well learn something else.
idk if its about a few syntax, then it's possible to make a temp proc-macro for those