|
1 | 1 | // Take a look at the license at the top of the repository in the LICENSE file.
|
2 | 2 |
|
3 |
| -use crate::{gstr, log as glib_log, log_structured_array, translate::*, LogField}; |
| 3 | +use crate::{gstr, log as glib_log, log_structured_array, translate::*, LogField, LogWriterOutput}; |
4 | 4 |
|
5 | 5 | // rustdoc-stripper-ignore-next
|
6 | 6 | /// Enumeration of the possible formatting behaviours for a
|
@@ -262,7 +262,108 @@ pub fn rust_log_handler(domain: Option<&str>, level: glib_log::LogLevel, message
|
262 | 262 | glib_log::LogLevel::Debug => rs_log::Level::Debug,
|
263 | 263 | };
|
264 | 264 |
|
265 |
| - rs_log::log!(target: domain.unwrap_or("<null>"), level, "{}", message); |
| 265 | + rs_log::log!(target: domain.unwrap_or_default(), level, "{message}"); |
| 266 | +} |
| 267 | + |
| 268 | +#[cfg(feature = "log_kv")] |
| 269 | +struct LogFields<'field>(&'field [LogField<'field>]); |
| 270 | + |
| 271 | +#[cfg(feature = "log_kv")] |
| 272 | +impl<'fields> rs_log::kv::Source for LogFields<'fields> { |
| 273 | + fn visit<'kvs>( |
| 274 | + &'kvs self, |
| 275 | + visitor: &mut dyn rs_log::kv::VisitSource<'kvs>, |
| 276 | + ) -> Result<(), rs_log::kv::Error> { |
| 277 | + use rs_log::kv::{Key, Value}; |
| 278 | + |
| 279 | + for field in self.0 { |
| 280 | + let key = Key::from_str(field.key()); |
| 281 | + let value = field |
| 282 | + .value_str() |
| 283 | + .map(Value::from) |
| 284 | + .unwrap_or_else(Value::null); |
| 285 | + visitor.visit_pair(key, value)?; |
| 286 | + } |
| 287 | + |
| 288 | + Ok(()) |
| 289 | + } |
| 290 | + |
| 291 | + fn count(&self) -> usize { |
| 292 | + self.0.len() |
| 293 | + } |
| 294 | +} |
| 295 | + |
| 296 | +// rustdoc-stripper-ignore-next |
| 297 | +/// Provides a glib log writer which routes all structured logging messages to the |
| 298 | +/// [`log crate`](https://crates.io/crates/log). |
| 299 | +/// |
| 300 | +/// In order to use this function, `glib` must be built with the `log` feature |
| 301 | +/// enabled. |
| 302 | +/// |
| 303 | +/// Use this function if you want to use the log crate as the main logging |
| 304 | +/// output in your application, and want to route all structured logging happening in |
| 305 | +/// glib to the log crate. If you want the opposite, use [`GlibLogger`](struct.GlibLogger.html). |
| 306 | +/// |
| 307 | +/// NOTE: This should never be used when [`GlibLogger`](struct.GlibLogger.html) is |
| 308 | +/// registered as a logger, otherwise a stack overflow will occur. |
| 309 | +/// |
| 310 | +/// ```no_run |
| 311 | +/// glib::log_set_writer_func(glib::rust_log_writer); |
| 312 | +/// ``` |
| 313 | +pub fn rust_log_writer(log_level: glib_log::LogLevel, fields: &[LogField<'_>]) -> LogWriterOutput { |
| 314 | + let lvl = match log_level { |
| 315 | + glib_log::LogLevel::Error | glib_log::LogLevel::Critical => rs_log::Level::Error, |
| 316 | + glib_log::LogLevel::Warning => rs_log::Level::Warn, |
| 317 | + glib_log::LogLevel::Info | glib_log::LogLevel::Message => rs_log::Level::Info, |
| 318 | + glib_log::LogLevel::Debug => rs_log::Level::Debug, |
| 319 | + }; |
| 320 | + |
| 321 | + if lvl > rs_log::STATIC_MAX_LEVEL { |
| 322 | + return LogWriterOutput::Handled; |
| 323 | + } |
| 324 | + |
| 325 | + let mut domain = None::<&str>; |
| 326 | + let mut message = None::<&str>; |
| 327 | + let mut file = None::<&str>; |
| 328 | + let mut line = None::<u32>; |
| 329 | + let mut func = None::<&str>; |
| 330 | + |
| 331 | + for field in fields { |
| 332 | + let Some(value) = field.value_str() else { |
| 333 | + continue; |
| 334 | + }; |
| 335 | + |
| 336 | + match field.key() { |
| 337 | + "GLIB_DOMAIN" => domain = Some(value), |
| 338 | + "MESSAGE" => message = Some(value), |
| 339 | + "CODE_FILE" => file = Some(value), |
| 340 | + "CODE_LINE" => line = value.parse().ok(), |
| 341 | + "CODE_FUNC" => func = Some(value), |
| 342 | + _ => continue, |
| 343 | + }; |
| 344 | + } |
| 345 | + |
| 346 | + if let Some(message) = message { |
| 347 | + let logger = rs_log::logger(); |
| 348 | + let mut record = rs_log::Record::builder(); |
| 349 | + |
| 350 | + #[cfg(feature = "log_kv")] |
| 351 | + let fields = LogFields(fields); |
| 352 | + |
| 353 | + record |
| 354 | + .level(lvl) |
| 355 | + .target(domain.unwrap_or_default()) |
| 356 | + .file(file) |
| 357 | + .line(line) |
| 358 | + .module_path(func); |
| 359 | + |
| 360 | + #[cfg(feature = "log_kv")] |
| 361 | + record.key_values(&fields); |
| 362 | + |
| 363 | + logger.log(&record.args(format_args!("{message}")).build()); |
| 364 | + } |
| 365 | + |
| 366 | + LogWriterOutput::Handled |
266 | 367 | }
|
267 | 368 |
|
268 | 369 | // rustdoc-stripper-ignore-next
|
|
0 commit comments