spdlog/sink/
mod.rs

1//! Provides sinks to flexibly output log messages to specified targets.
2//!
3//! # Sink
4//!
5//! Sinks are the objects that actually write logs to their targets. Each sink
6//! should be responsible for only single target (e.g file, console, database),
7//! and each sink has its own private instance of [`Formatter`] object.
8//!
9//! A sink has its own level filter that is not shared with the logger, and a
10//! [`Logger`] can combine multiple [`Sink`]s.
11//!
12//! # Combined sink
13//!
14//! A combined sink is also a sink, but instead of having its own target and
15//! formatter, it combines other sinks (as sub-sinks).
16//!
17//! Operations on a combined sink will be forwarded to its sub-sinks according
18//! to the implementation.
19//!
20//! [`Logger`]: crate::logger::Logger
21
22#[cfg(any(
23    all(target_os = "android", feature = "native", feature = "android-ndk"),
24    all(doc, not(doctest))
25))]
26mod android_sink;
27#[cfg(feature = "multi-thread")]
28pub(crate) mod async_sink;
29mod dedup_sink;
30mod file_sink;
31#[cfg(any(
32    all(target_os = "linux", feature = "native", feature = "libsystemd"),
33    all(doc, not(doctest))
34))]
35mod journald_sink;
36mod rotating_file_sink;
37mod std_stream_sink;
38#[cfg(any(all(windows, feature = "native"), all(doc, not(doctest))))]
39mod win_debug_sink;
40mod write_sink;
41
42use std::ops::Deref;
43
44#[cfg(any(
45    all(target_os = "android", feature = "native", feature = "android-ndk"),
46    all(doc, not(doctest))
47))]
48pub use android_sink::*;
49#[cfg(feature = "multi-thread")]
50pub use async_sink::*;
51pub use dedup_sink::*;
52pub use file_sink::*;
53#[cfg(any(
54    all(target_os = "linux", feature = "native", feature = "libsystemd"),
55    all(doc, not(doctest))
56))]
57pub use journald_sink::*;
58pub use rotating_file_sink::*;
59pub use std_stream_sink::*;
60#[cfg(any(all(windows, feature = "native"), all(doc, not(doctest))))]
61pub use win_debug_sink::*;
62pub use write_sink::*;
63
64use crate::{
65    formatter::{Formatter, FullFormatter},
66    sync::*,
67    Error, ErrorHandler, Level, LevelFilter, Record, Result,
68};
69
70pub(crate) const SINK_DEFAULT_LEVEL_FILTER: LevelFilter = LevelFilter::All;
71
72/// Contains definitions of sink properties.
73///
74/// It provides a set of common properties for sink to define. If there is no
75/// special need for properties, use it directly and then implement
76/// [`GetSinkProp`] for your sink, a blanket implementation will be enabled,
77/// which would eliminate a lot of boilerplate code.
78///
79/// If further customization of the properties is needed (e.g., using different
80/// types, changing behavior), this struct is not needed. Instead, define
81/// properties manually within your sink, and then implement [`SinkPropAccess`].
82pub struct SinkProp {
83    level_filter: Atomic<LevelFilter>,
84    formatter: RwLockMappable<Box<dyn Formatter>>,
85    error_handler: RwLock<ErrorHandler>,
86}
87
88impl Default for SinkProp {
89    fn default() -> Self {
90        Self {
91            level_filter: Atomic::new(SINK_DEFAULT_LEVEL_FILTER),
92            formatter: RwLockMappable::new(Box::new(FullFormatter::new())),
93            error_handler: RwLock::new(ErrorHandler::default()),
94        }
95    }
96}
97
98impl SinkProp {
99    /// Gets the log level filter.
100    #[must_use]
101    pub fn level_filter(&self) -> LevelFilter {
102        self.level_filter.load(Ordering::Relaxed)
103    }
104
105    /// Sets the log level filter.
106    pub fn set_level_filter(&self, level_filter: LevelFilter) {
107        self.level_filter.store(level_filter, Ordering::Relaxed)
108    }
109
110    /// Gets the formatter.
111    ///
112    /// The returned value is a lock guard, so please avoid storing it in a
113    /// variable with a longer lifetime.
114    pub fn formatter<'a>(&'a self) -> impl Deref<Target = dyn Formatter> + 'a {
115        RwLockMappableReadGuard::map(self.formatter.read(), |f| &**f)
116    }
117
118    /// Sets the formatter.
119    pub fn set_formatter<F>(&self, formatter: F)
120    where
121        F: Formatter + 'static,
122    {
123        self.set_formatter_boxed(Box::new(formatter));
124    }
125
126    /// Sets the boxed formatter.
127    pub fn set_formatter_boxed(&self, formatter: Box<dyn Formatter>) {
128        *self.formatter.write() = formatter;
129    }
130
131    /// Calls the error handler with an error.
132    pub fn call_error_handler(&self, err: Error) {
133        self.error_handler.read_expect().call(err)
134    }
135
136    pub(crate) fn call_error_handler_internal(&self, from: impl AsRef<str>, err: Error) {
137        self.error_handler.read_expect().call_internal(from, err)
138    }
139
140    /// Sets a error handler.
141    ///
142    /// Most errors that occur in `Sink` will be returned as directly as
143    /// possible (e.g. returned to [`Logger`]), but some errors that cannot be
144    /// returned immediately, this function will be called. For example,
145    /// asynchronous errors.
146    ///
147    /// [`Logger`]: crate::logger::Logger
148    pub fn set_error_handler<F: Into<ErrorHandler>>(&self, handler: F) {
149        *self.error_handler.write_expect() = handler.into();
150    }
151}
152
153/// Represents the getter for the [`SinkProp`] inside a sink.
154///
155/// This trait is not mandatory for a sink. It enables a blanket implementation,
156/// where a sink that implements this trait will automatically get the
157/// [`SinkPropAccess`] trait implemented, which eliminates a lot of boilerplate
158/// code.
159pub trait GetSinkProp {
160    /// Gets the [`SinkProp`] from a sink.
161    fn prop(&self) -> &SinkProp;
162}
163
164/// Represents getters for properties of a sink.
165///
166/// The use of a sink requires these properties, and this trait describes the
167/// methods for getting them.
168///
169/// For the common case of custom sinks, users don't need to implement this
170/// trait manually, they can just store a `SinkProp` in their sink struct and
171/// implement trait [`GetSinkProp`], a blanket implementation will automatically
172/// implement `SinkPropAccess` for the sink.
173///
174/// For more details on implementing custom sink, see [. /examples] directory.
175///
176/// [./examples]: https://github.com/SpriteOvO/spdlog-rs/tree/main/spdlog/examples
177pub trait SinkPropAccess {
178    /// Gets the log level filter.
179    #[must_use]
180    fn level_filter(&self) -> LevelFilter;
181
182    /// Sets the log level filter.
183    fn set_level_filter(&self, level_filter: LevelFilter);
184
185    /// Sets the formatter.
186    fn set_formatter(&self, formatter: Box<dyn Formatter>);
187
188    /// Sets a error handler.
189    ///
190    /// Most errors that occur in `Sink` will be returned as directly as
191    /// possible (e.g. returned to [`Logger`]), but some errors that cannot be
192    /// returned immediately, this function will be called. For example,
193    /// asynchronous errors.
194    ///
195    /// [`Logger`]: crate::logger::Logger
196    fn set_error_handler(&self, handler: ErrorHandler);
197}
198
199impl<S: GetSinkProp> SinkPropAccess for S {
200    fn level_filter(&self) -> LevelFilter {
201        self.prop().level_filter()
202    }
203
204    fn set_level_filter(&self, level_filter: LevelFilter) {
205        self.prop().set_level_filter(level_filter);
206    }
207
208    fn set_formatter(&self, formatter: Box<dyn Formatter>) {
209        self.prop().set_formatter_boxed(formatter);
210    }
211
212    fn set_error_handler(&self, handler: ErrorHandler) {
213        self.prop().set_error_handler(handler);
214    }
215}
216
217/// Represents a sink
218///
219/// See [./examples] directory for how to implement a custom sink.
220///
221/// [./examples]: https://github.com/SpriteOvO/spdlog-rs/tree/main/spdlog/examples
222pub trait Sink: SinkPropAccess + Sync + Send {
223    /// Determines if a log message with the specified level would be logged.
224    #[must_use]
225    fn should_log(&self, level: Level) -> bool {
226        self.level_filter().test(level)
227    }
228
229    /// Logs a record.
230    fn log(&self, record: &Record) -> Result<()>;
231
232    /// Flushes any buffered records.
233    fn flush(&self) -> Result<()>;
234}
235
236/// Container type for [`Sink`]s.
237pub type Sinks = Vec<Arc<dyn Sink>>;