Skip to content

feat: structured error logging / propagation#32

Merged
hainsdominic merged 13 commits intomainfrom
error-propagation
Jun 28, 2022
Merged

feat: structured error logging / propagation#32
hainsdominic merged 13 commits intomainfrom
error-propagation

Conversation

@hainsdominic
Copy link
Copy Markdown
Contributor

Why

Currently, when a function reaches the unreachable instruction (panics), the output will look like this:
Screen Shot 2022-06-23 at 12 40 10 PM

2x "Error:", no separation between logs and performance metrics and even no info at all opposed to what you would get by running a working function. Also, some logging info is lost, so it makes debugging harder.

How

This is how the new error reporting looks like:
Screen Shot 2022-06-23 at 11 15 19 AM

There is now the headers between the "results" and the "logs" that were previously only visible on successful functions.

There is now an "Error" header/block that displays the error reported by the Wasm engine.

In the logs, there is now the panic message from the Wasm binary itself. This will help debugging, because it allows to see the panic message and it even shows on what line the panic occurred.

Detail

Before, the structured output was not displayed, because the engine run function panicked because it was not able to serialize the output from the function. That was fixed by setting the output to null if the function did not output (as it happens when it panics).

Comment thread src/engine.rs Outdated
.into_inner();
let output: serde_json::Value = serde_json::from_slice(output.as_slice())
.map_err(|e| anyhow!("Couldn't decode Function Output: {}", e))?;
let output = serde_json::from_slice(raw_output.as_slice()).unwrap_or_default();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we fail to parse the output as JSON, we might want to show the user the raw string value instead of null so they can more easily debug what's happening. I'm thinking of a case where the function has a bug in it that causes it to output invalid JSON.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1. Also I wonder if it makes sense to use serde_json::Value::Null as the default here because that is also a possible output from the function. What if we had an enum like this:

enum FunctionOutput<'a> {
    Json(serde_json::Value),
    Other(&'a [u8]), // not sure what the best value is here
}

and then for the Other variant we could output it but maybe using red on the header with a note that it was invalid JSON

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The very last thing a Function does is returning its result, if the Function fails before returning, it will no return anything. "Returning" here is printing to stdout. However, if the value returned is not valid JSON, then an other error will occur. I forgot about this edge case and I'll update this PR with a fix. I really like the FunctionOutput enum idea, I'll play with that also.

Comment thread src/function_run_result.rs Outdated
Comment thread src/engine.rs Outdated
Comment thread src/engine.rs Outdated
.into_inner();
let output: serde_json::Value = serde_json::from_slice(output.as_slice())
.map_err(|e| anyhow!("Couldn't decode Function Output: {}", e))?;
let output = serde_json::from_slice(raw_output.as_slice()).unwrap_or_default();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1. Also I wonder if it makes sense to use serde_json::Value::Null as the default here because that is also a possible output from the function. What if we had an enum like this:

enum FunctionOutput<'a> {
    Json(serde_json::Value),
    Other(&'a [u8]), // not sure what the best value is here
}

and then for the Other variant we could output it but maybe using red on the header with a note that it was invalid JSON

Comment thread src/engine.rs Outdated
let title = " Benchmark Results ".black().on_bright_green();
let title = " Benchmark Results "
.black()
.on_truecolor(150, 191, 72);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did we change the color?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first one is Shopify's green color, the second one (for the logs) is blue. The third one, for successful JSON I chose green and where there is an error it it red. I changed the first green to not have 2 of the same color as headers.

Comment thread src/function_run_result.rs Outdated
writeln!(
f,
"{}\n\n{}",
" Invalid Output ".black().on_bright_red(),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any value in stating why the output is invalid (cannot be parsed as JSON)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a user, all I see is Invalid Output. How do I know why it is invalid?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. I'll add the Json parsing error to the logs section

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the output is nothing:
Screen Shot 2022-06-27 at 2 24 19 PM

When the output is something invalid:
Screen Shot 2022-06-27 at 2 28 01 PM

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible this could lead to confusion since we are mixing logs from the function and logs from function-runner?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is solved by adding the JSON deserialization error message. What else do you think would be good?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly. I find it a bit confusing that we are combining the function logs (STDERR) and errors that function-runner encountered (non-zero exit code, output that cannot be parsed to JSON). I wonder if we would benefit from taking a similar approach to what we have in partner's dashboard where logs (STDERR) and the errors we encounter are in separate sections. Just an idea; open to what others think.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'd be good to split them out to make it clear that you won't see the same error in production. I could imagine debugging this and thinking "Why am I getting a JSON deserialization error logged locally but not in production? What's logging that?"

Copy link
Copy Markdown
Contributor Author

@hainsdominic hainsdominic Jun 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Screen Shot 2022-06-27 at 5 30 33 PM

I splitted the Json error from the logs by tweaking the enum

Comment thread src/function_run_result.rs Outdated
Comment thread src/function_run_result.rs Outdated
Comment thread src/function_run_result.rs Outdated
Comment thread src/function_run_result.rs Outdated
Copy link
Copy Markdown
Contributor

@adampetro adampetro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎩👍

@hainsdominic hainsdominic merged commit 04b1825 into main Jun 28, 2022
@jbourassa jbourassa deleted the error-propagation branch November 16, 2023 18:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants