Replace logging backend to log4rs and add log rotation (#1789)

* Replace logging backend to flexi-logger and add log rotation
* Changed flexi_logger to log4rs
* Disable logging level filtering in Root logger
* Support different logging levels for file and stdout
* Don't log messages from modules other than Grin-related
* Fix formatting
* Place backed up compressed log copies into log file directory
* Increase default log file size to 16 MiB
* Add comment to config file on log_max_size option
This commit is contained in:
eupn
2018-10-21 23:30:56 +03:00
committed by Ignotus Peverell
parent 0852b0c4cf
commit 1195071f5b
83 changed files with 582 additions and 897 deletions
+2 -3
View File
@@ -13,9 +13,8 @@ lazy_static = "1"
rand = "0.5"
serde = "1"
serde_derive = "1"
slog = { version = "~2.3", features = ["max_level_trace", "release_max_level_trace"] }
slog-term = "~2.4"
slog-async = "~2.3"
log4rs = { version = "0.8.1", features = ["rolling_file_appender", "compound_policy", "size_trigger", "fixed_window_roller"] }
log = "0.4"
walkdir = "2"
zip = "0.4"
parking_lot = {version = "0.6"}
+3 -5
View File
@@ -26,10 +26,8 @@ extern crate base64;
extern crate byteorder;
extern crate rand;
#[macro_use]
extern crate slog;
extern crate slog_async;
extern crate slog_term;
extern crate log;
extern crate log4rs;
#[macro_use]
extern crate lazy_static;
@@ -48,7 +46,7 @@ pub extern crate secp256k1zkp as secp;
// Logging related
pub mod logger;
pub use logger::{init_logger, init_test_logger, LOGGER};
pub use logger::{init_logger, init_test_logger};
// Static secp instance
pub mod secp_static;
+119 -59
View File
@@ -12,10 +12,6 @@
// limitations under the License.
//! Logging wrapper to be used throughout all crates in the workspace
use slog::{Discard, Drain, Duplicate, Level, LevelFilter, Logger};
use slog_async;
use slog_term;
use std::fs::OpenOptions;
use std::ops::Deref;
use Mutex;
@@ -24,14 +20,27 @@ use std::{panic, thread};
use types::{LogLevel, LoggingConfig};
fn convert_log_level(in_level: &LogLevel) -> Level {
use log::{LevelFilter, Record};
use log4rs;
use log4rs::append::console::ConsoleAppender;
use log4rs::append::file::FileAppender;
use log4rs::append::rolling_file::{
policy::compound::roll::fixed_window::FixedWindowRoller,
policy::compound::trigger::size::SizeTrigger, policy::compound::CompoundPolicy,
RollingFileAppender,
};
use log4rs::append::Append;
use log4rs::config::{Appender, Config, Root};
use log4rs::encode::pattern::PatternEncoder;
use log4rs::filter::{threshold::ThresholdFilter, Filter, Response};
fn convert_log_level(in_level: &LogLevel) -> LevelFilter {
match *in_level {
LogLevel::Info => Level::Info,
LogLevel::Critical => Level::Critical,
LogLevel::Warning => Level::Warning,
LogLevel::Debug => Level::Debug,
LogLevel::Trace => Level::Trace,
LogLevel::Error => Level::Error,
LogLevel::Info => LevelFilter::Info,
LogLevel::Warning => LevelFilter::Warn,
LogLevel::Debug => LevelFilter::Debug,
LogLevel::Trace => LevelFilter::Trace,
LogLevel::Error => LevelFilter::Error,
}
}
@@ -43,60 +52,115 @@ lazy_static! {
static ref TUI_RUNNING: Mutex<bool> = Mutex::new(false);
/// Static Logging configuration, should only be set once, before first logging call
static ref LOGGING_CONFIG: Mutex<LoggingConfig> = Mutex::new(LoggingConfig::default());
}
/// And a static reference to the logger itself, accessible from all crates
pub static ref LOGGER: Logger = {
let was_init = WAS_INIT.lock().clone();
let config = LOGGING_CONFIG.lock();
let slog_level_stdout = convert_log_level(&config.stdout_log_level);
let slog_level_file = convert_log_level(&config.file_log_level);
if config.tui_running.is_some() && config.tui_running.unwrap() {
let mut tui_running_ref = TUI_RUNNING.lock();
*tui_running_ref = true;
/// This filter is rejecting messages that doesn't start with "grin"
/// in order to save log space for only Grin-related records
#[derive(Debug)]
struct GrinFilter;
impl Filter for GrinFilter {
fn filter(&self, record: &Record) -> Response {
if let Some(module_path) = record.module_path() {
if module_path.starts_with("grin") {
return Response::Neutral;
}
}
//Terminal output drain
let terminal_decorator = slog_term::TermDecorator::new().build();
let terminal_drain = slog_term::FullFormat::new(terminal_decorator).build().fuse();
let terminal_drain = LevelFilter::new(terminal_drain, slog_level_stdout).fuse();
let mut terminal_drain = slog_async::Async::new(terminal_drain).build().fuse();
if !config.log_to_stdout || !was_init {
terminal_drain = slog_async::Async::new(Discard{}).build().fuse();
}
if config.log_to_file && was_init {
//File drain
let file = OpenOptions::new()
.create(true)
.write(true)
.append(config.log_file_append)
.truncate(false)
.open(&config.log_file_path)
.unwrap();
let file_decorator = slog_term::PlainDecorator::new(file);
let file_drain = slog_term::FullFormat::new(file_decorator).build().fuse();
let file_drain = LevelFilter::new(file_drain, slog_level_file).fuse();
let file_drain_final = slog_async::Async::new(file_drain).build().fuse();
let composite_drain = Duplicate::new(terminal_drain, file_drain_final).fuse();
Logger::root(composite_drain, o!())
} else {
Logger::root(terminal_drain, o!())
}
};
Response::Reject
}
}
/// Initialize the logger with the given configuration
pub fn init_logger(config: Option<LoggingConfig>) {
if let Some(c) = config {
let mut config_ref = LOGGING_CONFIG.lock();
*config_ref = c.clone();
let level_stdout = convert_log_level(&c.stdout_log_level);
let level_file = convert_log_level(&c.file_log_level);
let level_minimum;
// Determine minimum logging level for Root logger
if level_stdout > level_file {
level_minimum = level_stdout;
} else {
level_minimum = level_file;
}
// Start logger
let stdout = ConsoleAppender::builder()
.encoder(Box::new(PatternEncoder::default()))
.build();
let mut root = Root::builder();
let mut appenders = vec![];
if c.log_to_stdout {
let filter = Box::new(ThresholdFilter::new(level_stdout));
appenders.push(
Appender::builder()
.filter(filter)
.filter(Box::new(GrinFilter))
.build("stdout", Box::new(stdout)),
);
root = root.appender("stdout");
}
if c.log_to_file {
// If maximum log size is specified, use rolling file appender
// or use basic one otherwise
let filter = Box::new(ThresholdFilter::new(level_file));
let file: Box<Append> = {
if let Some(size) = c.log_max_size {
let roller = FixedWindowRoller::builder()
.build(&format!("{}.{{}}.gz", c.log_file_path), 32)
.unwrap();
let trigger = SizeTrigger::new(size);
let policy = CompoundPolicy::new(Box::new(trigger), Box::new(roller));
Box::new(
RollingFileAppender::builder()
.append(c.log_file_append)
.encoder(Box::new(PatternEncoder::new("{d} {l} {M} - {m}{n}")))
.build(c.log_file_path, Box::new(policy))
.unwrap(),
)
} else {
Box::new(
FileAppender::builder()
.append(c.log_file_append)
.encoder(Box::new(PatternEncoder::new("{d} {l} {M} - {m}{n}")))
.build(c.log_file_path)
.unwrap(),
)
}
};
appenders.push(
Appender::builder()
.filter(filter)
.filter(Box::new(GrinFilter))
.build("file", file),
);
root = root.appender("file");
}
let config = Config::builder()
.appenders(appenders)
.build(root.build(level_minimum))
.unwrap();
let _ = log4rs::init_config(config).unwrap();
info!(
"log4rs is initialized, file level: {:?}, stdout level: {:?}, min. level: {:?}",
level_file, level_stdout, level_minimum
);
// Logger configuration successfully injected into LOGGING_CONFIG...
let mut was_init_ref = WAS_INIT.lock();
*was_init_ref = true;
// .. allow logging, having ensured that paths etc are immutable
}
send_panic_to_log();
}
@@ -134,7 +198,6 @@ fn send_panic_to_log() {
match info.location() {
Some(location) => {
error!(
LOGGER,
"\nthread '{}' panicked at '{}': {}:{}{:?}\n\n",
thread,
msg,
@@ -143,10 +206,7 @@ fn send_panic_to_log() {
backtrace
);
}
None => error!(
LOGGER,
"thread '{}' panicked at '{}'{:?}", thread, msg, backtrace
),
None => error!("thread '{}' panicked at '{}'{:?}", thread, msg, backtrace),
}
//also print to stderr
let tui_running = TUI_RUNNING.lock().clone();
+4 -3
View File
@@ -14,11 +14,9 @@
//! Logging configuration types
/// Log level types, as slog's don't implement serialize
/// Log level types
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum LogLevel {
/// Critical
Critical,
/// Error
Error,
/// Warning
@@ -46,6 +44,8 @@ pub struct LoggingConfig {
pub log_file_path: String,
/// Whether to append to log or replace
pub log_file_append: bool,
/// Size of the log in bytes to rotate over (optional)
pub log_max_size: Option<u64>,
/// Whether the tui is running (optional)
pub tui_running: Option<bool>,
}
@@ -59,6 +59,7 @@ impl Default for LoggingConfig {
file_log_level: LogLevel::Debug,
log_file_path: String::from("grin.log"),
log_file_append: true,
log_max_size: Some(1024 * 1024 * 16), // 16 megabytes default
tui_running: None,
}
}