Skip to content

Commit

Permalink
Add context to funrun client errors (#23741)
Browse files Browse the repository at this point in the history
*

GitOrigin-RevId: 1486eb4f6429ed120a57c0ffd742e0cccd0fb202
  • Loading branch information
sshader authored and Convex, Inc. committed Mar 21, 2024
1 parent a35fa6c commit e575804
Showing 1 changed file with 51 additions and 1 deletion.
52 changes: 51 additions & 1 deletion crates/pb/src/error_metadata.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::fmt::Display;

use anyhow::Context;
use errors::{
ErrorCode,
Expand Down Expand Up @@ -79,11 +81,14 @@ impl TryFrom<ErrorMetadataProto> for ErrorMetadata {
pub trait ErrorMetadataStatusExt {
fn from_anyhow(error: anyhow::Error) -> Self;
fn into_anyhow(self) -> anyhow::Error;
fn context<C>(self, context: C) -> Self
where
C: Display + Send + Sync + 'static;
}

impl ErrorMetadataStatusExt for tonic::Status {
fn from_anyhow(error: anyhow::Error) -> Self {
let message = format!("{error}");
let message = format!("{error:#}");
if let Some(metadata) = error.downcast_ref::<ErrorMetadata>().cloned() {
let code: tonic::Code = metadata.code.grpc_status_code();
let details = StatusDetailsProto {
Expand Down Expand Up @@ -112,10 +117,22 @@ impl ErrorMetadataStatusExt for tonic::Status {
}
error
}

fn context<C>(self, context: C) -> Self
where
C: Display + Send + Sync + 'static,
{
let anyhow_err = self.into_anyhow();
Self::from_anyhow(anyhow_err.context(context))
}
}

#[cfg(test)]
mod tests {
use errors::{
ErrorMetadataAnyhowExt,
INTERNAL_SERVER_ERROR_MSG,
};
use proptest::prelude::*;
use value::testing::assert_roundtrips;

Expand Down Expand Up @@ -157,4 +174,37 @@ mod tests {
let error = status.into_anyhow();
assert!(error.downcast_ref::<ErrorMetadata>().is_none());
}

#[test]
fn test_context_no_error_metadata() {
let status =
tonic::Status::from_anyhow(anyhow::anyhow!("My special error")).context("Test context");

let error = status.into_anyhow();
// Check the error we log to sentry includes the original error and the context
let error_string = format!("{error:#}");
assert!(error_string.contains("My special error"));
assert!(error_string.contains("Test context"));

// Check that the user facing portions haven't changed
assert_eq!(error.user_facing_message(), INTERNAL_SERVER_ERROR_MSG);
}

#[test]
fn test_context_with_error_metadata() {
let status = tonic::Status::from_anyhow(
ErrorMetadata::overloaded("ShortMsg", "Test long message").into(),
)
.context("Test context");

let error = status.into_anyhow();
// Check the error we log to sentry includes the original error and the context
let error_string = format!("{error:#}");
assert!(error_string.contains("Test long message"));
assert!(error_string.contains("Test context"));

// Check that the user facing portions haven't changed
assert_eq!(error.user_facing_message(), "Test long message");
assert_eq!(error.short_msg(), "ShortMsg")
}
}

0 comments on commit e575804

Please sign in to comment.