diff --git a/src/lib.rs b/src/lib.rs index 461078bd..8c1be91b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1072,6 +1072,17 @@ where let _ = self.drain.log(record, &self.list); } + /// Flush all pending log records, + /// blocking until completion. + /// + /// Will call [`std::io::Write::flush`] if applicable. + /// + /// Returns [`FlushError::NotSupported`] if the underlying drain does not support [`Drain::flush`]. + #[inline] + pub fn flush(&self) -> result::Result<(), FlushError> { + self.drain.flush() + } + /// Get list of key-value pairs assigned to this `Logger` pub fn list(&self) -> &OwnedKVList { &self.list @@ -1152,6 +1163,53 @@ where fn is_enabled(&self, level: Level) -> bool { self.drain.is_enabled(level) } + + #[inline] + fn flush(&self) -> result::Result<(), FlushError> { + self.drain.flush() + } +} + +/// An error that occurs when calling [`Drain::flush`]. +#[non_exhaustive] +#[derive(Debug)] +pub enum FlushError { + /// An error that occurs doing IO. + /// + /// Often triggered by [`std::io::] + #[cfg(feature = "std")] + Io(std::io::Error), + /// Indicates this drain does not support flushing. + NotSupported, +} +#[cfg(feature = "std")] +impl From for FlushError { + fn from(value: std::io::Error) -> Self { + FlushError::Io(value) + } +} +#[cfg(has_std_error)] +impl StdError for FlushError { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + match self { + #[cfg(feature = "std")] + FlushError::Io(cause) => Some(cause), + FlushError::NotSupported => None, + } + } +} +impl fmt::Display for FlushError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + #[cfg(feature = "std")] + FlushError::Io(_) => { + f.write_str("Encountered IO error during flushing") + } + FlushError::NotSupported => { + f.write_str("Drain does not support flushing") + } + } + } } // {{{ Drain @@ -1196,6 +1254,15 @@ pub trait Drain { values: &OwnedKVList, ) -> result::Result; + /// Flush all pending log records, blocking until completion. + /// + /// Should call [`std::io::Write::flush`] if applicable. + /// + /// Returns [`FlushError::NotSupported`] if the drain has not implemented this method. + fn flush(&self) -> result::Result<(), FlushError> { + Err(FlushError::NotSupported) + } + /// **Avoid**: Check if messages at the specified log level are **maybe** /// enabled for this logger. /// @@ -1358,6 +1425,10 @@ impl<'a, D: Drain + 'a> Drain for &'a D { fn is_enabled(&self, level: Level) -> bool { (**self).is_enabled(level) } + #[inline] + fn flush(&self) -> result::Result<(), FlushError> { + (**self).flush() + } } impl<'a, D: Drain + 'a> Drain for &'a mut D { @@ -1375,6 +1446,10 @@ impl<'a, D: Drain + 'a> Drain for &'a mut D { fn is_enabled(&self, level: Level) -> bool { (**self).is_enabled(level) } + #[inline] + fn flush(&self) -> result::Result<(), FlushError> { + (**self).flush() + } } /// Internal utility module used to "maybe" bound traits @@ -1536,6 +1611,10 @@ impl Drain for Box { fn is_enabled(&self, level: Level) -> bool { (**self).is_enabled(level) } + #[inline] + fn flush(&self) -> result::Result<(), FlushError> { + (**self).flush() + } } impl Drain for Arc { @@ -1552,6 +1631,10 @@ impl Drain for Arc { fn is_enabled(&self, level: Level) -> bool { (**self).is_enabled(level) } + #[inline] + fn flush(&self) -> result::Result<(), FlushError> { + (**self).flush() + } } /// `Drain` discarding everything @@ -1575,6 +1658,10 @@ impl Drain for Discard { fn is_enabled(&self, _level: Level) -> bool { false } + #[inline] + fn flush(&self) -> result::Result<(), FlushError> { + Ok(()) + } } /// `Drain` filtering records @@ -1623,6 +1710,10 @@ where */ self.0.is_enabled(level) } + #[inline] + fn flush(&self) -> result::Result<(), FlushError> { + self.0.flush() + } } /// `Drain` filtering records by `Record` logging level @@ -1663,6 +1754,10 @@ impl Drain for LevelFilter { fn is_enabled(&self, level: Level) -> bool { level.is_at_least(self.1) && self.0.is_enabled(level) } + #[inline] + fn flush(&self) -> result::Result<(), FlushError> { + self.0.flush() + } } /// `Drain` mapping error returned by another `Drain` @@ -1704,6 +1799,10 @@ impl Drain for MapError { fn is_enabled(&self, level: Level) -> bool { self.drain.is_enabled(level) } + #[inline] + fn flush(&self) -> result::Result<(), FlushError> { + self.drain.flush() + } } /// `Drain` duplicating records into two other `Drain`s @@ -1743,6 +1842,17 @@ impl Drain for Duplicate { fn is_enabled(&self, level: Level) -> bool { self.0.is_enabled(level) || self.1.is_enabled(level) } + /// Flush both drains. + /// + /// Will return [`FlushError::NotSupported`] if either drain does not support flushing. + /// If one drain supports flushing and the other does not, + /// it is unspecified whether or not anything will be flushed at all. + #[inline] + fn flush(&self) -> result::Result<(), FlushError> { + self.0.flush()?; + self.1.flush()?; + Ok(()) + } } /// `Drain` panicking on error @@ -1789,6 +1899,10 @@ where fn is_enabled(&self, level: Level) -> bool { self.0.is_enabled(level) } + #[inline] + fn flush(&self) -> result::Result<(), FlushError> { + self.0.flush() + } } /// `Drain` ignoring result @@ -1825,6 +1939,11 @@ impl Drain for IgnoreResult { fn is_enabled(&self, level: Level) -> bool { self.drain.is_enabled(level) } + + #[inline] + fn flush(&self) -> result::Result<(), FlushError> { + self.drain.flush() + } } /// Error returned by `Mutex` @@ -1920,6 +2039,13 @@ impl Drain for std::sync::Mutex { fn is_enabled(&self, level: Level) -> bool { self.lock().ok().map_or(true, |lock| lock.is_enabled(level)) } + #[inline] + fn flush(&self) -> result::Result<(), FlushError> { + let guard = self.lock().map_err(|_poison| { + std::io::Error::new(std::io::ErrorKind::Other, "Mutex is poisoned") + })?; + guard.flush() + } } // }}}