godot_logger/builder.rs
1use log::{Level, LevelFilter, SetLoggerError};
2use log4rs::config::{Appender, Logger, Root};
3use log4rs::Config;
4
5use crate::appender::GodotAppender;
6use crate::filter::Filter;
7
8const APPENDER_NAME: &str = "godot-logger";
9
10/// A `Builder` that configures and initializes the Godot logger
11///
12/// [godot-logger] implements the builder pattern as the primary interface to configure and
13/// initialize the logger. The configuration has sensible defaults that can be overwritten by
14/// calling the corresponding setters on the `Builder` struct. Once the configuration is done, the
15/// logger can be initialized by calling the `build` method.
16///
17/// # Examples
18///
19/// ```
20/// use log::Level;
21/// use godot_logger::GodotLogger;
22///
23/// GodotLogger::builder()
24/// .default_log_level(Level::Debug)
25/// .init();
26/// ```
27///
28/// [godot-logger]: https://crates.io/crates/godot-logger
29#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
30pub struct Builder {
31 default_log_level: Level,
32 filters: Vec<Filter>,
33}
34
35impl Builder {
36 /// Sets the default log level
37 ///
38 /// `GodotLogger` matches all log records against a default log level. By default, only warnings
39 /// and errors are logged.
40 ///
41 /// # Examples
42 ///
43 /// ```
44 /// use log::Level;
45 /// use godot_logger::GodotLogger;
46 ///
47 /// let mut builder = GodotLogger::builder();
48 /// builder = builder.default_log_level(Level::Debug);
49 /// ```
50 pub fn default_log_level(mut self, default_log_level: Level) -> Self {
51 self.default_log_level = default_log_level;
52 self
53 }
54
55 /// Adds a filter
56 ///
57 /// Filters override the default log level for specific Rust modules.
58 ///
59 /// # Examples
60 ///
61 /// ```
62 /// use godot_logger::GodotLogger;
63 /// use log::LevelFilter;
64 ///
65 /// GodotLogger::builder().add_filter("godot_logger", LevelFilter::Off);
66 /// ```
67 pub fn add_filter(mut self, module: &'static str, level: LevelFilter) -> Self {
68 self.filters.push(Filter::new(module, level));
69 self
70 }
71
72 /// Initializes the logger
73 ///
74 /// This method consumes the builder and initializes the logger with the current configuration
75 /// of the builder. After calling this method, log records will be written to Godot's output
76 /// console.
77 ///
78 /// # Examples
79 ///
80 /// ```
81 /// use log::Level;
82 /// use godot_logger::GodotLogger;
83 ///
84 /// GodotLogger::builder().init();
85 /// ```
86 pub fn init(self) -> Result<(), SetLoggerError> {
87 let loggers: Vec<Logger> = self
88 .filters
89 .iter()
90 .map(|filter| {
91 Logger::builder()
92 .appender(APPENDER_NAME)
93 .build(filter.module(), filter.level())
94 })
95 .collect();
96
97 let config = Config::builder()
98 .appender(Appender::builder().build(APPENDER_NAME, Box::new(GodotAppender)))
99 .loggers(loggers)
100 .build(
101 Root::builder()
102 .appender(APPENDER_NAME)
103 .build(self.default_log_level.to_level_filter()),
104 )
105 .unwrap();
106
107 let _handle = log4rs::init_config(config)?;
108 Ok(())
109 }
110}
111
112impl Default for Builder {
113 fn default() -> Self {
114 Self {
115 default_log_level: Level::Warn,
116 filters: Vec::new(),
117 }
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use log::{Level, LevelFilter};
124
125 use super::Builder;
126
127 #[test]
128 fn default_log_level() {
129 let mut builder = Builder::default();
130
131 builder = builder.default_log_level(Level::Debug);
132
133 assert!(matches!(builder.default_log_level, Level::Debug));
134 }
135
136 #[test]
137 fn add_filter() {
138 let mut builder = Builder::default();
139
140 builder = builder.add_filter("godot_logger::builder", LevelFilter::Off);
141
142 assert_eq!(builder.filters.len(), 1);
143 }
144
145 #[test]
146 fn trait_default() {
147 let builder = Builder::default();
148 assert!(matches!(builder.default_log_level, Level::Warn));
149 }
150
151 #[test]
152 fn trait_send() {
153 fn assert_send<T: Send>() {}
154 assert_send::<Builder>();
155 }
156
157 #[test]
158 fn trait_sync() {
159 fn assert_sync<T: Sync>() {}
160 assert_sync::<Builder>();
161 }
162}