Add multi-destination logging to logger
The logger was not able to handle multiple destinations before. Now it is possible for the logger. The file must be held behind an Arc<Mutex<_>> so we can use the logging from multiple threads but also because we need to borrow mutably, so that bit changes whith this commit.
This commit is contained in:
parent
e5155cacca
commit
f266791142
2 changed files with 50 additions and 8 deletions
|
@ -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
|
||||
for viewing the entry. This way one can view the entry in an editor or the
|
||||
browser or on the toaster.
|
||||
* The logger is now able to handle multiple destinations (file and "-" for
|
||||
stderr)
|
||||
|
||||
## 0.4.0
|
||||
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
use std::io::Write;
|
||||
use std::io::stderr;
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use std::ops::Deref;
|
||||
|
||||
use configuration::Configuration;
|
||||
use error::RuntimeErrorKind as EK;
|
||||
|
@ -38,7 +41,7 @@ type Result<T> = ::std::result::Result<T, RE>;
|
|||
|
||||
enum LogDestination {
|
||||
Stderr,
|
||||
File(::std::fs::File),
|
||||
File(Arc<Mutex<::std::fs::File>>),
|
||||
}
|
||||
|
||||
impl Default for LogDestination {
|
||||
|
@ -163,22 +166,57 @@ impl Log for ImagLogger {
|
|||
.render(&format!("{}", record.level()), &data)
|
||||
.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
|
||||
.get(record.target())
|
||||
.get(record_target)
|
||||
.map(|module_setting| {
|
||||
let set = module_setting.enabled &&
|
||||
module_setting.level.unwrap_or(self.global_loglevel) >= record.level();
|
||||
|
||||
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(|| {
|
||||
if self.global_loglevel >= record.level() {
|
||||
// Yes, we log
|
||||
let _ = write!(stderr(), "{}\n", logtext);
|
||||
.unwrap_or_else(|| {
|
||||
if self.global_loglevel >= record.level() {
|
||||
// Yes, we log
|
||||
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)
|
||||
.create(true)
|
||||
.open(other)
|
||||
.map(Mutex::new)
|
||||
.map(Arc::new)
|
||||
.map(LogDestination::File)
|
||||
.chain_err(|| EK::IOLogFileOpenError)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue