pub struct Logger { /* private fields */ }Expand description
Manages, controls and manipulates multiple sinks.
Logger is an entry point for a log to be processed, the Logger::log
method will be called by logging macros.
A Logger:
-
contains one or more sinks, each log will be passed into sinks in sequence;
-
has a level filter of its own, which is not shared with the level filter of sinks;
-
has automatic flushing policies that can be optionally enabled:
- Flush level filter: Flush once when the filter returns
truefor a log. - Flush period: Flush periodically.
These two automatic flushing policies can work at the same time.
- Flush level filter: Flush once when the filter returns
spdlog-rs has a global default_logger, you can modify it, or configure
a new logger to suit your needs and then replace it. Basically for a
lightweight program, such a global singleton logger is enough. For a complex
program, for example if you have a number of different components, you can
also configure multiple loggers and store them independently inside the
component struct, which allows different components to have different
approaches for logging.
§Examples
- Logging to the global default logger.
use spdlog::prelude::*;
info!("logging to the default logger");
spdlog::default_logger().set_level_filter(LevelFilter::All);
trace!("logging to the default logger at trace level");- Logging to a separated logger.
let separated_logger = /* ... */
info!(logger: separated_logger, "logging to a separated logger");
error!(logger: separated_logger, "logging to a separated logger at error level");- Fork, configure and replace the default logger.
let new_logger = spdlog::default_logger().fork_with(|new_logger| {
// Configure the new logger...
Ok(())
})?;
spdlog::set_default_logger(new_logger);
info!("logging to the default logger, but it's reconfigured");- For more examples, see ./examples directory.
Implementations§
Source§impl Logger
impl Logger
Sourcepub fn builder() -> LoggerBuilder
pub fn builder() -> LoggerBuilder
Gets a LoggerBuilder with default parameters:
| Parameter | Default Value |
|---|---|
| name | None |
| sinks | [] |
| level_filter | MoreSevereEqual(Info) |
| flush_level_filter | LevelFilter::Off |
| flush_period | None |
| error_handler | ErrorHandler::default() |
Examples found in repository?
18fn configure_file_logger() -> Result<(), Box<dyn std::error::Error>> {
19 let path = env::current_exe()?.with_file_name("file.log");
20
21 let file_sink = FileSink::builder().path(path).build_arc()?;
22 let new_logger = Logger::builder().sink(file_sink).build_arc()?;
23 spdlog::set_default_logger(new_logger);
24
25 info!("this log will be written to the file `all.log`");
26
27 Ok(())
28}
29
30fn configure_rotating_daily_file_logger() -> Result<(), Box<dyn std::error::Error>> {
31 let path = env::current_exe()?.with_file_name("rotating_daily.log");
32
33 let file_sink = RotatingFileSink::builder()
34 .base_path(path)
35 .rotation_policy(RotationPolicy::Daily { hour: 0, minute: 0 })
36 .build_arc()?;
37 let new_logger = Logger::builder().sink(file_sink).build_arc()?;
38 spdlog::set_default_logger(new_logger);
39
40 info!("this log will be written to the file `rotating_daily.log`, and the file will be rotated daily at 00:00");
41
42 Ok(())
43}
44
45fn configure_rotating_size_file_logger() -> Result<(), Box<dyn std::error::Error>> {
46 let path = env::current_exe()?.with_file_name("rotating_size.log");
47
48 let file_sink = RotatingFileSink::builder()
49 .base_path(path)
50 .rotation_policy(RotationPolicy::FileSize(1024))
51 .build_arc()?;
52 let new_logger = Logger::builder().sink(file_sink).build_arc()?;
53 spdlog::set_default_logger(new_logger);
54
55 info!("this log will be written to the file `rotating_size.log`, and the file will be rotated when its size reaches 1024 bytes");
56
57 Ok(())
58}
59
60fn configure_rotating_hourly_file_logger() -> Result<(), Box<dyn std::error::Error>> {
61 let path = env::current_exe()?.with_file_name("rotating_hourly.log");
62
63 let file_sink = RotatingFileSink::builder()
64 .base_path(path)
65 .rotation_policy(RotationPolicy::Hourly)
66 .build_arc()?;
67 let new_logger = Logger::builder().sink(file_sink).build_arc()?;
68 spdlog::set_default_logger(new_logger);
69
70 info!("this log will be written to the file `rotating_hourly.log`, and the file will be rotated every hour");
71
72 Ok(())
73}
74
75fn configure_rotating_period_file_logger() -> Result<(), Box<dyn std::error::Error>> {
76 let path = env::current_exe()?.with_file_name("rotating_period.log");
77
78 let file_sink = RotatingFileSink::builder()
79 .base_path(path)
80 .rotation_policy(RotationPolicy::Period(Duration::from_secs(
81 60 * 90, // 90 minutes
82 )))
83 .build_arc()?;
84 let new_logger = Logger::builder().sink(file_sink).build_arc()?;
85 spdlog::set_default_logger(new_logger);
86
87 info!("this log will be written to the file `rotating_period.log`, and the file will be rotated every 1.5 hours");
88
89 Ok(())
90}More examples
8fn main() -> Result<(), Box<dyn std::error::Error>> {
9 let path = env::current_exe()?.with_file_name("async.log");
10 let file_sink = FileSink::builder().path(path).build_arc()?;
11
12 // AsyncPoolSink is a combined sink which wraps other sinks
13 let async_pool_sink = AsyncPoolSink::builder().sink(file_sink).build_arc()?;
14
15 let async_logger = Logger::builder()
16 .sink(async_pool_sink)
17 .flush_level_filter(LevelFilter::All)
18 .build_arc()?;
19
20 info!(logger: async_logger, "Hello, async!");
21
22 Ok(())
23}50fn main() -> Result<(), Box<dyn std::error::Error>> {
51 let my_sink = Arc::new(CollectVecSink::new());
52 let example = Logger::builder().sink(my_sink.clone()).build()?;
53
54 info!(logger: example, "Hello, world!");
55 warn!(logger: example, "Meow~");
56
57 let collected = my_sink.collected();
58 println!("collected:\n{collected:#?}");
59
60 assert_eq!(collected.len(), 2);
61 assert!(collected[0].contains("[info]") && collected[0].contains("Hello, world!"));
62 assert!(collected[1].contains("[warn]") && collected[1].contains("Meow~"));
63
64 Ok(())
65}8fn main() -> Result<(), Box<dyn std::error::Error>> {
9 // `spdlog-rs` has a global default logger and logs will be processed by it
10 // by default, You can configure it.
11 let default_logger = spdlog::default_logger();
12 default_logger.set_level_filter(LevelFilter::All);
13
14 // Or completely replace it with a new one.
15 let path = env::current_exe()?.with_file_name("all.log");
16 let file_sink = FileSink::builder().path(path).build_arc()?;
17
18 let new_logger = Logger::builder()
19 .level_filter(LevelFilter::All)
20 .flush_level_filter(LevelFilter::MoreSevereEqual(Level::Warn))
21 .sink(file_sink.clone())
22 .build_arc()?;
23 new_logger.set_flush_period(Some(Duration::from_secs(3)));
24 spdlog::set_default_logger(new_logger);
25
26 info!("this log will be written to the file `all.log`");
27
28 // In addition to having the global default logger, more loggers are allowed to
29 // be configured, stored and used independently.
30 let db = AppDatabase::new(file_sink)?;
31 db.write_i32(114514);
32
33 Ok(())
34}
35
36struct AppDatabase {
37 logger: Logger,
38}
39
40impl AppDatabase {
41 fn new(all_log_sink: Arc<dyn Sink>) -> Result<Self, Box<dyn std::error::Error>> {
42 let path = env::current_exe()?.with_file_name("db.log");
43 let db_file_sink = FileSink::builder().path(path).build_arc()?;
44
45 let logger = Logger::builder()
46 .name("database")
47 .level_filter(LevelFilter::All)
48 .flush_level_filter(LevelFilter::MoreSevereEqual(Level::Warn))
49 .sinks([all_log_sink, db_file_sink])
50 .build()?;
51 Ok(Self { logger })
52 }Sourcepub fn name(&self) -> Option<&str>
pub fn name(&self) -> Option<&str>
Gets the logger name.
Returns None if the logger does not have a name.
Sourcepub fn set_name<S>(
&mut self,
name: Option<S>,
) -> StdResult<(), SetLoggerNameError>
pub fn set_name<S>( &mut self, name: Option<S>, ) -> StdResult<(), SetLoggerNameError>
Sets the logger name.
Examples found in repository?
2fn main() -> Result<(), Box<dyn std::error::Error>> {
3 use spdlog::{prelude::*, sink::JournaldSink};
4
5 let sink = JournaldSink::builder().build_arc()?;
6 let logger = spdlog::default_logger().fork_with(|logger| {
7 logger.set_name(Some("demo")).unwrap();
8 logger.sinks_mut().push(sink);
9 Ok(())
10 })?;
11 spdlog::set_default_logger(logger);
12
13 info!("info message from spdlog-rs's JournaldSink");
14 error!("error message from spdlog-rs's JournaldSink", kv: { error_code = 114514 });
15 Ok(())
16}Sourcepub fn should_log(&self, level: Level) -> bool
pub fn should_log(&self, level: Level) -> bool
Determines if a log with the specified level would be logged.
This allows callers to avoid expensive computation of log arguments if the would be discarded anyway.
§Examples
use spdlog::prelude::*;
logger.set_level_filter(LevelFilter::MoreSevere(Level::Info));
assert_eq!(logger.should_log(Level::Debug), false);
assert_eq!(logger.should_log(Level::Info), false);
assert_eq!(logger.should_log(Level::Warn), true);
assert_eq!(logger.should_log(Level::Error), true);
logger.set_level_filter(LevelFilter::All);
assert_eq!(logger.should_log(Level::Debug), true);
assert_eq!(logger.should_log(Level::Info), true);
assert_eq!(logger.should_log(Level::Warn), true);
assert_eq!(logger.should_log(Level::Error), true);Sourcepub fn flush(&self)
pub fn flush(&self)
Flushes sinks explicitly.
It calls Sink::flush method internally for each sink in sequence.
Users can call this function to flush explicitly and/or use automatic
flushing policies. See also Logger::flush_level_filter and
Logger::set_flush_period.
Be aware that the method can be expensive, calling it frequently may affect performance.
Sourcepub fn flush_level_filter(&self) -> LevelFilter
pub fn flush_level_filter(&self) -> LevelFilter
Gets the flush level filter.
Sourcepub fn set_flush_level_filter(&self, level_filter: LevelFilter)
pub fn set_flush_level_filter(&self, level_filter: LevelFilter)
Sets a flush level filter.
When logging a new record, flush the buffer if this filter condition
returns true.
This automatic flushing policy can work with
Logger::set_flush_period at the same time.
§Examples
use spdlog::prelude::*;
logger.set_flush_level_filter(LevelFilter::Off);
trace!(logger: logger, "hello");
trace!(logger: logger, "world");
// Until here the buffer may not have been flushed (depending on sinks implementation)
logger.set_flush_level_filter(LevelFilter::All);
trace!(logger: logger, "hello"); // Logs and flushes the buffer once
trace!(logger: logger, "world"); // Logs and flushes the buffer onceSourcepub fn level_filter(&self) -> LevelFilter
pub fn level_filter(&self) -> LevelFilter
Gets the log level filter.
Sourcepub fn set_level_filter(&self, level_filter: LevelFilter)
pub fn set_level_filter(&self, level_filter: LevelFilter)
Examples found in repository?
4fn main() {
5 // Writes a log at "info" level, and this log will be processed by the global
6 // default logger - It will be output to `stdout`.
7 info!("program started");
8
9 // They will be output to `stderr`.
10 let file = "config.json";
11 error!("failed to open file: {}", file);
12 warn!("undetermined locale, defaults to `en_US.UTF-8`");
13
14 // Level "trace" and "debug" will be ignored by default, you can modify the
15 // level filter of the global default logger to enable all levels.
16 let verbose = true;
17 if verbose {
18 spdlog::default_logger().set_level_filter(LevelFilter::All);
19 }
20
21 trace!("position x: {}, y: {}", 11.4, -5.14);
22 // Or if you prefer structured logging.
23 trace!("position", kv: { x = 11.4, y = -5.14 });
24}More examples
8fn main() -> Result<(), Box<dyn std::error::Error>> {
9 // `spdlog-rs` has a global default logger and logs will be processed by it
10 // by default, You can configure it.
11 let default_logger = spdlog::default_logger();
12 default_logger.set_level_filter(LevelFilter::All);
13
14 // Or completely replace it with a new one.
15 let path = env::current_exe()?.with_file_name("all.log");
16 let file_sink = FileSink::builder().path(path).build_arc()?;
17
18 let new_logger = Logger::builder()
19 .level_filter(LevelFilter::All)
20 .flush_level_filter(LevelFilter::MoreSevereEqual(Level::Warn))
21 .sink(file_sink.clone())
22 .build_arc()?;
23 new_logger.set_flush_period(Some(Duration::from_secs(3)));
24 spdlog::set_default_logger(new_logger);
25
26 info!("this log will be written to the file `all.log`");
27
28 // In addition to having the global default logger, more loggers are allowed to
29 // be configured, stored and used independently.
30 let db = AppDatabase::new(file_sink)?;
31 db.write_i32(114514);
32
33 Ok(())
34}Sourcepub fn set_flush_period(self: &Arc<Self>, interval: Option<Duration>)
pub fn set_flush_period(self: &Arc<Self>, interval: Option<Duration>)
Sets automatic periodic flushing.
This function receives a &Arc<Self>. Calling it will spawn a new
thread internally.
This automatic flushing policy can work with
Logger::set_flush_level_filter at the same time.
§Panics
-
Panics if
intervalis zero. -
Panics if this function is called with
Somevalue and then clones theLoggerinstead of theArc<Logger>.
§Examples
use std::time::Duration;
// From now on, the `logger` will automatically call `flush` method the every 10 seconds.
logger.set_flush_period(Some(Duration::from_secs(10)));
// Disable automatic periodic flushing.
logger.set_flush_period(None);Examples found in repository?
8fn main() -> Result<(), Box<dyn std::error::Error>> {
9 // `spdlog-rs` has a global default logger and logs will be processed by it
10 // by default, You can configure it.
11 let default_logger = spdlog::default_logger();
12 default_logger.set_level_filter(LevelFilter::All);
13
14 // Or completely replace it with a new one.
15 let path = env::current_exe()?.with_file_name("all.log");
16 let file_sink = FileSink::builder().path(path).build_arc()?;
17
18 let new_logger = Logger::builder()
19 .level_filter(LevelFilter::All)
20 .flush_level_filter(LevelFilter::MoreSevereEqual(Level::Warn))
21 .sink(file_sink.clone())
22 .build_arc()?;
23 new_logger.set_flush_period(Some(Duration::from_secs(3)));
24 spdlog::set_default_logger(new_logger);
25
26 info!("this log will be written to the file `all.log`");
27
28 // In addition to having the global default logger, more loggers are allowed to
29 // be configured, stored and used independently.
30 let db = AppDatabase::new(file_sink)?;
31 db.write_i32(114514);
32
33 Ok(())
34}Sourcepub fn sinks(&self) -> &[Arc<dyn Sink>]
pub fn sinks(&self) -> &[Arc<dyn Sink>]
Gets a reference to sinks in the logger.
Examples found in repository?
13fn use_pattern_formatter() {
14 use spdlog::{
15 formatter::{pattern, PatternFormatter},
16 prelude::*,
17 };
18
19 // Building a pattern formatter with a pattern.
20 // The `pattern!` macro will parse the template string at compile-time.
21 let new_formatter = Box::new(PatternFormatter::new(pattern!(
22 "{datetime} - {^{level}} - {payload}{eol}"
23 )));
24
25 // Setting the new formatter for each sink of the default logger.
26 for sink in spdlog::default_logger().sinks() {
27 sink.set_formatter(new_formatter.clone())
28 }
29
30 info!("format by `PatternFormatter`");
31}
32
33fn impl_manually() {
34 use std::fmt::Write;
35
36 use spdlog::{
37 formatter::{Formatter, FormatterContext},
38 prelude::*,
39 Record, StringBuf,
40 };
41
42 #[derive(Clone, Default)]
43 struct MyFormatter;
44
45 impl Formatter for MyFormatter {
46 fn format(
47 &self,
48 record: &Record,
49 dest: &mut StringBuf,
50 ctx: &mut FormatterContext,
51 ) -> spdlog::Result<()> {
52 let style_range_begin = dest.len();
53
54 dest.write_str(&record.level().as_str().to_ascii_uppercase())
55 .map_err(spdlog::Error::FormatRecord)?;
56
57 let style_range_end = dest.len();
58
59 writeln!(dest, " {}", record.payload()).map_err(spdlog::Error::FormatRecord)?;
60
61 ctx.set_style_range(Some(style_range_begin..style_range_end));
62 Ok(())
63 }
64 }
65
66 // Building a custom formatter.
67 let new_formatter = Box::new(MyFormatter);
68
69 // Setting the new formatter for each sink of the default logger.
70 for sink in spdlog::default_logger().sinks() {
71 sink.set_formatter(new_formatter.clone())
72 }
73
74 info!("format by `MyFormatter` (impl manually)");
75}Sourcepub fn sinks_mut(&mut self) -> &mut Sinks
pub fn sinks_mut(&mut self) -> &mut Sinks
Gets a mutable reference to sinks in the logger.
Examples found in repository?
2fn main() -> Result<(), Box<dyn std::error::Error>> {
3 use spdlog::{prelude::*, sink::JournaldSink};
4
5 let sink = JournaldSink::builder().build_arc()?;
6 let logger = spdlog::default_logger().fork_with(|logger| {
7 logger.set_name(Some("demo")).unwrap();
8 logger.sinks_mut().push(sink);
9 Ok(())
10 })?;
11 spdlog::set_default_logger(logger);
12
13 info!("info message from spdlog-rs's JournaldSink");
14 error!("error message from spdlog-rs's JournaldSink", kv: { error_code = 114514 });
15 Ok(())
16}Sourcepub fn set_error_handler<F: Into<ErrorHandler>>(&self, handler: F)
pub fn set_error_handler<F: Into<ErrorHandler>>(&self, handler: F)
Sets a error handler.
If an error occurs while logging or flushing, this handler will be
called. If no handler is set, the error will be print to stderr and
then ignored.
§Examples
use spdlog::prelude::*;
spdlog::default_logger().set_error_handler(|err| {
panic!("An error occurred in the default logger: {}", err)
});Sourcepub fn fork_with<F>(self: &Arc<Self>, modifier: F) -> Result<Arc<Self>>
pub fn fork_with<F>(self: &Arc<Self>, modifier: F) -> Result<Arc<Self>>
Forks and configures a separate new logger.
This function creates a new logger object that inherits logger
properties from Arc<Self>. Then this function calls the given
modifier function which configures the properties on the new
logger object. The created new logger object will be a separate
object from Arc<Self>. (No ownership sharing)
§Examples
let old: Arc<Logger> = /* ... */
// Fork from an existing logger and add a new sink.
let new = old.fork_with(|new| {
new.sinks_mut().push(new_sink);
Ok(())
})?;
info!(logger: new, "this record will be written to `new_sink`");
info!(logger: old, "this record will not be written to `new_sink`");Examples found in repository?
2fn main() -> Result<(), Box<dyn std::error::Error>> {
3 use spdlog::{prelude::*, sink::JournaldSink};
4
5 let sink = JournaldSink::builder().build_arc()?;
6 let logger = spdlog::default_logger().fork_with(|logger| {
7 logger.set_name(Some("demo")).unwrap();
8 logger.sinks_mut().push(sink);
9 Ok(())
10 })?;
11 spdlog::set_default_logger(logger);
12
13 info!("info message from spdlog-rs's JournaldSink");
14 error!("error message from spdlog-rs's JournaldSink", kv: { error_code = 114514 });
15 Ok(())
16}Sourcepub fn fork_with_name<S>(
self: &Arc<Self>,
new_name: Option<S>,
) -> Result<Arc<Self>>
pub fn fork_with_name<S>( self: &Arc<Self>, new_name: Option<S>, ) -> Result<Arc<Self>>
Forks a separates new logger with a new name.
This function creates a new logger object that inherits logger
properties from Arc<Self> and rename the new logger object to the
given name. The created new logger object will be a separate object
from Arc<Self>. (No ownership sharing)
This is a shorthand wrapper for Logger::fork_with.
§Examples
let old = Logger::builder().name("dog").build_arc()?;
let new = old.fork_with_name(Some("cat"))?;
assert_eq!(old.name(), Some("dog"));
assert_eq!(new.name(), Some("cat"));Examples found in repository?
1fn main() -> Result<(), Box<dyn std::error::Error>> {
2 spdlog::init_log_crate_proxy()
3 .expect("users should only call `init_log_crate_proxy` function once");
4
5 // Setup filter as needed.
6 let filter = env_filter::Builder::new().try_parse("RUST_LOG")?.build();
7 spdlog::log_crate_proxy().set_filter(Some(filter));
8
9 log::set_max_level(log::LevelFilter::Trace);
10 log::trace!("this log will be processed by the global default logger in spdlog-rs");
11
12 let custom_logger = spdlog::default_logger().fork_with_name(Some("another_logger"))?;
13 spdlog::log_crate_proxy().set_logger(Some(custom_logger));
14 log::info!("this log will be processed by custom_logger in spdlog-rs");
15
16 spdlog::log_crate_proxy().set_logger(None);
17 log::trace!("this log will be processed by the global default logger in spdlog-rs");
18
19 Ok(())
20}Trait Implementations§
Auto Trait Implementations§
impl !Freeze for Logger
impl !RefUnwindSafe for Logger
impl Send for Logger
impl Sync for Logger
impl Unpin for Logger
impl !UnwindSafe for Logger
Blanket Implementations§
§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§unsafe fn clone_to_uninit(&self, dest: *mut u8)
unsafe fn clone_to_uninit(&self, dest: *mut u8)
clone_to_uninit)