Files

149 lines
4.5 KiB
Rust

use std::str::FromStr;
use fern::colors::{Color, ColoredLevelConfig};
use serde::Serialize;
use serde_repr::{Deserialize_repr, Serialize_repr};
use tauri::Manager;
use time::{format_description, OffsetDateTime};
fn formatted_time() -> String {
// if we fail to obtain local time according to local offset, fallback to utc
let _now = OffsetDateTime::now_local().unwrap_or_else(|_| OffsetDateTime::now_utc());
// if we're running it in the unit test, use the hardcoded value
#[cfg(test)]
let _now = OffsetDateTime::from_unix_timestamp(1666666666).unwrap();
// the unwraps are fine as we know this description is correct
// note: the reason for this very particular format is a very simple one
// it's what we've always been using since we copied it from the example,
// so feel free to update it to whatever
let format =
format_description::parse("[[[year]-[month]-[day]][[[hour]:[minute]:[second]]").unwrap();
_now.format(&format).unwrap()
}
pub fn setup_logging(app_handle: tauri::AppHandle) -> Result<(), log::SetLoggerError> {
let colors = ColoredLevelConfig::new()
.trace(Color::Magenta)
.debug(Color::Blue)
.info(Color::Green)
.warn(Color::Yellow)
.error(Color::Red);
let base_config = fern::Dispatch::new()
.level(global_level())
.filter_lowlevel_external_components()
.show_operations();
let stdout_config = fern::Dispatch::new()
.format(move |out, message, record| {
out.finish(format_args!(
"{} {:5} {} > {}",
formatted_time(),
colors.color(record.level()),
record.target(),
message,
))
})
.chain(std::io::stdout());
let tauri_event_config = fern::Dispatch::new()
.format(move |out, message, record| {
out.finish(format_args!(
"{}[{}] {}",
formatted_time(),
record.target(),
message,
))
})
.chain(fern::Output::call(move |record| {
let msg = LogMessage {
message: record.args().to_string(),
level: record.level().into(),
};
app_handle.emit_all("log://log", msg).unwrap();
}));
base_config
.chain(stdout_config)
.chain(tauri_event_config)
.apply()
}
trait FernExt {
fn show_operations(self) -> Self;
fn filter_lowlevel_external_components(self) -> Self;
}
impl FernExt for fern::Dispatch {
fn show_operations(self) -> Self {
if ::std::env::var("RUST_TRACE_OPERATIONS").is_ok() {
self.level_for("nym_wallet::operations", log::LevelFilter::Trace)
} else {
self
}
}
fn filter_lowlevel_external_components(self) -> Self {
self.level_for("hyper", log::LevelFilter::Warn)
.level_for("tokio_reactor", log::LevelFilter::Warn)
.level_for("reqwest", log::LevelFilter::Warn)
.level_for("mio", log::LevelFilter::Warn)
.level_for("want", log::LevelFilter::Warn)
.level_for("sled", log::LevelFilter::Warn)
.level_for("tungstenite", log::LevelFilter::Warn)
.level_for("tokio_tungstenite", log::LevelFilter::Warn)
.level_for("rustls", log::LevelFilter::Warn)
.level_for("tokio_util", log::LevelFilter::Warn)
}
}
fn global_level() -> log::LevelFilter {
if let Ok(s) = ::std::env::var("RUST_LOG") {
log::LevelFilter::from_str(&s).unwrap_or(log::LevelFilter::Info)
} else {
log::LevelFilter::Info
}
}
#[derive(Debug, Serialize, Clone)]
struct LogMessage {
message: String,
level: LogLevel,
}
// Serialize to u16 instead of strings.
#[derive(Debug, Clone, Deserialize_repr, Serialize_repr)]
#[repr(u16)]
enum LogLevel {
Trace = 1,
Debug,
Info,
Warn,
Error,
}
impl From<log::Level> for LogLevel {
fn from(level: log::Level) -> Self {
match level {
log::Level::Trace => LogLevel::Trace,
log::Level::Debug => LogLevel::Debug,
log::Level::Info => LogLevel::Info,
log::Level::Warn => LogLevel::Warn,
log::Level::Error => LogLevel::Error,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn log_formatting() {
let expected_chrono_formated = "[2022-10-25][02:57:46]".to_string();
let new_time_based = formatted_time();
assert_eq!(new_time_based, expected_chrono_formated)
}
}