From d3729fd0161a461e336187633f9acbe8d34d91d3 Mon Sep 17 00:00:00 2001 From: tison Date: Sun, 17 May 2026 22:41:53 +0800 Subject: [PATCH] refactor: core apis Signed-off-by: tison --- CHANGELOG.md | 1 + core/src/error.rs | 40 +++++++++++++++++++--------------------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6080e1e..3b536c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file. * `Async` appender's `flush` method is now blocking until all buffered logs are flushed by worker threads. Any errors during flushing will be propagated back to the `flush` caller. * `Record::payload` is now `std::fmt::Arguments` instead of `Cow<'static, str>`. * `RecordOwned::as_record` has been removed; use `RecordOwned::with` instead. (This is a limitation of Rust as described [here](https://github.com/rust-lang/rust/issues/92698#issuecomment-3311144848).) +* `logforth_core::Error::with_source` now set the optional source field instead of append a sources list. ## [0.29.1] 2025-11-03 diff --git a/core/src/error.rs b/core/src/error.rs index 31ac0c1..84c40f3 100644 --- a/core/src/error.rs +++ b/core/src/error.rs @@ -18,7 +18,7 @@ use std::io; /// The error struct of logforth. pub struct Error { message: String, - sources: Vec, + source: Option, context: Vec<(&'static str, String)>, } @@ -40,15 +40,8 @@ impl fmt::Display for Error { write!(f, " }}")?; } - if !self.sources.is_empty() { - write!(f, ", sources: [")?; - for (i, source) in self.sources.iter().enumerate() { - if i > 0 { - write!(f, ", ")?; - } - write!(f, "{source}")?; - } - write!(f, "]")?; + if let Some(source) = &self.source { + write!(f, ", source: {source}")?; } Ok(()) @@ -62,7 +55,7 @@ impl fmt::Debug for Error { let mut de = f.debug_struct("Error"); de.field("message", &self.message); de.field("context", &self.context); - de.field("sources", &self.sources); + de.field("sources", &self.source); return de.finish(); } @@ -76,12 +69,11 @@ impl fmt::Debug for Error { writeln!(f, " {k}: {v}")?; } } - if !self.sources.is_empty() { + + if let Some(source) = &self.source { writeln!(f)?; - writeln!(f, "Sources:")?; - for source in self.sources.iter() { - writeln!(f, " {source:#}")?; - } + writeln!(f, "Source:")?; + writeln!(f, " {source:#}")?; } Ok(()) @@ -90,7 +82,7 @@ impl fmt::Debug for Error { impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - self.sources.first().map(|v| v.as_ref()) + self.source.as_ref().map(|v| v.as_ref()) } } @@ -99,7 +91,7 @@ impl Error { pub fn new(message: impl Into) -> Self { Self { message: message.into(), - sources: vec![], + source: None, context: vec![], } } @@ -110,15 +102,21 @@ impl Error { self } - /// Add one more source in error. + /// Set source for error. + /// + /// # Panics + /// + /// If the source has been set, we will raise a panic here. pub fn with_source(mut self, src: impl Into) -> Self { - self.sources.push(src.into()); + assert!(self.source.is_none(), "the source error has been set"); + + self.source = Some(src.into()); self } /// Return an iterator over all sources of this error. pub fn sources(&self) -> impl ExactSizeIterator { - self.sources.iter().map(|v| v.as_ref()) + self.source.iter().map(|v| v.as_ref()) } /// Default constructor for [`Error`] from [`io::Error`].