Skip to content

Commit

Permalink
Dump debug logs to a file rather than stderr
Browse files Browse the repository at this point in the history
Fixes #238

We now use our own `Log` implementation that logs to a file. The log
file is created on demand (on first log) so most of the time there won't
a file created.

Note that default log level is still "error". Given that logging won't
cause glithces in the UI by default now I think it makes sense to keep
error logs enabled always.
  • Loading branch information
osa1 committed Sep 9, 2020
1 parent b802bd3 commit 2a24948
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 48 deletions.
44 changes: 14 additions & 30 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion tiny/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ desktop-notifications = ["libtiny_tui/desktop-notifications"]
[dependencies]
clap = "2.33"
dirs = "1.0.2"
env_logger = { version = "0.7", default-features = false, features = ["humantime"] }
env_logger = { version = "0.7", default-features = false }
futures = { version = "0.3.1", default-features = false }
libtiny_client = { path = "../libtiny_client", default-features = false }
libtiny_logger = { path = "../libtiny_logger" }
Expand Down
91 changes: 91 additions & 0 deletions tiny/src/debug_logging.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
//! This module provides a logger (as in `log` and `env_logger` crates, rather than
//! `libtiny_logger`) implementation for logging to a file rather than stdout/stderr (which is what
//! `env_logger` provides).
//!
//! Some notes regarding implementation:
//!
//! - All IO errors ignored. Once initialized the logger never panics.
//! - TINY_LOG is the env variable used for setting filters.
//! - Filter syntax is unchanged (same as `env_logger` syntax).
//! - Log file is created when logging for the first time.
use env_logger::filter::{self, Filter};
use log::{Log, Record};

use std::fs::File;
use std::io::Write;
use std::mem::replace;
use std::path::PathBuf;
use std::sync::Mutex;

pub(crate) fn init(path: PathBuf) {
let filter = filter::Builder::from_env("TINY_LOG").build();
let sink = Mutex::new(LazyFile::new(path));

log::set_max_level(filter.filter());
log::set_boxed_logger(Box::new(Logger { sink, filter })).unwrap();
}

struct Logger {
sink: Mutex<LazyFile>,
filter: Filter,
}

impl Log for Logger {
fn enabled(&self, metadata: &log::Metadata) -> bool {
self.filter.enabled(metadata)
}

fn log(&self, record: &Record) {
if !self.filter.matches(record) {
return;
}

self.sink.lock().unwrap().with_file(|file| {
let _ = writeln!(
file,
"[{}] {} [{}:{}] {}",
time::strftime("%F %T", &time::now()).unwrap(),
record.level(),
record.file().unwrap_or_default(),
record.line().unwrap_or_default(),
record.args()
);
});
}

fn flush(&self) {}
}

enum LazyFile {
NotOpen(PathBuf),
Open(File),
Error,
}

impl LazyFile {
fn new(path: PathBuf) -> Self {
LazyFile::NotOpen(path)
}

fn with_file<F>(&mut self, f: F)
where
F: Fn(&mut File),
{
let mut file = match replace(self, LazyFile::Error) {
LazyFile::NotOpen(path) => match File::create(path) {
Ok(file) => file,
Err(_) => {
return;
}
},
LazyFile::Open(file) => file,
LazyFile::Error => {
return;
}
};

f(&mut file);
*self = LazyFile::Open(file);
}
}
29 changes: 12 additions & 17 deletions tiny/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod cli;
mod cmd;
mod config;
mod conn;
mod debug_logging;
mod ui;
mod utils;

Expand All @@ -12,7 +13,6 @@ use libtiny_logger::{Logger, LoggerInitError};
use libtiny_tui::{MsgTarget, TUI};
use libtiny_ui::UI;

use std::io::Write;
use std::path::PathBuf;
use std::process::exit;

Expand Down Expand Up @@ -68,28 +68,23 @@ fn main() {
}
}

const DEBUG_LOG_FILE: &str = "tiny_debug_logs.txt";

fn run(
servers: Vec<config::Server>,
defaults: config::Defaults,
config_path: PathBuf,
log_dir: Option<PathBuf>,
) {
env_logger::builder()
.target(env_logger::Target::Stderr)
.format(|buf, record| {
let timestamp = buf.timestamp_seconds();

writeln!(
buf,
"[{}] {} [{}:{}] {}",
timestamp,
record.level(),
record.file().unwrap_or_default(),
record.line().unwrap_or_default(),
record.args()
)
})
.init();
let debug_log_file = match log_dir.as_ref() {
Some(log_dir) => {
let mut log_dir = log_dir.clone();
log_dir.push(DEBUG_LOG_FILE);
log_dir
}
None => DEBUG_LOG_FILE.into(),
};
debug_logging::init(debug_log_file);

// One task for each client to handle IRC events
// One task for TUI events
Expand Down

0 comments on commit 2a24948

Please sign in to comment.