android_logd_logger/logger.rs
1use crate::{thread, Buffer, Priority, Record, TagMode};
2use env_logger::filter::{Builder, Filter};
3use log::{LevelFilter, Log, Metadata};
4use parking_lot::RwLock;
5use std::{io, process, sync::Arc, time::SystemTime};
6
7/// Logger configuration.
8pub(crate) struct Configuration {
9 pub(crate) filter: Filter,
10 pub(crate) tag: TagMode,
11 pub(crate) prepend_module: bool,
12 #[allow(unused)]
13 pub(crate) pstore: bool,
14 pub(crate) buffer_id: Buffer,
15}
16
17/// Logger configuration handler stores access to logger configuration parameters.
18#[derive(Clone)]
19pub struct Logger {
20 pub(crate) configuration: Arc<RwLock<Configuration>>,
21}
22
23impl Logger {
24 /// Sets buffer parameter of logger configuration
25 ///
26 /// # Examples
27 ///
28 /// ```
29 /// # use log::LevelFilter;
30 /// # use android_logd_logger::{Builder, Buffer};
31 ///
32 /// let logger = android_logd_logger::builder().init();
33 ///
34 /// logger.buffer(Buffer::Crash);
35 /// ```
36 pub fn buffer(&self, buffer: Buffer) -> &Self {
37 self.configuration.write().buffer_id = buffer;
38 self
39 }
40
41 // Sets tag parameter of logger configuration to custom value
42 ///
43 /// # Examples
44 ///
45 /// ```
46 /// # use log::LevelFilter;
47 /// # use android_logd_logger::Builder;
48 ///
49 /// let logger = android_logd_logger::builder().init();
50 ///
51 /// logger.tag("foo");
52 /// ```
53 pub fn tag(&self, tag: &str) -> &Self {
54 self.configuration.write().tag = TagMode::Custom(tag.into());
55 self
56 }
57
58 /// Sets tag parameter of logger configuration to target value
59 ///
60 /// # Examples
61 ///
62 /// ```
63 /// # use log::LevelFilter;
64 /// # use android_logd_logger::Builder;
65 ///
66 /// let logger = android_logd_logger::builder().init();
67 ///
68 /// logger.tag_target();
69 /// ```
70 pub fn tag_target(&self) -> &Self {
71 self.configuration.write().tag = TagMode::Target;
72 self
73 }
74
75 /// Sets tag parameter of logger configuration to strip value
76 ///
77 /// # Examples
78 ///
79 /// ```
80 /// # use log::LevelFilter;
81 /// # use android_logd_logger::Builder;
82 ///
83 /// let logger = android_logd_logger::builder().init();
84 ///
85 /// logger.tag_target_strip();
86 /// ```
87 pub fn tag_target_strip(&self) -> &Self {
88 self.configuration.write().tag = TagMode::TargetStrip;
89 self
90 }
91
92 /// Sets prepend module parameter of logger configuration
93 ///
94 /// # Examples
95 ///
96 /// ```
97 /// # use log::LevelFilter;
98 /// # use android_logd_logger::Builder;
99 ///
100 /// let logger = android_logd_logger::builder().init();
101 ///
102 /// logger.prepend_module(true);
103 /// ```
104 pub fn prepend_module(&self, prepend_module: bool) -> &Self {
105 self.configuration.write().prepend_module = prepend_module;
106 self
107 }
108
109 /// Adds a directive to the filter for a specific module.
110 ///
111 /// # Examples
112 ///
113 /// Only include messages for warning and above for logs in `path::to::module`:
114 ///
115 /// ```
116 /// # use log::LevelFilter;
117 /// # use android_logd_logger::Builder;
118 ///
119 /// let logger = android_logd_logger::builder().init();
120 ///
121 /// logger.filter_module("path::to::module", LevelFilter::Info);
122 /// ```
123 pub fn filter_module(&self, module: &str, level: LevelFilter) -> &Self {
124 self.configuration.write().filter = Builder::default().filter_module(module, level).build();
125 self
126 }
127
128 /// Adjust filter.
129 ///
130 /// # Examples
131 ///
132 /// Only include messages for warning and above.
133 ///
134 /// ```
135 /// # use log::LevelFilter;
136 /// # use android_logd_logger::Builder;
137 ///
138 /// let logger = Builder::new().init();
139 /// logger.filter_level(LevelFilter::Info);
140 /// ```
141 pub fn filter_level(&self, level: LevelFilter) -> &Self {
142 self.configuration.write().filter = Builder::default().filter_level(level).build();
143 self
144 }
145
146 /// Adjust filter.
147 ///
148 /// The given module (if any) will log at most the specified level provided.
149 /// If no module is provided then the filter will apply to all log messages.
150 ///
151 /// # Examples
152 ///
153 /// Only include messages for warning and above for logs in `path::to::module`:
154 ///
155 /// ```
156 /// # use log::LevelFilter;
157 /// # use android_logd_logger::Builder;
158 ///
159 /// let logger = Builder::new().init();
160 /// logger.filter(Some("path::to::module"), LevelFilter::Info);
161 /// ```
162 pub fn filter(&self, module: Option<&str>, level: LevelFilter) -> &Self {
163 self.configuration.write().filter = Builder::default().filter(module, level).build();
164 self
165 }
166
167 /// Parses the directives string in the same form as the `RUST_LOG`
168 /// environment variable.
169 ///
170 /// See the module documentation for more details.
171 pub fn parse_filters(&mut self, filters: &str) -> &mut Self {
172 let filter = Builder::default().parse(filters).build();
173 log::set_max_level(filter.filter());
174 self.configuration.write().filter = filter;
175 self
176 }
177
178 /// Sets filter parameter of logger configuration
179 ///
180 /// # Examples
181 ///
182 /// ```
183 /// # use log::LevelFilter;
184 /// # use android_logd_logger::Builder;
185 ///
186 /// let logger = android_logd_logger::builder().init();
187 ///
188 /// logger.pstore(true);
189 /// ```
190 #[cfg(target_os = "android")]
191 pub fn pstore(&self, pstore: bool) -> &Self {
192 self.configuration.write().pstore = pstore;
193 self
194 }
195}
196
197/// Logger implementation.
198pub(crate) struct LoggerImpl {
199 configuration: Arc<RwLock<Configuration>>,
200}
201
202impl LoggerImpl {
203 pub fn new(configuration: Arc<RwLock<Configuration>>) -> Result<LoggerImpl, io::Error> {
204 Ok(LoggerImpl { configuration })
205 }
206}
207
208impl Log for LoggerImpl {
209 fn enabled(&self, metadata: &Metadata) -> bool {
210 self.configuration.read().filter.enabled(metadata)
211 }
212
213 fn log(&self, record: &log::Record) {
214 let configuration = self.configuration.read();
215
216 if !configuration.filter.matches(record) {
217 return;
218 }
219
220 let args = record.args().to_string();
221 let message = if let Some(module_path) = record.module_path() {
222 if configuration.prepend_module {
223 [module_path, &args].join(": ")
224 } else {
225 args
226 }
227 } else {
228 args
229 };
230
231 let priority: Priority = record.metadata().level().into();
232 let tag = match &configuration.tag {
233 TagMode::Target => record.target(),
234 TagMode::TargetStrip => record
235 .target()
236 .split_once("::")
237 .map(|(tag, _)| tag)
238 .unwrap_or_else(|| record.target()),
239 TagMode::Custom(tag) => tag.as_str(),
240 };
241
242 let timestamp = SystemTime::now();
243 let record = Record {
244 timestamp,
245 pid: process::id() as u16,
246 thread_id: thread::id() as u16,
247 buffer_id: configuration.buffer_id,
248 tag,
249 priority,
250 message: &message,
251 };
252
253 crate::log_record(&record).ok();
254
255 #[cfg(target_os = "android")]
256 {
257 if configuration.pstore {
258 crate::pmsg::log(&record);
259 }
260 }
261 }
262
263 #[cfg(not(target_os = "android"))]
264 fn flush(&self) {
265 use std::io::Write;
266 io::stderr().flush().ok();
267 }
268
269 #[cfg(target_os = "android")]
270 fn flush(&self) {
271 if self.configuration.read().pstore {
272 crate::pmsg::flush().ok();
273 }
274 }
275}