mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-06-02 05:10:40 +00:00
refactor(error): remove backtrace, and introduce call-site location for debugging (#1329)
* wip: global replace Signed-off-by: Ruihang Xia <waynestxia@gmail.com> * fix compile Signed-off-by: Ruihang Xia <waynestxia@gmail.com> * fix warnings Signed-off-by: Ruihang Xia <waynestxia@gmail.com> * remove unneeded tests of errors Signed-off-by: Ruihang Xia <waynestxia@gmail.com> * fix ErrorExt trait implementator Signed-off-by: Ruihang Xia <waynestxia@gmail.com> * fix warnings Signed-off-by: Ruihang Xia <waynestxia@gmail.com> * fix format Signed-off-by: Ruihang Xia <waynestxia@gmail.com> * fix pyo3 tests Signed-off-by: Ruihang Xia <waynestxia@gmail.com> --------- Signed-off-by: Ruihang Xia <waynestxia@gmail.com>
This commit is contained in:
@@ -18,7 +18,7 @@ use std::io::{Read, Write};
|
||||
use bytes::{Buf, BufMut, BytesMut};
|
||||
use common_error::prelude::ErrorExt;
|
||||
use paste::paste;
|
||||
use snafu::{ensure, Backtrace, ErrorCompat, ResultExt, Snafu};
|
||||
use snafu::{ensure, Location, ResultExt, Snafu};
|
||||
|
||||
#[derive(Debug, Snafu)]
|
||||
#[snafu(visibility(pub))]
|
||||
@@ -31,29 +31,33 @@ pub enum Error {
|
||||
Overflow {
|
||||
src_len: usize,
|
||||
dst_len: usize,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Buffer underflow"))]
|
||||
Underflow { backtrace: Backtrace },
|
||||
Underflow { location: Location },
|
||||
|
||||
#[snafu(display("IO operation reach EOF, source: {}", source))]
|
||||
Eof {
|
||||
source: std::io::Error,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
impl ErrorExt for Error {
|
||||
fn backtrace_opt(&self) -> Option<&Backtrace> {
|
||||
ErrorCompat::backtrace(self)
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn location_opt(&self) -> Option<common_error::snafu::Location> {
|
||||
match self {
|
||||
Error::Overflow { location, .. } => Some(*location),
|
||||
Error::Underflow { location, .. } => Some(*location),
|
||||
Error::Eof { location, .. } => Some(*location),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_read_le {
|
||||
|
||||
@@ -16,29 +16,29 @@ use std::any::Any;
|
||||
|
||||
use common_error::ext::ErrorExt;
|
||||
use common_error::prelude::{Snafu, StatusCode};
|
||||
use snafu::{Backtrace, ErrorCompat};
|
||||
use snafu::Location;
|
||||
|
||||
#[derive(Debug, Snafu)]
|
||||
#[snafu(visibility(pub))]
|
||||
pub enum Error {
|
||||
#[snafu(display("Invalid catalog info: {}", key))]
|
||||
InvalidCatalog { key: String, backtrace: Backtrace },
|
||||
InvalidCatalog { key: String, location: Location },
|
||||
|
||||
#[snafu(display("Failed to deserialize catalog entry value: {}", raw))]
|
||||
DeserializeCatalogEntryValue {
|
||||
raw: String,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
source: serde_json::error::Error,
|
||||
},
|
||||
|
||||
#[snafu(display("Failed to serialize catalog entry value"))]
|
||||
SerializeCatalogEntryValue {
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
source: serde_json::error::Error,
|
||||
},
|
||||
|
||||
#[snafu(display("Failed to parse node id: {}", key))]
|
||||
ParseNodeId { key: String, backtrace: Backtrace },
|
||||
ParseNodeId { key: String, location: Location },
|
||||
}
|
||||
|
||||
impl ErrorExt for Error {
|
||||
@@ -51,10 +51,6 @@ impl ErrorExt for Error {
|
||||
}
|
||||
}
|
||||
|
||||
fn backtrace_opt(&self) -> Option<&Backtrace> {
|
||||
ErrorCompat::backtrace(self)
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
use std::any::Any;
|
||||
|
||||
use common_error::prelude::*;
|
||||
use snafu::Location;
|
||||
use url::ParseError;
|
||||
|
||||
#[derive(Debug, Snafu)]
|
||||
@@ -35,13 +36,13 @@ pub enum Error {
|
||||
#[snafu(display("Failed to build backend, source: {}", source))]
|
||||
BuildBackend {
|
||||
source: object_store::Error,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Failed to list object in path: {}, source: {}", path, source))]
|
||||
ListObjects {
|
||||
path: String,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
source: object_store::Error,
|
||||
},
|
||||
|
||||
@@ -65,11 +66,19 @@ impl ErrorExt for Error {
|
||||
}
|
||||
}
|
||||
|
||||
fn backtrace_opt(&self) -> Option<&Backtrace> {
|
||||
ErrorCompat::backtrace(self)
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn location_opt(&self) -> Option<common_error::snafu::Location> {
|
||||
match self {
|
||||
Error::BuildBackend { location, .. } => Some(*location),
|
||||
Error::ListObjects { location, .. } => Some(*location),
|
||||
Error::UnsupportedBackendProtocol { .. }
|
||||
| Error::EmptyHostPath { .. }
|
||||
| Error::InvalidPath { .. }
|
||||
| Error::InvalidUrl { .. }
|
||||
| Error::InvalidConnection { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,10 +23,12 @@ pub trait ErrorExt: std::error::Error {
|
||||
StatusCode::Unknown
|
||||
}
|
||||
|
||||
/// Get the reference to the backtrace of this error, None if the backtrace is unavailable.
|
||||
// Add `_opt` suffix to avoid confusing with similar method in `std::error::Error`, once backtrace
|
||||
// in std is stable, we can deprecate this method.
|
||||
fn backtrace_opt(&self) -> Option<&crate::snafu::Backtrace>;
|
||||
// TODO(ruihang): remove this default implementation
|
||||
/// Get the location of this error, None if the location is unavailable.
|
||||
/// Add `_opt` suffix to avoid confusing with similar method in `std::error::Error`
|
||||
fn location_opt(&self) -> Option<crate::snafu::Location> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns the error as [Any](std::any::Any) so that it can be
|
||||
/// downcast to a specific implementation.
|
||||
@@ -71,8 +73,8 @@ impl crate::ext::ErrorExt for BoxedError {
|
||||
self.inner.status_code()
|
||||
}
|
||||
|
||||
fn backtrace_opt(&self) -> Option<&crate::snafu::Backtrace> {
|
||||
self.inner.backtrace_opt()
|
||||
fn location_opt(&self) -> Option<crate::snafu::Location> {
|
||||
self.inner.location_opt()
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
@@ -84,7 +86,7 @@ impl crate::ext::ErrorExt for BoxedError {
|
||||
// via `ErrorCompat::backtrace()`.
|
||||
impl crate::snafu::ErrorCompat for BoxedError {
|
||||
fn backtrace(&self) -> Option<&crate::snafu::Backtrace> {
|
||||
self.inner.backtrace_opt()
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +120,7 @@ impl crate::ext::ErrorExt for PlainError {
|
||||
self.status_code
|
||||
}
|
||||
|
||||
fn backtrace_opt(&self) -> Option<&crate::snafu::Backtrace> {
|
||||
fn location_opt(&self) -> Option<crate::snafu::Location> {
|
||||
None
|
||||
}
|
||||
|
||||
@@ -126,62 +128,3 @@ impl crate::ext::ErrorExt for PlainError {
|
||||
self as _
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::error::Error;
|
||||
|
||||
use snafu::ErrorCompat;
|
||||
|
||||
use super::*;
|
||||
use crate::format::DebugFormat;
|
||||
use crate::mock::MockError;
|
||||
|
||||
#[test]
|
||||
fn test_opaque_error_without_backtrace() {
|
||||
let err = BoxedError::new(MockError::new(StatusCode::Internal));
|
||||
assert!(err.backtrace_opt().is_none());
|
||||
assert_eq!(StatusCode::Internal, err.status_code());
|
||||
assert!(err.as_any().downcast_ref::<MockError>().is_some());
|
||||
assert!(err.source().is_none());
|
||||
|
||||
assert!(ErrorCompat::backtrace(&err).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_opaque_error_with_backtrace() {
|
||||
let err = BoxedError::new(MockError::with_backtrace(StatusCode::Internal));
|
||||
assert!(err.backtrace_opt().is_some());
|
||||
assert_eq!(StatusCode::Internal, err.status_code());
|
||||
assert!(err.as_any().downcast_ref::<MockError>().is_some());
|
||||
assert!(err.source().is_none());
|
||||
|
||||
assert!(ErrorCompat::backtrace(&err).is_some());
|
||||
|
||||
let msg = format!("{err:?}");
|
||||
assert!(msg.contains("\nBacktrace:\n"));
|
||||
let fmt_msg = format!("{:?}", DebugFormat::new(&err));
|
||||
assert_eq!(msg, fmt_msg);
|
||||
|
||||
let msg = err.to_string();
|
||||
msg.contains("Internal");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_opaque_error_with_source() {
|
||||
let leaf_err = MockError::with_backtrace(StatusCode::Internal);
|
||||
let internal_err = MockError::with_source(leaf_err);
|
||||
let err = BoxedError::new(internal_err);
|
||||
|
||||
assert!(err.backtrace_opt().is_some());
|
||||
assert_eq!(StatusCode::Internal, err.status_code());
|
||||
assert!(err.as_any().downcast_ref::<MockError>().is_some());
|
||||
assert!(err.source().is_some());
|
||||
|
||||
let msg = format!("{err:?}");
|
||||
assert!(msg.contains("\nBacktrace:\n"));
|
||||
assert!(msg.contains("Caused by"));
|
||||
|
||||
assert!(ErrorCompat::backtrace(&err).is_some());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,9 +33,9 @@ impl<'a, E: ErrorExt + ?Sized> fmt::Debug for DebugFormat<'a, E> {
|
||||
// Source error use debug format for more verbose info.
|
||||
write!(f, " Caused by: {source:?}")?;
|
||||
}
|
||||
if let Some(backtrace) = self.0.backtrace_opt() {
|
||||
if let Some(location) = self.0.location_opt() {
|
||||
// Add a newline to separate causes and backtrace.
|
||||
write!(f, "\nBacktrace:\n{backtrace}")?;
|
||||
write!(f, " at: {location}")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -47,7 +47,7 @@ mod tests {
|
||||
use std::any::Any;
|
||||
|
||||
use snafu::prelude::*;
|
||||
use snafu::{Backtrace, GenerateImplicitData};
|
||||
use snafu::{GenerateImplicitData, Location};
|
||||
|
||||
use super::*;
|
||||
|
||||
@@ -56,7 +56,7 @@ mod tests {
|
||||
struct Leaf;
|
||||
|
||||
impl ErrorExt for Leaf {
|
||||
fn backtrace_opt(&self) -> Option<&Backtrace> {
|
||||
fn location_opt(&self) -> Option<Location> {
|
||||
None
|
||||
}
|
||||
|
||||
@@ -66,14 +66,14 @@ mod tests {
|
||||
}
|
||||
|
||||
#[derive(Debug, Snafu)]
|
||||
#[snafu(display("This is a leaf with backtrace"))]
|
||||
struct LeafWithBacktrace {
|
||||
backtrace: Backtrace,
|
||||
#[snafu(display("This is a leaf with location"))]
|
||||
struct LeafWithLocation {
|
||||
location: Location,
|
||||
}
|
||||
|
||||
impl ErrorExt for LeafWithBacktrace {
|
||||
fn backtrace_opt(&self) -> Option<&Backtrace> {
|
||||
Some(&self.backtrace)
|
||||
impl ErrorExt for LeafWithLocation {
|
||||
fn location_opt(&self) -> Option<Location> {
|
||||
None
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
@@ -86,12 +86,12 @@ mod tests {
|
||||
struct Internal {
|
||||
#[snafu(source)]
|
||||
source: Leaf,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
}
|
||||
|
||||
impl ErrorExt for Internal {
|
||||
fn backtrace_opt(&self) -> Option<&Backtrace> {
|
||||
Some(&self.backtrace)
|
||||
fn location_opt(&self) -> Option<Location> {
|
||||
None
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
@@ -106,19 +106,21 @@ mod tests {
|
||||
let msg = format!("{:?}", DebugFormat::new(&err));
|
||||
assert_eq!("This is a leaf error.", msg);
|
||||
|
||||
let err = LeafWithBacktrace {
|
||||
backtrace: Backtrace::generate(),
|
||||
let err = LeafWithLocation {
|
||||
location: Location::generate(),
|
||||
};
|
||||
|
||||
// TODO(ruihang): display location here
|
||||
let msg = format!("{:?}", DebugFormat::new(&err));
|
||||
assert!(msg.starts_with("This is a leaf with backtrace.\nBacktrace:\n"));
|
||||
assert!(msg.starts_with("This is a leaf with location."));
|
||||
|
||||
let err = Internal {
|
||||
source: Leaf,
|
||||
backtrace: Backtrace::generate(),
|
||||
location: Location::generate(),
|
||||
};
|
||||
|
||||
// TODO(ruihang): display location here
|
||||
let msg = format!("{:?}", DebugFormat::new(&err));
|
||||
assert!(msg.contains("Internal error. Caused by: Leaf\nBacktrace:\n"));
|
||||
assert!(msg.contains("Internal error. Caused by: Leaf"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
use std::any::Any;
|
||||
use std::fmt;
|
||||
|
||||
use snafu::GenerateImplicitData;
|
||||
use snafu::Location;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
@@ -25,34 +25,19 @@ use crate::prelude::*;
|
||||
#[derive(Debug)]
|
||||
pub struct MockError {
|
||||
pub code: StatusCode,
|
||||
backtrace: Option<Backtrace>,
|
||||
source: Option<Box<MockError>>,
|
||||
}
|
||||
|
||||
impl MockError {
|
||||
/// Create a new [MockError] without backtrace.
|
||||
pub fn new(code: StatusCode) -> MockError {
|
||||
MockError {
|
||||
code,
|
||||
backtrace: None,
|
||||
source: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new [MockError] with backtrace.
|
||||
pub fn with_backtrace(code: StatusCode) -> MockError {
|
||||
MockError {
|
||||
code,
|
||||
backtrace: Some(Backtrace::generate()),
|
||||
source: None,
|
||||
}
|
||||
MockError { code, source: None }
|
||||
}
|
||||
|
||||
/// Create a new [MockError] with source.
|
||||
pub fn with_source(source: MockError) -> MockError {
|
||||
MockError {
|
||||
code: source.code,
|
||||
backtrace: None,
|
||||
source: Some(Box::new(source)),
|
||||
}
|
||||
}
|
||||
@@ -75,39 +60,11 @@ impl ErrorExt for MockError {
|
||||
self.code
|
||||
}
|
||||
|
||||
fn backtrace_opt(&self) -> Option<&Backtrace> {
|
||||
self.backtrace
|
||||
.as_ref()
|
||||
.or_else(|| self.source.as_ref().and_then(|err| err.backtrace_opt()))
|
||||
fn location_opt(&self) -> Option<Location> {
|
||||
None
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl ErrorCompat for MockError {
|
||||
fn backtrace(&self) -> Option<&Backtrace> {
|
||||
self.backtrace_opt()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::error::Error;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_mock_error() {
|
||||
let err = MockError::new(StatusCode::Unknown);
|
||||
assert!(err.backtrace_opt().is_none());
|
||||
|
||||
let err = MockError::with_backtrace(StatusCode::Unknown);
|
||||
assert!(err.backtrace_opt().is_some());
|
||||
|
||||
let root_err = MockError::with_source(err);
|
||||
assert!(root_err.source().is_some());
|
||||
assert!(root_err.backtrace_opt().is_some());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ use std::any::Any;
|
||||
use api::DecodeError;
|
||||
use common_error::ext::ErrorExt;
|
||||
use common_error::prelude::{Snafu, StatusCode};
|
||||
use snafu::{Backtrace, ErrorCompat};
|
||||
use snafu::Location;
|
||||
|
||||
#[derive(Debug, Snafu)]
|
||||
#[snafu(visibility(pub))]
|
||||
@@ -32,7 +32,7 @@ pub enum Error {
|
||||
DecodeInsert { source: DecodeError },
|
||||
|
||||
#[snafu(display("Illegal insert data"))]
|
||||
IllegalInsertData { backtrace: Backtrace },
|
||||
IllegalInsertData { location: Location },
|
||||
|
||||
#[snafu(display("Column datatype error, source: {}", source))]
|
||||
ColumnDataType {
|
||||
@@ -48,17 +48,14 @@ pub enum Error {
|
||||
DuplicatedTimestampColumn {
|
||||
exists: String,
|
||||
duplicated: String,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Missing timestamp column, msg: {}", msg))]
|
||||
MissingTimestampColumn { msg: String, backtrace: Backtrace },
|
||||
MissingTimestampColumn { msg: String, location: Location },
|
||||
|
||||
#[snafu(display("Invalid column proto: {}", err_msg))]
|
||||
InvalidColumnProto {
|
||||
err_msg: String,
|
||||
backtrace: Backtrace,
|
||||
},
|
||||
InvalidColumnProto { err_msg: String, location: Location },
|
||||
#[snafu(display("Failed to create vector, source: {}", source))]
|
||||
CreateVector {
|
||||
#[snafu(backtrace)]
|
||||
@@ -66,7 +63,7 @@ pub enum Error {
|
||||
},
|
||||
|
||||
#[snafu(display("Missing required field in protobuf, field: {}", field))]
|
||||
MissingField { field: String, backtrace: Backtrace },
|
||||
MissingField { field: String, location: Location },
|
||||
|
||||
#[snafu(display("Invalid column default constraint, source: {}", source))]
|
||||
ColumnDefaultConstraint {
|
||||
@@ -113,9 +110,6 @@ impl ErrorExt for Error {
|
||||
Error::UnrecognizedTableOption { .. } => StatusCode::InvalidArguments,
|
||||
}
|
||||
}
|
||||
fn backtrace_opt(&self) -> Option<&Backtrace> {
|
||||
ErrorCompat::backtrace(self)
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
|
||||
@@ -16,7 +16,7 @@ use std::any::Any;
|
||||
use std::io;
|
||||
|
||||
use common_error::prelude::{ErrorExt, StatusCode};
|
||||
use snafu::{Backtrace, ErrorCompat, Snafu};
|
||||
use snafu::{Location, Snafu};
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
@@ -29,11 +29,11 @@ pub enum Error {
|
||||
#[snafu(display("Invalid config file path, {}", source))]
|
||||
InvalidConfigFilePath {
|
||||
source: io::Error,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Missing required field in protobuf, field: {}", field))]
|
||||
MissingField { field: String, backtrace: Backtrace },
|
||||
MissingField { field: String, location: Location },
|
||||
|
||||
#[snafu(display(
|
||||
"Write type mismatch, column name: {}, expected: {}, actual: {}",
|
||||
@@ -45,13 +45,13 @@ pub enum Error {
|
||||
column_name: String,
|
||||
expected: String,
|
||||
actual: String,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Failed to create gRPC channel, source: {}", source))]
|
||||
CreateChannel {
|
||||
source: tonic::transport::Error,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Failed to create RecordBatch, source: {}", source))]
|
||||
@@ -61,7 +61,7 @@ pub enum Error {
|
||||
},
|
||||
|
||||
#[snafu(display("Failed to convert Arrow type: {}", from))]
|
||||
Conversion { from: String, backtrace: Backtrace },
|
||||
Conversion { from: String, location: Location },
|
||||
|
||||
#[snafu(display("Column datatype error, source: {}", source))]
|
||||
ColumnDataType {
|
||||
@@ -72,14 +72,11 @@ pub enum Error {
|
||||
#[snafu(display("Failed to decode FlightData, source: {}", source))]
|
||||
DecodeFlightData {
|
||||
source: api::DecodeError,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Invalid FlightData, reason: {}", reason))]
|
||||
InvalidFlightData {
|
||||
reason: String,
|
||||
backtrace: Backtrace,
|
||||
},
|
||||
InvalidFlightData { reason: String, location: Location },
|
||||
|
||||
#[snafu(display("Failed to convert Arrow Schema, source: {}", source))]
|
||||
ConvertArrowSchema {
|
||||
@@ -107,65 +104,7 @@ impl ErrorExt for Error {
|
||||
}
|
||||
}
|
||||
|
||||
fn backtrace_opt(&self) -> Option<&Backtrace> {
|
||||
ErrorCompat::backtrace(self)
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use snafu::{OptionExt, ResultExt};
|
||||
|
||||
use super::*;
|
||||
|
||||
type StdResult<E> = std::result::Result<(), E>;
|
||||
|
||||
fn throw_none_option() -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_field_error() {
|
||||
let e = throw_none_option()
|
||||
.context(MissingFieldSnafu { field: "test" })
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
assert!(e.backtrace_opt().is_some());
|
||||
assert_eq!(e.status_code(), StatusCode::InvalidArguments);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_type_mismatch_error() {
|
||||
let e = throw_none_option()
|
||||
.context(TypeMismatchSnafu {
|
||||
column_name: "",
|
||||
expected: "",
|
||||
actual: "",
|
||||
})
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
assert!(e.backtrace_opt().is_some());
|
||||
assert_eq!(e.status_code(), StatusCode::InvalidArguments);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_channel_error() {
|
||||
fn throw_tonic_error() -> StdResult<tonic::transport::Error> {
|
||||
tonic::transport::Endpoint::new("http//http").map(|_| ())
|
||||
}
|
||||
|
||||
let e = throw_tonic_error()
|
||||
.context(CreateChannelSnafu)
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
assert!(e.backtrace_opt().is_some());
|
||||
assert_eq!(e.status_code(), StatusCode::Internal);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ use std::any::Any;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use common_error::prelude::{ErrorExt, StatusCode};
|
||||
use snafu::{Backtrace, Snafu};
|
||||
use snafu::{Location, Snafu};
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
@@ -30,7 +30,7 @@ pub enum Error {
|
||||
ProfilingNotEnabled,
|
||||
|
||||
#[snafu(display("Failed to build temp file from given path: {:?}", path))]
|
||||
BuildTempPath { path: PathBuf, backtrace: Backtrace },
|
||||
BuildTempPath { path: PathBuf, location: Location },
|
||||
|
||||
#[snafu(display("Failed to open temp file: {}", path))]
|
||||
OpenTempFile {
|
||||
@@ -56,10 +56,6 @@ impl ErrorExt for Error {
|
||||
}
|
||||
}
|
||||
|
||||
fn backtrace_opt(&self) -> Option<&Backtrace> {
|
||||
snafu::ErrorCompat::backtrace(self)
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ use std::string::FromUtf8Error;
|
||||
use std::sync::Arc;
|
||||
|
||||
use common_error::prelude::*;
|
||||
use snafu::Location;
|
||||
|
||||
use crate::procedure::ProcedureId;
|
||||
|
||||
@@ -34,18 +35,18 @@ pub enum Error {
|
||||
},
|
||||
|
||||
#[snafu(display("Loader {} is already registered", name))]
|
||||
LoaderConflict { name: String, backtrace: Backtrace },
|
||||
LoaderConflict { name: String, location: Location },
|
||||
|
||||
#[snafu(display("Failed to serialize to json, source: {}", source))]
|
||||
ToJson {
|
||||
source: serde_json::Error,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Procedure {} already exists", procedure_id))]
|
||||
DuplicateProcedure {
|
||||
procedure_id: ProcedureId,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Failed to put state, key: '{key}', source: {source}"))]
|
||||
@@ -84,7 +85,7 @@ pub enum Error {
|
||||
#[snafu(display("Failed to deserialize from json, source: {}", source))]
|
||||
FromJson {
|
||||
source: serde_json::Error,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Procedure exec failed, source: {}", source))]
|
||||
@@ -99,13 +100,13 @@ pub enum Error {
|
||||
#[snafu(display("Failed to wait watcher, source: {}", source))]
|
||||
WaitWatcher {
|
||||
source: tokio::sync::watch::error::RecvError,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Failed to execute procedure, source: {}", source))]
|
||||
ProcedureExec {
|
||||
source: Arc<Error>,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display(
|
||||
@@ -147,10 +148,6 @@ impl ErrorExt for Error {
|
||||
}
|
||||
}
|
||||
|
||||
fn backtrace_opt(&self) -> Option<&Backtrace> {
|
||||
ErrorCompat::backtrace(self)
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ use datatypes::arrow;
|
||||
use datatypes::arrow::datatypes::DataType as ArrowDatatype;
|
||||
use datatypes::error::Error as DataTypeError;
|
||||
use datatypes::prelude::ConcreteDataType;
|
||||
use snafu::Location;
|
||||
use statrs::StatsError;
|
||||
|
||||
#[derive(Debug, Snafu)]
|
||||
@@ -31,7 +32,7 @@ pub enum Error {
|
||||
PyUdf {
|
||||
// TODO(discord9): find a way that prevent circle depend(query<-script<-query) and can use script's error type
|
||||
msg: String,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display(
|
||||
@@ -46,20 +47,20 @@ pub enum Error {
|
||||
#[snafu(display("Fail to execute function, source: {}", source))]
|
||||
ExecuteFunction {
|
||||
source: DataFusionError,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Unsupported input datatypes {:?} in function {}", datatypes, function))]
|
||||
UnsupportedInputDataType {
|
||||
function: String,
|
||||
datatypes: Vec<ConcreteDataType>,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Fail to generate function, source: {}", source))]
|
||||
GenerateFunction {
|
||||
source: StatsError,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Fail to cast scalar value into vector: {}", source))]
|
||||
@@ -88,10 +89,7 @@ pub enum Error {
|
||||
DowncastVector { err_msg: String },
|
||||
|
||||
#[snafu(display("Bad accumulator implementation: {}", err_msg))]
|
||||
BadAccumulatorImpl {
|
||||
err_msg: String,
|
||||
backtrace: Backtrace,
|
||||
},
|
||||
BadAccumulatorImpl { err_msg: String, location: Location },
|
||||
|
||||
#[snafu(display("Invalid input type: {}", err_msg))]
|
||||
InvalidInputType {
|
||||
@@ -103,24 +101,24 @@ pub enum Error {
|
||||
#[snafu(display(
|
||||
"Illegal input_types status, check if DataFusion has changed its UDAF execution logic"
|
||||
))]
|
||||
InvalidInputState { backtrace: Backtrace },
|
||||
InvalidInputState { location: Location },
|
||||
|
||||
#[snafu(display("unexpected: not constant column"))]
|
||||
InvalidInputCol { backtrace: Backtrace },
|
||||
InvalidInputCol { location: Location },
|
||||
|
||||
#[snafu(display("Not expected to run ExecutionPlan more than once"))]
|
||||
ExecuteRepeatedly { backtrace: Backtrace },
|
||||
ExecuteRepeatedly { location: Location },
|
||||
|
||||
#[snafu(display("General DataFusion error, source: {}", source))]
|
||||
GeneralDataFusion {
|
||||
source: DataFusionError,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Failed to execute DataFusion ExecutionPlan, source: {}", source))]
|
||||
DataFusionExecutionPlan {
|
||||
source: DataFusionError,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display(
|
||||
@@ -148,7 +146,7 @@ pub enum Error {
|
||||
TypeCast {
|
||||
source: ArrowError,
|
||||
typ: arrow::datatypes::DataType,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display(
|
||||
@@ -157,7 +155,7 @@ pub enum Error {
|
||||
))]
|
||||
ArrowCompute {
|
||||
source: ArrowError,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Query engine fail to cast value: {}", source))]
|
||||
@@ -173,10 +171,7 @@ pub enum Error {
|
||||
},
|
||||
|
||||
#[snafu(display("Invalid function args: {}", err_msg))]
|
||||
InvalidFuncArgs {
|
||||
err_msg: String,
|
||||
backtrace: Backtrace,
|
||||
},
|
||||
InvalidFuncArgs { err_msg: String, location: Location },
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
@@ -216,10 +211,6 @@ impl ErrorExt for Error {
|
||||
}
|
||||
}
|
||||
|
||||
fn backtrace_opt(&self) -> Option<&Backtrace> {
|
||||
ErrorCompat::backtrace(self)
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
@@ -236,83 +227,3 @@ impl From<BoxedError> for Error {
|
||||
Error::ExecutePhysicalPlan { source }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use snafu::GenerateImplicitData;
|
||||
|
||||
use super::*;
|
||||
|
||||
fn throw_df_error() -> std::result::Result<(), DataFusionError> {
|
||||
Err(DataFusionError::NotImplemented("test".to_string()))
|
||||
}
|
||||
|
||||
fn assert_error(err: &Error, code: StatusCode) {
|
||||
let inner_err = err.as_any().downcast_ref::<Error>().unwrap();
|
||||
assert_eq!(code, inner_err.status_code());
|
||||
assert!(inner_err.backtrace_opt().is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_datafusion_as_source() {
|
||||
let err = throw_df_error()
|
||||
.context(ExecuteFunctionSnafu)
|
||||
.err()
|
||||
.unwrap();
|
||||
assert_error(&err, StatusCode::EngineExecuteQuery);
|
||||
|
||||
let err: Error = throw_df_error()
|
||||
.context(GeneralDataFusionSnafu)
|
||||
.err()
|
||||
.unwrap();
|
||||
assert_error(&err, StatusCode::Unexpected);
|
||||
|
||||
let err = throw_df_error()
|
||||
.context(DataFusionExecutionPlanSnafu)
|
||||
.err()
|
||||
.unwrap();
|
||||
assert_error(&err, StatusCode::Unexpected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_execute_repeatedly_error() {
|
||||
let error = None::<i32>.context(ExecuteRepeatedlySnafu).err().unwrap();
|
||||
assert_eq!(error.status_code(), StatusCode::Unexpected);
|
||||
assert!(error.backtrace_opt().is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_convert_df_recordbatch_stream_error() {
|
||||
let result: std::result::Result<i32, common_recordbatch::error::Error> =
|
||||
Err(common_recordbatch::error::Error::PollStream {
|
||||
source: DataFusionError::Internal("blabla".to_string()),
|
||||
backtrace: Backtrace::generate(),
|
||||
});
|
||||
let error = result
|
||||
.context(ConvertDfRecordBatchStreamSnafu)
|
||||
.err()
|
||||
.unwrap();
|
||||
assert_eq!(error.status_code(), StatusCode::Internal);
|
||||
assert!(error.backtrace_opt().is_some());
|
||||
}
|
||||
|
||||
fn raise_datatype_error() -> std::result::Result<(), DataTypeError> {
|
||||
Err(DataTypeError::Conversion {
|
||||
from: "test".to_string(),
|
||||
backtrace: Backtrace::generate(),
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_vector_error() {
|
||||
let err = raise_datatype_error()
|
||||
.context(IntoVectorSnafu {
|
||||
data_type: ArrowDatatype::Int32,
|
||||
})
|
||||
.err()
|
||||
.unwrap();
|
||||
assert!(err.backtrace_opt().is_some());
|
||||
let datatype_err = raise_datatype_error().err().unwrap();
|
||||
assert_eq!(datatype_err.status_code(), err.status_code());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ use std::any::Any;
|
||||
use common_error::ext::BoxedError;
|
||||
use common_error::prelude::*;
|
||||
use datatypes::prelude::ConcreteDataType;
|
||||
use snafu::Location;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
@@ -27,7 +28,7 @@ pub enum Error {
|
||||
#[snafu(display("Fail to create datafusion record batch, source: {}", source))]
|
||||
NewDfRecordBatch {
|
||||
source: datatypes::arrow::error::ArrowError,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Data types error, source: {}", source))]
|
||||
@@ -43,40 +44,37 @@ pub enum Error {
|
||||
},
|
||||
|
||||
#[snafu(display("Failed to create RecordBatches, reason: {}", reason))]
|
||||
CreateRecordBatches {
|
||||
reason: String,
|
||||
backtrace: Backtrace,
|
||||
},
|
||||
CreateRecordBatches { reason: String, location: Location },
|
||||
|
||||
#[snafu(display("Failed to convert Arrow schema, source: {}", source))]
|
||||
SchemaConversion {
|
||||
source: datatypes::error::Error,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Failed to poll stream, source: {}", source))]
|
||||
PollStream {
|
||||
source: datafusion::error::DataFusionError,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Fail to format record batch, source: {}", source))]
|
||||
Format {
|
||||
source: datatypes::arrow::error::ArrowError,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Failed to init Recordbatch stream, source: {}", source))]
|
||||
InitRecordbatchStream {
|
||||
source: datafusion_common::DataFusionError,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Column {} not exists in table {}", column_name, table_name))]
|
||||
ColumnNotExists {
|
||||
column_name: String,
|
||||
table_name: String,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display(
|
||||
@@ -113,10 +111,6 @@ impl ErrorExt for Error {
|
||||
}
|
||||
}
|
||||
|
||||
fn backtrace_opt(&self) -> Option<&Backtrace> {
|
||||
ErrorCompat::backtrace(self)
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
use std::any::Any;
|
||||
|
||||
use common_error::prelude::*;
|
||||
use snafu::Location;
|
||||
use tokio::task::JoinError;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
@@ -25,10 +26,10 @@ pub enum Error {
|
||||
#[snafu(display("Failed to build runtime, source: {}", source))]
|
||||
BuildRuntime {
|
||||
source: std::io::Error,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
#[snafu(display("Repeated task {} not started yet", name))]
|
||||
IllegalState { name: String, backtrace: Backtrace },
|
||||
IllegalState { name: String, location: Location },
|
||||
|
||||
#[snafu(display(
|
||||
"Failed to wait for repeated task {} to stop, source: {}",
|
||||
@@ -38,16 +39,20 @@ pub enum Error {
|
||||
WaitGcTaskStop {
|
||||
name: String,
|
||||
source: JoinError,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
}
|
||||
|
||||
impl ErrorExt for Error {
|
||||
fn backtrace_opt(&self) -> Option<&Backtrace> {
|
||||
ErrorCompat::backtrace(self)
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn location_opt(&self) -> Option<common_error::snafu::Location> {
|
||||
match self {
|
||||
Error::BuildRuntime { location, .. }
|
||||
| Error::IllegalState { location, .. }
|
||||
| Error::WaitGcTaskStop { location, .. } => Some(*location),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,61 +18,58 @@ use common_error::prelude::{BoxedError, ErrorExt, StatusCode};
|
||||
use datafusion::error::DataFusionError;
|
||||
use datatypes::prelude::ConcreteDataType;
|
||||
use prost::{DecodeError, EncodeError};
|
||||
use snafu::{Backtrace, ErrorCompat, Snafu};
|
||||
use snafu::{Location, Snafu};
|
||||
|
||||
#[derive(Debug, Snafu)]
|
||||
#[snafu(visibility(pub))]
|
||||
pub enum Error {
|
||||
#[snafu(display("Unsupported physical plan: {}", name))]
|
||||
UnsupportedPlan { name: String, backtrace: Backtrace },
|
||||
UnsupportedPlan { name: String, location: Location },
|
||||
|
||||
#[snafu(display("Unsupported expr: {}", name))]
|
||||
UnsupportedExpr { name: String, backtrace: Backtrace },
|
||||
UnsupportedExpr { name: String, location: Location },
|
||||
|
||||
#[snafu(display("Unsupported concrete type: {:?}", ty))]
|
||||
UnsupportedConcreteType {
|
||||
ty: ConcreteDataType,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Unsupported substrait type: {}", ty))]
|
||||
UnsupportedSubstraitType { ty: String, backtrace: Backtrace },
|
||||
UnsupportedSubstraitType { ty: String, location: Location },
|
||||
|
||||
#[snafu(display("Failed to decode substrait relation, source: {}", source))]
|
||||
DecodeRel {
|
||||
source: DecodeError,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Failed to encode substrait relation, source: {}", source))]
|
||||
EncodeRel {
|
||||
source: EncodeError,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Input plan is empty"))]
|
||||
EmptyPlan { backtrace: Backtrace },
|
||||
EmptyPlan { location: Location },
|
||||
|
||||
#[snafu(display("Input expression is empty"))]
|
||||
EmptyExpr { backtrace: Backtrace },
|
||||
EmptyExpr { location: Location },
|
||||
|
||||
#[snafu(display("Missing required field in protobuf, field: {}, plan: {}", field, plan))]
|
||||
MissingField {
|
||||
field: String,
|
||||
plan: String,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Invalid parameters: {}", reason))]
|
||||
InvalidParameters {
|
||||
reason: String,
|
||||
backtrace: Backtrace,
|
||||
},
|
||||
InvalidParameters { reason: String, location: Location },
|
||||
|
||||
#[snafu(display("Internal error from DataFusion: {}", source))]
|
||||
DFInternal {
|
||||
source: DataFusionError,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Internal error: {}", source))]
|
||||
@@ -82,10 +79,10 @@ pub enum Error {
|
||||
},
|
||||
|
||||
#[snafu(display("Table querying not found: {}", name))]
|
||||
TableNotFound { name: String, backtrace: Backtrace },
|
||||
TableNotFound { name: String, location: Location },
|
||||
|
||||
#[snafu(display("Cannot convert plan doesn't belong to GreptimeDB"))]
|
||||
UnknownPlan { backtrace: Backtrace },
|
||||
UnknownPlan { location: Location },
|
||||
|
||||
#[snafu(display(
|
||||
"Schema from Substrait proto doesn't match with the schema in storage.
|
||||
@@ -97,7 +94,7 @@ pub enum Error {
|
||||
SchemaNotMatch {
|
||||
substrait_schema: datafusion::arrow::datatypes::SchemaRef,
|
||||
storage_schema: datafusion::arrow::datatypes::SchemaRef,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Failed to convert DataFusion schema, source: {}", source))]
|
||||
@@ -138,10 +135,6 @@ impl ErrorExt for Error {
|
||||
}
|
||||
}
|
||||
|
||||
fn backtrace_opt(&self) -> Option<&Backtrace> {
|
||||
ErrorCompat::backtrace(self)
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -38,15 +38,15 @@ macro_rules! error {
|
||||
($e:expr; target: $target:expr, $($arg:tt)+) => ({
|
||||
use $crate::common_error::ext::ErrorExt;
|
||||
use std::error::Error;
|
||||
match ($e.source(), $e.backtrace_opt()) {
|
||||
(Some(source), Some(backtrace)) => {
|
||||
match ($e.source(), $e.location_opt()) {
|
||||
(Some(source), Some(location)) => {
|
||||
$crate::log!(
|
||||
target: $target,
|
||||
$crate::logging::Level::ERROR,
|
||||
err.msg = %$e,
|
||||
err.code = %$e.status_code(),
|
||||
err.source = source,
|
||||
err.backtrace = %backtrace,
|
||||
err.location = %location,
|
||||
$($arg)+
|
||||
)
|
||||
},
|
||||
@@ -60,13 +60,13 @@ macro_rules! error {
|
||||
$($arg)+
|
||||
)
|
||||
},
|
||||
(None, Some(backtrace)) => {
|
||||
(None, Some(location)) => {
|
||||
$crate::log!(
|
||||
target: $target,
|
||||
$crate::logging::Level::ERROR,
|
||||
err.msg = %$e,
|
||||
err.code = %$e.status_code(),
|
||||
err.backtrace = %backtrace,
|
||||
err.location = %location,
|
||||
$($arg)+
|
||||
)
|
||||
},
|
||||
@@ -86,14 +86,14 @@ macro_rules! error {
|
||||
($e:expr; $($arg:tt)+) => ({
|
||||
use std::error::Error;
|
||||
use $crate::common_error::ext::ErrorExt;
|
||||
match ($e.source(), $e.backtrace_opt()) {
|
||||
(Some(source), Some(backtrace)) => {
|
||||
match ($e.source(), $e.location_opt()) {
|
||||
(Some(source), Some(location)) => {
|
||||
$crate::log!(
|
||||
$crate::logging::Level::ERROR,
|
||||
err.msg = %$e,
|
||||
err.code = %$e.status_code(),
|
||||
err.source = source,
|
||||
err.backtrace = %backtrace,
|
||||
err.location = %location,
|
||||
$($arg)+
|
||||
)
|
||||
},
|
||||
@@ -106,12 +106,12 @@ macro_rules! error {
|
||||
$($arg)+
|
||||
)
|
||||
},
|
||||
(None, Some(backtrace)) => {
|
||||
(None, Some(location)) => {
|
||||
$crate::log!(
|
||||
$crate::logging::Level::ERROR,
|
||||
err.msg = %$e,
|
||||
err.code = %$e.status_code(),
|
||||
err.backtrace = %backtrace,
|
||||
err.location = %location,
|
||||
$($arg)+
|
||||
)
|
||||
},
|
||||
@@ -263,9 +263,6 @@ mod tests {
|
||||
error!(err_ref2; "hello {}", "world");
|
||||
error!("hello {}", "world");
|
||||
|
||||
let err = MockError::with_backtrace(StatusCode::Internal);
|
||||
error!(err; "Error with backtrace hello {}", "world");
|
||||
|
||||
let root_err = MockError::with_source(err);
|
||||
error!(root_err; "Error with source hello {}", "world");
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ use std::num::TryFromIntError;
|
||||
use chrono::ParseError;
|
||||
use common_error::ext::ErrorExt;
|
||||
use common_error::prelude::StatusCode;
|
||||
use snafu::{Backtrace, ErrorCompat, Snafu};
|
||||
use snafu::{Location, Snafu};
|
||||
|
||||
#[derive(Debug, Snafu)]
|
||||
#[snafu(visibility(pub))]
|
||||
@@ -27,16 +27,16 @@ pub enum Error {
|
||||
ParseDateStr { raw: String, source: ParseError },
|
||||
|
||||
#[snafu(display("Failed to parse a string into Timestamp, raw string: {}", raw))]
|
||||
ParseTimestamp { raw: String, backtrace: Backtrace },
|
||||
ParseTimestamp { raw: String, location: Location },
|
||||
|
||||
#[snafu(display("Current timestamp overflow, source: {}", source))]
|
||||
TimestampOverflow {
|
||||
source: TryFromIntError,
|
||||
backtrace: Backtrace,
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Timestamp arithmetic overflow, msg: {}", msg))]
|
||||
ArithmeticOverflow { msg: String, backtrace: Backtrace },
|
||||
ArithmeticOverflow { msg: String, location: Location },
|
||||
}
|
||||
|
||||
impl ErrorExt for Error {
|
||||
@@ -50,33 +50,18 @@ impl ErrorExt for Error {
|
||||
}
|
||||
}
|
||||
|
||||
fn backtrace_opt(&self) -> Option<&Backtrace> {
|
||||
ErrorCompat::backtrace(self)
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn location_opt(&self) -> Option<common_error::snafu::Location> {
|
||||
match self {
|
||||
Error::ParseTimestamp { location, .. }
|
||||
| Error::TimestampOverflow { location, .. }
|
||||
| Error::ArithmeticOverflow { location, .. } => Some(*location),
|
||||
Error::ParseDateStr { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use chrono::NaiveDateTime;
|
||||
use snafu::ResultExt;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_errors() {
|
||||
let raw = "2020-09-08T13:42:29.190855Z";
|
||||
let result = NaiveDateTime::parse_from_str(raw, "%F").context(ParseDateStrSnafu { raw });
|
||||
assert!(matches!(result.err().unwrap(), Error::ParseDateStr { .. }));
|
||||
|
||||
assert_eq!(
|
||||
"Failed to parse a string into Timestamp, raw string: 2020-09-08T13:42:29.190855Z",
|
||||
ParseTimestampSnafu { raw }.build().to_string()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user