2020-02-29 10:50:15 +01:00
|
|
|
// Copyright: Ankitects Pty Ltd and contributors
|
|
|
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
|
|
|
|
|
|
pub use slog::{debug, error, Logger};
|
|
|
|
use slog::{slog_o, Drain};
|
|
|
|
use slog_async::OverflowStrategy;
|
|
|
|
use std::fs::OpenOptions;
|
2020-03-10 01:33:14 +01:00
|
|
|
use std::{fs, io};
|
|
|
|
|
|
|
|
const LOG_ROTATE_BYTES: u64 = 50 * 1024 * 1024;
|
2020-02-29 10:50:15 +01:00
|
|
|
|
|
|
|
pub(crate) fn terminal() -> Logger {
|
|
|
|
let decorator = slog_term::TermDecorator::new().build();
|
|
|
|
let drain = slog_term::FullFormat::new(decorator).build().fuse();
|
|
|
|
let drain = slog_envlogger::new(drain);
|
|
|
|
let drain = slog_async::Async::new(drain)
|
|
|
|
.chan_size(1_024)
|
|
|
|
.overflow_strategy(OverflowStrategy::Block)
|
|
|
|
.build()
|
|
|
|
.fuse();
|
|
|
|
Logger::root(drain, slog_o!())
|
|
|
|
}
|
|
|
|
|
2020-03-10 01:33:14 +01:00
|
|
|
fn file(path: &str) -> io::Result<Logger> {
|
|
|
|
maybe_rotate_log(path)?;
|
2020-02-29 10:50:15 +01:00
|
|
|
let file = OpenOptions::new().create(true).append(true).open(path)?;
|
|
|
|
|
|
|
|
let decorator = slog_term::PlainSyncDecorator::new(file);
|
|
|
|
let drain = slog_term::FullFormat::new(decorator).build().fuse();
|
|
|
|
let drain = slog_envlogger::new(drain);
|
2020-04-06 07:57:13 +02:00
|
|
|
|
2020-04-07 02:25:47 +02:00
|
|
|
if std::env::var("LOGTERM").is_ok() {
|
|
|
|
// log to the terminal as well
|
|
|
|
let decorator = slog_term::TermDecorator::new().build();
|
|
|
|
let term_drain = slog_term::FullFormat::new(decorator).build().fuse();
|
|
|
|
let term_drain = slog_envlogger::new(term_drain);
|
|
|
|
let joined_drain = slog::Duplicate::new(drain, term_drain).fuse();
|
|
|
|
let drain = slog_async::Async::new(joined_drain)
|
|
|
|
.chan_size(1_024)
|
|
|
|
.overflow_strategy(OverflowStrategy::Block)
|
|
|
|
.build()
|
|
|
|
.fuse();
|
|
|
|
Ok(Logger::root(drain, slog_o!()))
|
|
|
|
} else {
|
|
|
|
let drain = slog_async::Async::new(drain)
|
|
|
|
.chan_size(1_024)
|
|
|
|
.overflow_strategy(OverflowStrategy::Block)
|
|
|
|
.build()
|
|
|
|
.fuse();
|
|
|
|
Ok(Logger::root(drain, slog_o!()))
|
|
|
|
}
|
2020-02-29 10:50:15 +01:00
|
|
|
}
|
|
|
|
|
2020-03-10 01:33:14 +01:00
|
|
|
fn maybe_rotate_log(path: &str) -> io::Result<()> {
|
|
|
|
let current_bytes = match fs::metadata(path) {
|
|
|
|
Ok(meta) => meta.len(),
|
|
|
|
Err(e) => {
|
|
|
|
if e.kind() == io::ErrorKind::NotFound {
|
|
|
|
0
|
|
|
|
} else {
|
|
|
|
return Err(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
if current_bytes < LOG_ROTATE_BYTES {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
|
|
|
let path2 = format!("{}.1", path);
|
|
|
|
let path3 = format!("{}.2", path);
|
|
|
|
|
|
|
|
// if a rotated file already exists, rename it
|
|
|
|
if let Err(e) = fs::rename(&path2, &path3) {
|
|
|
|
if e.kind() != io::ErrorKind::NotFound {
|
|
|
|
return Err(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// and rotate the primary log
|
|
|
|
fs::rename(path, path2)
|
|
|
|
}
|
|
|
|
|
2020-02-29 10:50:15 +01:00
|
|
|
/// Get a logger, logging to a file if a path was provided, otherwise terminal.
|
2020-03-10 01:33:14 +01:00
|
|
|
pub(crate) fn default_logger(path: Option<&str>) -> io::Result<Logger> {
|
2020-02-29 10:50:15 +01:00
|
|
|
Ok(match path {
|
|
|
|
Some(path) => file(path)?,
|
|
|
|
None => terminal(),
|
|
|
|
})
|
|
|
|
}
|