Skip to content

Commit

Permalink
Add compatibility with multi_log (fixes issue-44).
Browse files Browse the repository at this point in the history
  • Loading branch information
emabee committed Jun 4, 2020
1 parent cf4f032 commit 75946e8
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 54 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Cargo.lock
*.alerts
*.log
*.seclog
*.gz
*.zip
link_to_log
link_to_mt_log
log_files
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,5 @@ libc = {version = "^0.2.50", optional = true}

[dev-dependencies]
serde_derive = "1.0"
version-sync = "0.8"
version-sync = "0.9"
#env_logger = '*' # optionally needed for the performance example
1 change: 0 additions & 1 deletion src/flexi_error.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::log_specification::LogSpecification;
use log;
// use std::backtrace::Backtrace;
use thiserror::Error;

Expand Down
1 change: 0 additions & 1 deletion src/flexi_logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use crate::primary_writer::PrimaryWriter;
use crate::writers::LogWriter;
use crate::LogSpecification;

use log;
#[cfg(feature = "textfilter")]
use regex::Regex;
use std::collections::HashMap;
Expand Down
137 changes: 88 additions & 49 deletions src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,22 @@ impl Logger {
/// # Errors
///
/// Several variants of `FlexiLoggerError` can occur.
pub fn start(mut self) -> Result<ReconfigurationHandle, FlexiLoggerError> {
pub fn start(self) -> Result<ReconfigurationHandle, FlexiLoggerError> {
let (boxed_logger, handle) = self.build()?;
log::set_boxed_logger(boxed_logger)?;
Ok(handle)
}

/// Consumes the Logger object and builds a boxed logger and a `ReconfigurationHandle` for it.
///
/// The returned reconfiguration handle allows updating the log specification programmatically
/// later on, e.g. to intensify logging for (buggy) parts of a (test) program, etc.
/// See [`ReconfigurationHandle`](struct.ReconfigurationHandle.html) for an example.
///
/// # Errors
///
/// Several variants of `FlexiLoggerError` can occur.
pub fn build(mut self) -> Result<(Box<dyn log::Log>, ReconfigurationHandle), FlexiLoggerError> {
let max_level = self.spec.max_level();
let spec = Arc::new(RwLock::new(self.spec));
let other_writers = Arc::new(self.other_writers);
Expand Down Expand Up @@ -555,10 +570,9 @@ impl Logger {
Arc::clone(&other_writers),
);

log::set_boxed_logger(Box::new(flexi_logger))?;
let handle = ReconfigurationHandle::new(spec, primary_writer, other_writers);
handle.reconfigure(max_level);
Ok(handle)
Ok((Box::new(flexi_logger), handle))
}

/// Consumes the Logger object and initializes `flexi_logger` in a way that
Expand Down Expand Up @@ -628,63 +642,88 @@ impl Logger {
specfile: P,
) -> Result<ReconfigurationHandle, FlexiLoggerError> {
// Make logging work, before caring for the specfile
let mut handle = self.start()?;
let handle2 = handle.clone();

let specfile = specfile.as_ref().to_owned();
synchronize_handle_with_specfile(&mut handle, &specfile)?;
let (boxed_logger, handle) = self.build()?;
log::set_boxed_logger(boxed_logger)?;
setup_specfile(specfile, handle.clone())?;
Ok(handle)
}

// Now that the file exists, we can canonicalize the path
let specfile = specfile
.canonicalize()
.map_err(FlexiLoggerError::SpecfileIo)?;
///
/// # Errors
///
/// Several variants of `FlexiLoggerError` can occur.
///
/// # Returns
///
/// A `ReconfigurationHandle` is returned, predominantly to allow using its
/// [`shutdown`](struct.ReconfigurationHandle.html#method.shutdown) method.
#[cfg(feature = "specfile")]
pub fn build_with_specfile<P: AsRef<std::path::Path>>(
self,
specfile: P,
) -> Result<(Box<dyn log::Log>, ReconfigurationHandle), FlexiLoggerError> {
let (boxed_log, handle) = self.build()?;
setup_specfile(specfile, handle.clone())?;
Ok((boxed_log, handle))
}
}

// Watch the parent folder of the specfile, using debounced events
let (tx, rx) = std::sync::mpsc::channel();
let debouncing_delay = std::time::Duration::from_millis(1000);
let mut watcher = watcher(tx, debouncing_delay)?;
watcher.watch(&specfile.parent().unwrap(), RecursiveMode::NonRecursive)?;

// in a separate thread, reread the specfile when it was updated
std::thread::Builder::new()
.name("flexi_logger-specfile-watcher".to_string())
.stack_size(128 * 1024)
.spawn(move || {
let _anchor_for_watcher = watcher; // keep it alive!
loop {
match rx.recv() {
Ok(debounced_event) => {
// println!("got debounced event {:?}", debounced_event);
match debounced_event {
DebouncedEvent::Create(ref path)
| DebouncedEvent::Write(ref path) => {
if path.canonicalize().unwrap() == specfile {
match log_spec_string_from_file(&specfile)
.map_err(FlexiLoggerError::SpecfileIo)
.and_then(|s| LogSpecification::from_toml(&s))
{
Ok(spec) => handle.set_new_spec(spec),
Err(e) => eprintln!(
#[cfg(feature = "specfile")]
fn setup_specfile<P: AsRef<std::path::Path>>(
specfile: P,
mut handle: ReconfigurationHandle,
) -> Result<(), FlexiLoggerError> {
let specfile = specfile.as_ref().to_owned();
synchronize_handle_with_specfile(&mut handle, &specfile)?;

// Now that the file exists, we can canonicalize the path
let specfile = specfile
.canonicalize()
.map_err(FlexiLoggerError::SpecfileIo)?;

// Watch the parent folder of the specfile, using debounced events
let (tx, rx) = std::sync::mpsc::channel();
let debouncing_delay = std::time::Duration::from_millis(1000);
let mut watcher = watcher(tx, debouncing_delay)?;
watcher.watch(&specfile.parent().unwrap(), RecursiveMode::NonRecursive)?;

// in a separate thread, reread the specfile when it was updated
std::thread::Builder::new()
.name("flexi_logger-specfile-watcher".to_string())
.stack_size(128 * 1024)
.spawn(move || {
let _anchor_for_watcher = watcher; // keep it alive!
loop {
match rx.recv() {
Ok(debounced_event) => {
// println!("got debounced event {:?}", debounced_event);
match debounced_event {
DebouncedEvent::Create(ref path) | DebouncedEvent::Write(ref path) => {
if path.canonicalize().unwrap() == specfile {
match log_spec_string_from_file(&specfile)
.map_err(FlexiLoggerError::SpecfileIo)
.and_then(|s| LogSpecification::from_toml(&s))
{
Ok(spec) => handle.set_new_spec(spec),
Err(e) => eprintln!(
"[flexi_logger] rereading the log specification file \
failed with {:?}, \
continuing with previous log specification",
failed with {:?}, \
continuing with previous log specification",
e
),
}
}
}
_event => {}
}
_event => {}
}
Err(e) => {
eprintln!("[flexi_logger] error while watching the specfile: {:?}", e)
}
}
Err(e) => {
eprintln!("[flexi_logger] error while watching the specfile: {:?}", e)
}
}
})?;

Ok(handle2)
}
}
})?;
Ok(())
}

// If the specfile exists, read the file and update the log_spec from it;
Expand Down
3 changes: 1 addition & 2 deletions src/reconfiguration_handle.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::log_specification::LogSpecification;
use crate::primary_writer::PrimaryWriter;
use crate::writers::LogWriter;
use std::borrow::Borrow;
use std::collections::HashMap;
use std::sync::{Arc, RwLock};

Expand Down Expand Up @@ -153,6 +152,6 @@ impl ReconfigurationHandle {
// Allows checking the logs written so far to the writer
#[doc(hidden)]
pub fn validate_logs(&self, expected: &[(&'static str, &'static str, &'static str)]) {
Borrow::<PrimaryWriter>::borrow(&self.primary_writer).validate_logs(expected)
self.primary_writer.validate_logs(expected)
}
}

0 comments on commit 75946e8

Please sign in to comment.