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
|
* `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
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue