aws-lambda-rust-runtime: Match error handling to other runtimes
The format of error messages returned by the runtime is hard to work with at the client end.
Example:
{
"errorType": "alloc::boxed::Box<dyn std::error::Error+core::marker::Sync+core::marker::Send>",
"errorMessage": "LambdaError { msg: \"cust error\", source: \"somewhere in code\", code: InvalidInput }"
}
It is produced by this code in https://github.com/awslabs/aws-lambda-rust-runtime/blob/f40461785625d8ac23e7c248367b1d724ef2b5ba/lambda/src/lib.rs#L216
Err(e) => EventErrorRequest {
request_id,
diagnostic: Diagnostic {
error_message: format!("{:?}", e),
error_type: type_name_of_val(e).to_owned(),
},
}
.into_req()?,
with help from
fn type_name_of_val<T>(_: T) -> &'static str {
std::any::type_name::<T>()
}
Proposed change
- Log the error message, probably via
error!so that it appears in CloudWatch. - Serialise
einto JSON instead of Debug output ({:?}). - Allow to set error type and fall back on
std::any::type_nameif none was provided.
Here are examples of what other runtimes are producing:
- C#: https://docs.aws.amazon.com/lambda/latest/dg/csharp-exceptions.html
- Go: https://docs.aws.amazon.com/lambda/latest/dg/golang-exceptions.html
- Java: https://docs.aws.amazon.com/lambda/latest/dg/java-exceptions.html
- NodeJS: https://docs.aws.amazon.com/lambda/latest/dg/nodejs-exceptions.html
Discussion
I’m not 100% sure how it all can be implemented yet. Just wondering if this is a problem that impacts others and is worth looking into.
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 1
- Comments: 35 (34 by maintainers)
Commits related to this issue
- Merge remote-tracking branch 'rimutaka/master' into merge_branch * rimutaka/master: (26 commits) Removed unnecessary + Sync on handler's future Added docs and missing _vars to reduce warnings E... — committed to markdingram/aws-lambda-rust-runtime by calavera 4 years ago
- Error logging and examples (#284) * reorg * Replace `genawaiter` with `async-stream` (#240) * don't depend on serde_derive directly * Add Cargo.lock to gitignore; whoops. * Cleanup docs; ... — committed to awslabs/aws-lambda-rust-runtime by bahildebrand 3 years ago
+1
I’m wondering if it helps to move things forward. can we separate how the error name is derived from how it is logged? there’s lots of ways to log an error but I assume there’s like one pretty good way to format the name of the error type.
On picking a log impl and size and all that. cargo feature flags can help with that!
Yup, here’s how: https://github.com/awslabs/aws-lambda-rust-runtime/blob/davidbarsky/update-readme/lambda/examples/hello-without-macro-tracing.rs#L16.
Kinda. That’ll enable
tracing’slogfacade, which is in turn enabled by this feature. This feature was initially missing.Hrm, I’m unable to reproduce this. The first example below makes use of
simple_loggerand it has output from thelambdacrate.tracing-subscriberoutput has a similar output, also from thelambdacrate.@brainstorm
I think using cargo bloat is a good idea, but I’d hold off on making a PR.
Just wanted to echo the voice of a minimal runtime again so something can ship soon. The problem to be solved here is to log an error, correct?
tracingfeels a bit much just to print an error to the stdout/err. What was wrong withlog::error!("{}", e)and letting the user select the log impl of their choice in theirmainagain?I’ll attempt a PR in a few days.
Further to the discussion on the bloat and the size of the binaries. Compiled with
cargo build --release --target x86_64-unknown-linux-musl --examples. I have no idea if this is too big or OK. Just stating the facts.@rimutaka
This is where I disagree and regret mentioning
tracing.tracingwill not impact how your error will be rendered or logged; I only mentionedtracingin reference to your comment on https://github.com/rust-lang/log/issues/357 because it’ll allow you to preserve the fact that you’re recording an error if and only if you’re using atracingSubscriber.logusers will not benefit from this feature oftracing, but they will not be harmed either—they will merely get the fallbackDebugorDisplayrendering.With that being said—and please correct me if I’m wrong—this issue was opened to resolve how this runtime should report errors to the Invocation error endpoint. The current implementation has lots of room for improvement—I’ll accept ownership and blame for that.
I’ve personally found
eyre::Reportto be a really compelling illustration of the distinction between error handling and error reporting, the latter of which this issue focuses on. I’ll say this off the bat: I don’t think we can useeyre, but I think we can get some inspiration from its ideas. One approach I’ve been thinking about is keeping theInto<Box<dyn std::error::Error + Send + Sync + 'static>>bounds but (re)introducing astd::panic::set_hook-style error reporting hook to this runtime. It’ll have a closure that accepts aBox<dyn std::error::Error + Send + Sync + 'static>, but you’d be able to downcast to specific error variants and convert them to aDiagnosticaccordingly. Here’s a limited example:As @Veetaha mentioned in https://github.com/awslabs/aws-lambda-rust-runtime/issues/243#issuecomment-662741226, we’re between a rock (the current AWS APIs) and a hard place (the lack of stable specialization in Rust). This downcasting-based approach feels like the least bad approach to me, but what do you think?
Additionally, free to ping me directly over Discord or even setup a call. I’d be happy to walk through and discuss my thinking, which might be lossy over text.
Thanks for opening this issue! I’m personally inclined to use
tracingoverlog(given that I’m one of the authors oftracing…), if only because it integrates with XRay already.We had a similar set up in the past but required muuuch more machinery and was a bit onerous on the user end. There might still.be a way to have the best of both worlds with fancy downcasting. I’d propose some unit tests here. Might have caught the usability issue sooner
I have an even simpler suggestion, use
Displayinstead ofDebug.Displayis often implemented precisely for displaying a message.Debugis not meant for this purpose. You get this for free as implementingErrorrequires it so no extra type constraints are needed .