Merge pull request #1127 from matthiasbeyer/libimagrt/logging-to-file

Add multi-destination logging to logger
This commit is contained in:
Matthias Beyer 2017-10-08 19:00:07 +02:00 committed by GitHub
commit 75a8041c0e
2 changed files with 50 additions and 8 deletions

View file

@ -25,6 +25,8 @@ This section contains the changelog from the last release to the next release.
* `imag-view` uses the configuration file now to find the command to call * `imag-view` uses the configuration file now to find the command to call
for viewing the entry. This way one can view the entry in an editor or the for viewing the entry. This way one can view the entry in an editor or the
browser or on the toaster. browser or on the toaster.
* The logger is now able to handle multiple destinations (file and "-" for
stderr)
## 0.4.0 ## 0.4.0

View file

@ -20,6 +20,9 @@
use std::io::Write; use std::io::Write;
use std::io::stderr; use std::io::stderr;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::sync::Arc;
use std::sync::Mutex;
use std::ops::Deref;
use configuration::Configuration; use configuration::Configuration;
use error::RuntimeErrorKind as EK; use error::RuntimeErrorKind as EK;
@ -38,7 +41,7 @@ type Result<T> = ::std::result::Result<T, RE>;
enum LogDestination { enum LogDestination {
Stderr, Stderr,
File(::std::fs::File), File(Arc<Mutex<::std::fs::File>>),
} }
impl Default for LogDestination { impl Default for LogDestination {
@ -163,20 +166,55 @@ impl Log for ImagLogger {
.render(&format!("{}", record.level()), &data) .render(&format!("{}", record.level()), &data)
.unwrap_or_else(|e| format!("Failed rendering logging data: {:?}\n", e)); .unwrap_or_else(|e| format!("Failed rendering logging data: {:?}\n", e));
let log_to_destination = |d: &LogDestination| match d {
&LogDestination::Stderr => {
let _ = write!(stderr(), "{}\n", logtext);
},
&LogDestination::File(ref arc_mutex_logdest) => {
// if there is an error in the lock, we cannot do anything. So we ignore it here.
let _ = arc_mutex_logdest
.deref()
.lock()
.map(|mut logdest| {
write!(logdest, "{}\n", logtext)
});
}
};
// hack to get the right target configuration.
// If there is no element here, we use the empty string which automatically drops through
// to the unwrap_or_else() case
let record_target = record
.target()
.split("::")
.next()
.unwrap_or("");
self.module_settings self.module_settings
.get(record.target()) .get(record_target)
.map(|module_setting| { .map(|module_setting| {
let set = module_setting.enabled && let set = module_setting.enabled &&
module_setting.level.unwrap_or(self.global_loglevel) >= record.level(); module_setting.level.unwrap_or(self.global_loglevel) >= record.level();
if set { if set {
let _ = write!(stderr(), "{}\n", logtext); module_setting.destinations.as_ref().map(|destinations| for d in destinations {
// If there's an error, we cannot do anything, can we?
let _ = log_to_destination(&d);
});
for d in self.global_destinations.iter() {
// If there's an error, we cannot do anything, can we?
let _ = log_to_destination(&d);
}
} }
}) })
.unwrap_or_else(|| { .unwrap_or_else(|| {
if self.global_loglevel >= record.level() { if self.global_loglevel >= record.level() {
// Yes, we log // Yes, we log
let _ = write!(stderr(), "{}\n", logtext); for d in self.global_destinations.iter() {
// If there's an error, we cannot do anything, can we?
let _ = log_to_destination(&d);
}
} }
}); });
} }
@ -230,6 +268,8 @@ fn translate_destination(raw: &str) -> Result<LogDestination> {
.append(true) .append(true)
.create(true) .create(true)
.open(other) .open(other)
.map(Mutex::new)
.map(Arc::new)
.map(LogDestination::File) .map(LogDestination::File)
.chain_err(|| EK::IOLogFileOpenError) .chain_err(|| EK::IOLogFileOpenError)
} }