//! This provides testing of the 'meta-logging' feature, which allows for //! deadlock-free logging within logging formatters. //! //! These tests *will* deadlock if the feature is not enabled, so they're //! disabled by default. #![cfg(feature = "meta-logging-in-format")] use std::{fmt, fs, io, io::prelude::*}; use log::{Level::*, Log}; mod support; use support::manual_log; // in order to actually trigger the situation that deadlocks, we need a custom // Display implementation which performs logging: struct VerboseDisplayThing<'a> { log_copy: &'a dyn Log, msg: &'a str, } impl<'a> fmt::Display for VerboseDisplayThing<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { manual_log( self.log_copy, Debug, format_args!( "VerboseDisplayThing is being displayed! [contents: {}]", self.msg ), ); f.write_str(self.msg) } } #[test] fn file_deadlock() { // Create a temporary directory to put a log file into for testing let temp_log_dir = tempfile::tempdir().expect("Failed to set up temporary directory"); let log_file = temp_log_dir.path().join("test.log"); { let (_max_level, logger) = fern::Dispatch::new() .format(|out, msg, record| out.finish(format_args!("[{}] {}", record.level(), msg))) .chain(io::stdout()) .chain(fern::log_file(log_file).expect("Failed to open log file")) .into_log(); let l = &*logger; manual_log( l, Info, format_args!( "Hello, world! {}", VerboseDisplayThing { log_copy: l, msg: "it's verbose!", } ), ); // ensure all File objects are dropped and OS buffers are flushed. log::logger().flush(); { let contents = { let mut log_read = fs::File::open(temp_log_dir.path().join("test.log")).unwrap(); let mut buf = String::new(); log_read.read_to_string(&mut buf).unwrap(); buf }; assert_eq!( contents, // double logs because we're logging to stdout & the file "[DEBUG] VerboseDisplayThing is being displayed! [contents: it's verbose!]\ \n[DEBUG] VerboseDisplayThing is being displayed! [contents: it's verbose!]\ \n[INFO] Hello, world! it's verbose!\n" ); } } // ensure logger is dropped before temp dir temp_log_dir .close() .expect("Failed to clean up temporary directory"); }