This is an automated email from the ASF dual-hosted git repository.
xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-opendal.git
The following commit(s) were added to refs/heads/main by this push:
new 64ddcb6ec refactor: Implement backtrace for Error correctly (#2871)
64ddcb6ec is described below
commit 64ddcb6ecc37edcbb69297f5d82460e6b3aa1f9d
Author: Xuanwo <[email protected]>
AuthorDate: Wed Aug 16 15:25:38 2023 +0800
refactor: Implement backtrace for Error correctly (#2871)
Signed-off-by: Xuanwo <[email protected]>
---
bin/oay/src/services/webdav/webdav_dir_entry.rs | 6 +-
bin/oay/src/services/webdav/webdav_metadata.rs | 3 +-
bin/oay/src/services/webdav/webdavfs.rs | 9 +--
bindings/haskell/src/logger.rs | 3 +-
bindings/ocaml/src/lib.rs | 6 +-
bindings/php/src/lib.rs | 5 +-
core/fuzz/fuzz_reader.rs | 7 +-
core/fuzz/fuzz_writer.rs | 8 +--
core/src/layers/blocking.rs | 3 +-
core/src/services/postgresql/backend.rs | 17 +++--
core/src/types/entry.rs | 6 +-
core/src/types/error.rs | 87 +++++++++++++++++++++++--
core/src/types/operator/blocking_operator.rs | 14 ++--
core/tests/behavior/blocking_write.rs | 3 +-
14 files changed, 130 insertions(+), 47 deletions(-)
diff --git a/bin/oay/src/services/webdav/webdav_dir_entry.rs
b/bin/oay/src/services/webdav/webdav_dir_entry.rs
index 80bd5ed43..b3e4f6f11 100644
--- a/bin/oay/src/services/webdav/webdav_dir_entry.rs
+++ b/bin/oay/src/services/webdav/webdav_dir_entry.rs
@@ -15,9 +15,11 @@
// specific language governing permissions and limitations
// under the License.
-use dav_server::fs::{DavDirEntry, DavMetaData};
+use dav_server::fs::DavDirEntry;
+use dav_server::fs::DavMetaData;
use futures::FutureExt;
-use opendal::{Entry, Operator};
+use opendal::Entry;
+use opendal::Operator;
use super::webdav_metadata::WebdavMetaData;
diff --git a/bin/oay/src/services/webdav/webdav_metadata.rs
b/bin/oay/src/services/webdav/webdav_metadata.rs
index a473b3d76..03295125d 100644
--- a/bin/oay/src/services/webdav/webdav_metadata.rs
+++ b/bin/oay/src/services/webdav/webdav_metadata.rs
@@ -15,7 +15,8 @@
// specific language governing permissions and limitations
// under the License.
-use dav_server::fs::{DavMetaData, FsError};
+use dav_server::fs::DavMetaData;
+use dav_server::fs::FsError;
use opendal::Metadata;
#[derive(Debug, Clone)]
diff --git a/bin/oay/src/services/webdav/webdavfs.rs
b/bin/oay/src/services/webdav/webdavfs.rs
index 0a974dfd9..3ec86343a 100644
--- a/bin/oay/src/services/webdav/webdavfs.rs
+++ b/bin/oay/src/services/webdav/webdavfs.rs
@@ -17,7 +17,8 @@
use std::path::Path;
use std::pin::Pin;
-use std::task::Poll::{Pending, Ready};
+use std::task::Poll::Pending;
+use std::task::Poll::Ready;
use dav_server::davpath::DavPath;
use dav_server::fs::DavDirEntry;
@@ -30,10 +31,10 @@ use futures_util::StreamExt;
use opendal::Lister;
use opendal::Operator;
-use crate::services::webdav::webdav_dir_entry::WebDAVDirEntry;
-
-use super::webdav_file::{convert_error, WebdavFile};
+use super::webdav_file::convert_error;
+use super::webdav_file::WebdavFile;
use super::webdav_metadata::WebdavMetaData;
+use crate::services::webdav::webdav_dir_entry::WebDAVDirEntry;
#[derive(Clone)]
pub struct WebdavFs {
diff --git a/bindings/haskell/src/logger.rs b/bindings/haskell/src/logger.rs
index 1ffa84c6c..ebb34f155 100644
--- a/bindings/haskell/src/logger.rs
+++ b/bindings/haskell/src/logger.rs
@@ -15,7 +15,8 @@
// specific language governing permissions and limitations
// under the License.
-use std::ffi::{c_char, CString};
+use std::ffi::c_char;
+use std::ffi::CString;
pub struct HsLogger {
pub callback: extern "C" fn(u32, *const c_char),
diff --git a/bindings/ocaml/src/lib.rs b/bindings/ocaml/src/lib.rs
index 4a6d1533c..f6ec3f2b8 100644
--- a/bindings/ocaml/src/lib.rs
+++ b/bindings/ocaml/src/lib.rs
@@ -15,10 +15,12 @@
// specific language governing permissions and limitations
// under the License.
-use ::opendal as od;
-use std::collections::{BTreeMap, HashMap};
+use std::collections::BTreeMap;
+use std::collections::HashMap;
use std::str::FromStr;
+use ::opendal as od;
+
mod operator;
pub fn new_operator(
diff --git a/bindings/php/src/lib.rs b/bindings/php/src/lib.rs
index dbb85a8e6..2e5166935 100644
--- a/bindings/php/src/lib.rs
+++ b/bindings/php/src/lib.rs
@@ -15,6 +15,9 @@
// specific language governing permissions and limitations
// under the License.
+use std::collections::HashMap;
+use std::str::FromStr;
+
use ::opendal as od;
use ext_php_rs::binary::Binary;
use ext_php_rs::convert::FromZval;
@@ -22,8 +25,6 @@ use ext_php_rs::exception::PhpException;
use ext_php_rs::flags::DataType;
use ext_php_rs::prelude::*;
use ext_php_rs::types::Zval;
-use std::collections::HashMap;
-use std::str::FromStr;
#[php_class(name = "OpenDAL\\Operator")]
pub struct Operator(od::BlockingOperator);
diff --git a/core/fuzz/fuzz_reader.rs b/core/fuzz/fuzz_reader.rs
index 4cd8a68ff..25b9db37e 100644
--- a/core/fuzz/fuzz_reader.rs
+++ b/core/fuzz/fuzz_reader.rs
@@ -23,14 +23,13 @@ use bytes::Bytes;
use libfuzzer_sys::arbitrary::Arbitrary;
use libfuzzer_sys::arbitrary::Unstructured;
use libfuzzer_sys::fuzz_target;
-use rand::prelude::*;
-use sha2::Digest;
-use sha2::Sha256;
-
use opendal::raw::oio::ReadExt;
use opendal::raw::BytesRange;
use opendal::Operator;
use opendal::Result;
+use rand::prelude::*;
+use sha2::Digest;
+use sha2::Sha256;
mod utils;
diff --git a/core/fuzz/fuzz_writer.rs b/core/fuzz/fuzz_writer.rs
index 63c3ebb3a..4c2151035 100644
--- a/core/fuzz/fuzz_writer.rs
+++ b/core/fuzz/fuzz_writer.rs
@@ -17,17 +17,17 @@
#![no_main]
-use bytes::{Bytes, BytesMut};
+use bytes::Bytes;
+use bytes::BytesMut;
use libfuzzer_sys::arbitrary::Arbitrary;
use libfuzzer_sys::arbitrary::Unstructured;
use libfuzzer_sys::fuzz_target;
+use opendal::Operator;
+use opendal::Result;
use rand::prelude::*;
use sha2::Digest;
use sha2::Sha256;
-use opendal::Operator;
-use opendal::Result;
-
mod utils;
const MAX_DATA_SIZE: usize = 16 * 1024 * 1024;
diff --git a/core/src/layers/blocking.rs b/core/src/layers/blocking.rs
index a9f8e0df4..c6fe23bb9 100644
--- a/core/src/layers/blocking.rs
+++ b/core/src/layers/blocking.rs
@@ -221,9 +221,8 @@ impl<I: oio::Page> oio::BlockingPage for BlockingWrapper<I>
{
mod tests {
use once_cell::sync::Lazy;
- use crate::types::Result;
-
use super::*;
+ use crate::types::Result;
static RUNTIME: Lazy<tokio::runtime::Runtime> = Lazy::new(|| {
tokio::runtime::Builder::new_multi_thread()
diff --git a/core/src/services/postgresql/backend.rs
b/core/src/services/postgresql/backend.rs
index 7600a5bde..23eb127dd 100644
--- a/core/src/services/postgresql/backend.rs
+++ b/core/src/services/postgresql/backend.rs
@@ -15,16 +15,21 @@
// specific language governing permissions and limitations
// under the License.
-use crate::raw::adapters::kv;
-use crate::raw::*;
-use crate::*;
-use async_trait::async_trait;
use std::collections::HashMap;
-use std::fmt::{Debug, Formatter};
+use std::fmt::Debug;
+use std::fmt::Formatter;
use std::str::FromStr;
use std::sync::Arc;
+
+use async_trait::async_trait;
use tokio::sync::OnceCell;
-use tokio_postgres::{Client, Config, Statement};
+use tokio_postgres::Client;
+use tokio_postgres::Config;
+use tokio_postgres::Statement;
+
+use crate::raw::adapters::kv;
+use crate::raw::*;
+use crate::*;
/// [Postgresql](https://www.postgresql.org/) services support.
#[doc = include_str!("docs.md")]
diff --git a/core/src/types/entry.rs b/core/src/types/entry.rs
index d6a062828..86121293c 100644
--- a/core/src/types/entry.rs
+++ b/core/src/types/entry.rs
@@ -175,11 +175,7 @@ impl Entry {
/// let (path, meta) = entry.into_parts();
/// match meta.mode() {
/// EntryMode::FILE => {
- /// println!(
- /// "Handling file {} with size {}",
- /// path,
- /// meta.content_length()
- /// )
+ /// println!("Handling file {} with size {}", path,
meta.content_length())
/// }
/// EntryMode::DIR => {
/// println!("Handling dir {}", path)
diff --git a/core/src/types/error.rs b/core/src/types/error.rs
index e4266a96f..cd1def506 100644
--- a/core/src/types/error.rs
+++ b/core/src/types/error.rs
@@ -35,6 +35,8 @@
//! # }
//! ```
+use std::backtrace::Backtrace;
+use std::backtrace::BacktraceStatus;
use std::fmt;
use std::fmt::Debug;
use std::fmt::Display;
@@ -172,6 +174,65 @@ impl Display for ErrorStatus {
}
/// Error is the error struct returned by all opendal functions.
+///
+/// ## Display
+///
+/// Error can be displayed in two ways:
+///
+/// - Via `Display`: like `err.to_string()` or `format!("{err}")`
+///
+/// Error will be printed in a single line:
+///
+/// ```shell
+/// Unexpected, context: { path: /path/to/file, called: send_async } =>
something wrong happened, source: networking error"
+/// ```
+///
+/// - Via `Debug`: like `format!("{err:?}")`
+///
+/// Error will be printed in multi lines with more details and backtraces (if
captured):
+///
+/// ```shell
+/// Unexpected => something wrong happened
+///
+/// Context:
+/// path: /path/to/file
+/// called: send_async
+///
+/// Source: networking error
+///
+/// Backtrace:
+/// 0: opendal::error::Error::new
+/// at ./src/error.rs:197:24
+/// 1: opendal::error::tests::generate_error
+/// at ./src/error.rs:241:9
+/// 2: opendal::error::tests::test_error_debug_with_backtrace::{{closure}}
+/// at ./src/error.rs:305:41
+/// ...
+/// ```
+///
+/// - For conventional struct-style Debug representation, like
`format!("{err:#?}")`:
+///
+/// ```shell
+/// Error {
+/// kind: Unexpected,
+/// message: "something wrong happened",
+/// status: Permanent,
+/// operation: "Read",
+/// context: [
+/// (
+/// "path",
+/// "/path/to/file",
+/// ),
+/// (
+/// "called",
+/// "send_async",
+/// ),
+/// ],
+/// source: Some(
+/// "networking error",
+/// ),
+/// }
+/// ```
pub struct Error {
kind: ErrorKind,
message: String,
@@ -180,6 +241,7 @@ pub struct Error {
operation: &'static str,
context: Vec<(&'static str, String)>,
source: Option<anyhow::Error>,
+ backtrace: Backtrace,
}
impl Display for Error {
@@ -236,12 +298,18 @@ impl Debug for Error {
writeln!(f)?;
writeln!(f, "Context:")?;
for (k, v) in self.context.iter() {
- writeln!(f, " {k}: {v}")?;
+ writeln!(f, " {k}: {v}")?;
}
}
if let Some(source) = &self.source {
writeln!(f)?;
- writeln!(f, "Source: {source:?}")?;
+ writeln!(f, "Source:")?;
+ writeln!(f, " {source:#}")?;
+ }
+ if self.backtrace.status() == BacktraceStatus::Captured {
+ writeln!(f)?;
+ writeln!(f, "Backtrace:")?;
+ writeln!(f, "{}", self.backtrace)?;
}
Ok(())
@@ -265,6 +333,9 @@ impl Error {
operation: "",
context: Vec::default(),
source: None,
+ // `Backtrace::capture()` will check if backtrace has been enabled
+ // internally. It's zero cost if backtrace is disabled.
+ backtrace: Backtrace::capture(),
}
}
@@ -359,6 +430,7 @@ impl From<Error> for io::Error {
mod tests {
use anyhow::anyhow;
use once_cell::sync::Lazy;
+ use pretty_assertions::assert_eq;
use super::*;
@@ -372,6 +444,7 @@ mod tests {
("called", "send_async".to_string()),
],
source: Some(anyhow!("networking error")),
+ backtrace: Backtrace::disabled(),
});
#[test]
@@ -380,7 +453,8 @@ mod tests {
assert_eq!(
s,
r#"Unexpected (permanent) at Read, context: { path: /path/to/file,
called: send_async } => something wrong happened, source: networking error"#
- )
+ );
+ println!("{:#?}", Lazy::force(&TEST_ERROR));
}
#[test]
@@ -391,10 +465,11 @@ mod tests {
r#"Unexpected (permanent) at Read => something wrong happened
Context:
- path: /path/to/file
- called: send_async
+ path: /path/to/file
+ called: send_async
-Source: networking error
+Source:
+ networking error
"#
)
}
diff --git a/core/src/types/operator/blocking_operator.rs
b/core/src/types/operator/blocking_operator.rs
index 8a9027df5..ade1086da 100644
--- a/core/src/types/operator/blocking_operator.rs
+++ b/core/src/types/operator/blocking_operator.rs
@@ -737,9 +737,9 @@ impl BlockingOperator {
///
/// ```no_run
/// # use anyhow::Result;
+ /// use opendal::BlockingOperator;
/// use opendal::EntryMode;
/// use opendal::Metakey;
- /// use opendal::BlockingOperator;
/// # fn test(op: BlockingOperator) -> Result<()> {
/// let mut entries = op.list("path/to/dir/")?;
/// for entry in entries {
@@ -786,9 +786,9 @@ impl BlockingOperator {
///
/// ```no_run
/// # use anyhow::Result;
+ /// use opendal::BlockingOperator;
/// use opendal::EntryMode;
/// use opendal::Metakey;
- /// use opendal::BlockingOperator;
/// # fn test(op: BlockingOperator) -> Result<()> {
/// let mut entries = op.list_with("prefix/").delimiter("").call()?;
/// for entry in entries {
@@ -810,9 +810,9 @@ impl BlockingOperator {
///
/// ```no_run
/// # use anyhow::Result;
+ /// use opendal::BlockingOperator;
/// use opendal::EntryMode;
/// use opendal::Metakey;
- /// use opendal::BlockingOperator;
/// # fn test(op: BlockingOperator) -> Result<()> {
/// let mut entries = op
/// .list_with("dir/")
@@ -888,9 +888,9 @@ impl BlockingOperator {
/// # use anyhow::Result;
/// # use futures::io;
/// use futures::TryStreamExt;
+ /// use opendal::BlockingOperator;
/// use opendal::EntryMode;
/// use opendal::Metakey;
- /// use opendal::BlockingOperator;
/// # fn test(op: BlockingOperator) -> Result<()> {
/// let mut ds = op.lister("path/to/dir/")?;
/// for de in ds {
@@ -926,9 +926,9 @@ impl BlockingOperator {
/// # use anyhow::Result;
/// # use futures::io;
/// use futures::TryStreamExt;
+ /// use opendal::BlockingOperator;
/// use opendal::EntryMode;
/// use opendal::Metakey;
- /// use opendal::BlockingOperator;
/// # fn test(op: BlockingOperator) -> Result<()> {
/// let mut ds = op
/// .lister_with("path/to/dir/")
@@ -957,9 +957,9 @@ impl BlockingOperator {
/// # use anyhow::Result;
/// # use futures::io;
/// use futures::TryStreamExt;
+ /// use opendal::BlockingOperator;
/// use opendal::EntryMode;
/// use opendal::Metakey;
- /// use opendal::BlockingOperator;
/// # fn test(op: BlockingOperator) -> Result<()> {
/// let mut ds = op.lister_with("path/to/dir/").delimiter("").call()?;
/// for entry in ds {
@@ -984,9 +984,9 @@ impl BlockingOperator {
/// # use anyhow::Result;
/// # use futures::io;
/// use futures::TryStreamExt;
+ /// use opendal::BlockingOperator;
/// use opendal::EntryMode;
/// use opendal::Metakey;
- /// use opendal::BlockingOperator;
/// # fn test(op: BlockingOperator) -> Result<()> {
/// let mut ds = op
/// .lister_with("path/to/dir/")
diff --git a/core/tests/behavior/blocking_write.rs
b/core/tests/behavior/blocking_write.rs
index 62838d8e0..2b4f65a91 100644
--- a/core/tests/behavior/blocking_write.rs
+++ b/core/tests/behavior/blocking_write.rs
@@ -19,7 +19,8 @@ use std::io::Read;
use std::io::Seek;
use anyhow::Result;
-use log::{debug, warn};
+use log::debug;
+use log::warn;
use sha2::Digest;
use sha2::Sha256;