Last active
November 3, 2020 03:39
-
-
Save thebluefish/6346dda79d898f7bcd4ae58bc868551c to your computer and use it in GitHub Desktop.
A simple fern-based logging implementation demonstrating formatting for multiple outputs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use colored::*; | |
use log::*; | |
use std::{fs, thread::ThreadId}; | |
/// Please ignore the evil that is parsing debug output | |
fn parse_thread_id(id: &ThreadId) -> String { | |
let id_str = format!("{:?}", id); | |
let parsed = (|| { | |
let start_idx = id_str.find('(')?; | |
let end_idx = id_str.rfind(')')?; | |
Some(id_str[start_idx+1..end_idx].to_owned()) | |
})(); | |
parsed.unwrap_or(id_str) | |
} | |
/// app_name **must** match Cargo.toml's package.name, or else app-level logging won't work properly! | |
pub fn setup(app_name: impl AsRef<str>) -> Result<(), fern::InitError> { | |
let log_root = format_args!("logs/{}", app_name.as_ref()).to_string(); | |
fs::create_dir_all(log_root.clone())?; | |
log_panics::init(); | |
// Pretty print for stdout | |
// Logging lib errors and all app logs | |
let stdout_dispatch = fern::Dispatch::new() | |
.format(|out, message, record| { | |
out.finish(format_args!( | |
"{}[{}][{}][{}] {}", | |
chrono::Utc::now().format("[%Y-%m-%d][%H:%M:%S]"), | |
parse_thread_id(&std::thread::current().id()), | |
match record.level() { | |
Level::Error => format!("{}", record.level()).red(), | |
Level::Warn => format!("{}", record.level()).red().italic(), | |
Level::Info => format!("{}", record.level()).cyan(), | |
Level::Debug => format!("{}", record.level()).yellow(), | |
Level::Trace => format!("{}", record.level()).normal(), | |
}, | |
record.target(), | |
message | |
)) | |
}) | |
.level(LevelFilter::Error) | |
.level_for(app_name.as_ref().to_string(), LevelFilter::Trace) | |
.chain(std::io::stdout()); | |
let log_file_root = format!("{}/{}.{}", log_root.clone(), app_name.as_ref().to_string(), chrono::Utc::now().format("%Y_%m_%d")); | |
// Produce a file that contains all app logs | |
let out_file_dispatch = fern::Dispatch::new() | |
.level(LevelFilter::Off) | |
.level_for(app_name.as_ref().to_string(), LevelFilter::Trace) | |
.chain(fern::log_file(format!("{}.log", log_file_root))?); | |
// Produce a separate file that contains all debug and error logs | |
let debug_file_dispatch = fern::Dispatch::new() | |
.level(LevelFilter::Debug) | |
.chain(fern::log_file(format!("{}.debug.log", log_file_root))?); | |
// Produce a separate file that contains all logs | |
let full_file_dispatch = fern::Dispatch::new() | |
.chain(fern::log_file(format!("{}.full.log", log_file_root))?); | |
let files_dispatch = fern::Dispatch::new() | |
// Format for files | |
.format(|out, message, record| { | |
out.finish(format_args!( | |
"{}[{}][{}][{}] {}", | |
chrono::Utc::now().format("[%Y-%m-%d %H:%M:%S]"), | |
parse_thread_id(&std::thread::current().id()), | |
record.level(), | |
record.target(), | |
message | |
)) | |
}) | |
.chain(out_file_dispatch) | |
.chain(debug_file_dispatch) | |
.chain(full_file_dispatch) | |
; | |
// This is the main logging dispatch | |
fern::Dispatch::new() | |
.chain(stdout_dispatch) | |
.chain(files_dispatch) | |
.apply()?; | |
Ok(()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment