refactor: keep fern [skip ci]

pull/96/head
Lucas Nogueira 2 years ago
parent fa44de7440
commit bbdabbd64d
No known key found for this signature in database
GPG Key ID: FFEA6C72E73482F1

@ -18,8 +18,6 @@ serde_repr = "0.1"
byte-unit = "4.0" byte-unit = "4.0"
log = { workspace = true, features = ["kv_unstable"] } log = { workspace = true, features = ["kv_unstable"] }
time = { version = "0.3", features = ["formatting"] } time = { version = "0.3", features = ["formatting"] }
[target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
fern = "0.6" fern = "0.6"
[target."cfg(target_os = \"android\")".dependencies] [target."cfg(target_os = \"android\")".dependencies]

@ -2,34 +2,26 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#[cfg(desktop)]
use fern::FormatCallback; use fern::FormatCallback;
use log::LevelFilter;
use log::{logger, RecordBuilder}; use log::{logger, RecordBuilder};
use log::{LevelFilter, Record};
use serde::Serialize; use serde::Serialize;
use serde_repr::{Deserialize_repr, Serialize_repr}; use serde_repr::{Deserialize_repr, Serialize_repr};
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashMap; use std::collections::HashMap;
use std::{iter::FromIterator, path::PathBuf}; use std::{
fmt::Arguments,
fs::{self, File},
iter::FromIterator,
path::{Path, PathBuf},
};
use tauri::{ use tauri::{
plugin::{self, TauriPlugin}, plugin::{self, TauriPlugin},
Runtime, Manager, Runtime,
}; };
#[cfg(desktop)]
use desktop::*;
#[cfg(desktop)]
pub use fern; pub use fern;
#[cfg(desktop)]
mod desktop {
pub use std::{
fs::{self, File},
path::Path,
};
pub use tauri::Manager;
}
const DEFAULT_MAX_FILE_SIZE: u128 = 40000; const DEFAULT_MAX_FILE_SIZE: u128 = 40000;
const DEFAULT_ROTATION_STRATEGY: RotationStrategy = RotationStrategy::KeepOne; const DEFAULT_ROTATION_STRATEGY: RotationStrategy = RotationStrategy::KeepOne;
const DEFAULT_LOG_TARGETS: [LogTarget; 2] = [LogTarget::Stdout, LogTarget::LogDir]; const DEFAULT_LOG_TARGETS: [LogTarget; 2] = [LogTarget::Stdout, LogTarget::LogDir];
@ -151,41 +143,31 @@ fn log(
} }
pub struct Builder { pub struct Builder {
#[cfg(desktop)]
dispatch: fern::Dispatch, dispatch: fern::Dispatch,
rotation_strategy: RotationStrategy, rotation_strategy: RotationStrategy,
max_file_size: u128, max_file_size: u128,
targets: Vec<LogTarget>, targets: Vec<LogTarget>,
level_filter: Option<LevelFilter>,
levels: Vec<(Cow<'static, str>, log::LevelFilter)>,
} }
impl Default for Builder { impl Default for Builder {
fn default() -> Self { fn default() -> Self {
#[cfg(desktop)] let format =
let dispatch = { time::format_description::parse("[[[year]-[month]-[day]][[[hour]:[minute]:[second]]")
let format = time::format_description::parse( .unwrap();
"[[[year]-[month]-[day]][[[hour]:[minute]:[second]]", let dispatch = fern::Dispatch::new().format(move |out, message, record| {
) out.finish(format_args!(
.unwrap(); "{}[{}][{}] {}",
fern::Dispatch::new().format(move |out, message, record| { time::OffsetDateTime::now_utc().format(&format).unwrap(),
out.finish(format_args!( record.target(),
"{}[{}][{}] {}", record.level(),
time::OffsetDateTime::now_utc().format(&format).unwrap(), message
record.target(), ))
record.level(), });
message
))
})
};
Self { Self {
#[cfg(desktop)]
dispatch, dispatch,
rotation_strategy: DEFAULT_ROTATION_STRATEGY, rotation_strategy: DEFAULT_ROTATION_STRATEGY,
max_file_size: DEFAULT_MAX_FILE_SIZE, max_file_size: DEFAULT_MAX_FILE_SIZE,
targets: DEFAULT_LOG_TARGETS.into(), targets: DEFAULT_LOG_TARGETS.into(),
level_filter: None,
levels: Vec::new(),
} }
} }
} }
@ -205,37 +187,24 @@ impl Builder {
self self
} }
#[cfg(desktop)]
pub fn format<F>(mut self, formatter: F) -> Self pub fn format<F>(mut self, formatter: F) -> Self
where where
F: Fn(FormatCallback, &std::fmt::Arguments, &log::Record) + Sync + Send + 'static, F: Fn(FormatCallback, &Arguments, &Record) + Sync + Send + 'static,
{ {
self.dispatch = self.dispatch.format(formatter); self.dispatch = self.dispatch.format(formatter);
self self
} }
pub fn level(mut self, level_filter: impl Into<LevelFilter>) -> Self { pub fn level(mut self, level_filter: impl Into<LevelFilter>) -> Self {
self.level_filter.replace(level_filter.into()); self.dispatch = self.dispatch.level(level_filter.into());
self self
} }
pub fn level_for(mut self, module: impl Into<Cow<'static, str>>, level: LevelFilter) -> Self { pub fn level_for(mut self, module: impl Into<Cow<'static, str>>, level: LevelFilter) -> Self {
let module = module.into(); self.dispatch = self.dispatch.level_for(module, level);
if let Some((index, _)) = self
.levels
.iter()
.enumerate()
.find(|&(_, &(ref name, _))| name == &module)
{
self.levels.remove(index);
}
self.levels.push((module, level));
self self
} }
#[cfg(desktop)]
pub fn filter<F>(mut self, filter: F) -> Self pub fn filter<F>(mut self, filter: F) -> Self
where where
F: Fn(&log::Metadata) -> bool + Send + Sync + 'static, F: Fn(&log::Metadata) -> bool + Send + Sync + 'static,
@ -254,7 +223,7 @@ impl Builder {
self self
} }
#[cfg(all(desktop, feature = "colored"))] #[cfg(feature = "colored")]
pub fn with_colors(self, colors: fern::colors::ColoredLevelConfig) -> Self { pub fn with_colors(self, colors: fern::colors::ColoredLevelConfig) -> Self {
let format = let format =
time::format_description::parse("[[[year]-[month]-[day]][[[hour]:[minute]:[second]]") time::format_description::parse("[[[year]-[month]-[day]][[[hour]:[minute]:[second]]")
@ -270,149 +239,106 @@ impl Builder {
}) })
} }
pub fn build<R: Runtime>(#[allow(unused_mut)] mut self) -> TauriPlugin<R> { pub fn build<R: Runtime>(mut self) -> TauriPlugin<R> {
#[cfg(desktop)]
{
if let Some(level) = self.level_filter {
self.dispatch = self.dispatch.level(level);
}
for (module, level) in self.levels {
self.dispatch = self.dispatch.level_for(module, level);
}
}
plugin::Builder::new("log") plugin::Builder::new("log")
.invoke_handler(tauri::generate_handler![log]) .invoke_handler(tauri::generate_handler![log])
.setup(move |app_handle| { .setup(move |app_handle| {
#[cfg(target_os = "ios")] let app_name = &app_handle.package_info().name;
{
let mut subsystem = String::new(); // setup targets
let identifier = &app_handle.config().tauri.bundle.identifier; for target in &self.targets {
let s = identifier.split('.'); let logger = match target {
let last = s.clone().count() - 1; #[cfg(target_os = "android")]
for (i, w) in s.enumerate() { LogTarget::Stdout | LogTarget::Stderr => {
if i != last { fern::Output::call(android_logger::log)
subsystem.push_str(w);
subsystem.push('.');
}
}
subsystem.push_str(&app_handle.package_info().crate_name);
let mut logger = oslog::OsLogger::new(&subsystem);
logger =
logger.level_filter(self.level_filter.unwrap_or(log::LevelFilter::Trace));
for (module, level) in self.levels {
logger = logger.category_level_filter(&module, level);
}
logger.init()?;
}
#[cfg(target_os = "android")]
{
let mut logger = android_logger::Config::default();
if let Some(level_filter) = self.level_filter {
if let Some(level) = level_filter.to_level() {
logger = logger.with_min_level(level);
} }
} else { #[cfg(target_os = "ios")]
logger = logger.with_min_level(log::Level::Trace); LogTarget::Stdout | LogTarget::Stderr => {
} use std::{collections::HashMap, sync::Mutex};
if !self.levels.is_empty() { let loggers: Mutex<HashMap<String, oslog::OsLog>> = Default::default();
let mut filter = android_logger::FilterBuilder::new(); let mut subsystem = String::new();
for (module, level) in self.levels { let identifier = &app_handle.config().tauri.bundle.identifier;
filter.filter_module(&module, level); let s = identifier.split('.');
} let last = s.clone().count() - 1;
logger = logger.with_filter(filter.build()); for (i, w) in s.enumerate() {
} if i != last {
println!( subsystem.push_str(w);
"with tag {}", subsystem.push('.');
app_handle
.config()
.tauri
.bundle
.identifier
.split('.')
.rev()
.next()
.unwrap(),
);
android_logger::init_once(
logger.with_tag(
app_handle
.config()
.tauri
.bundle
.identifier
.split('.')
.rev()
.next()
.unwrap(),
),
);
}
#[cfg(desktop)]
{
let app_name = &app_handle.package_info().name;
// setup targets
for target in &self.targets {
self.dispatch = self.dispatch.chain(match target {
LogTarget::Stdout => fern::Output::from(std::io::stdout()),
LogTarget::Stderr => fern::Output::from(std::io::stderr()),
LogTarget::Folder(path) => {
if !path.exists() {
fs::create_dir_all(path).unwrap();
} }
fern::log_file(get_log_file_path(
&path,
app_name,
&self.rotation_strategy,
self.max_file_size,
)?)?
.into()
} }
LogTarget::LogDir => { subsystem.push_str(&app_handle.package_info().crate_name);
let path = app_handle.path_resolver().app_log_dir().unwrap();
if !path.exists() {
fs::create_dir_all(&path).unwrap();
}
fern::log_file(get_log_file_path( fern::Output::call(move |record| {
&path, let mut loggers = loggers.lock().unwrap();
app_name, let pair =
&self.rotation_strategy, loggers.entry(record.target().into()).or_insert_with(|| {
self.max_file_size, oslog::OsLog::new(&subsystem, record.target())
)?)? });
.into()
let message = format!("{}", record.args());
(*pair).with_level(record.level().into(), &message);
});
}
#[cfg(desktop)]
LogTarget::Stdout => std::io::stdout().into(),
#[cfg(desktop)]
LogTarget::Stderr => std::io::stderr().into(),
LogTarget::Folder(path) => {
if !path.exists() {
fs::create_dir_all(path).unwrap();
} }
LogTarget::Webview => {
let app_handle = app_handle.clone();
fern::Output::call(move |record| { fern::log_file(get_log_file_path(
let payload = RecordPayload { &path,
message: record.args().to_string(), app_name,
level: record.level().into(), &self.rotation_strategy,
}; self.max_file_size,
let app_handle = app_handle.clone(); )?)?
tauri::async_runtime::spawn(async move { .into()
app_handle.emit_all("log://log", payload).unwrap(); }
}); #[cfg(mobile)]
}) LogTarget::LogDir => continue,
#[cfg(desktop)]
LogTarget::LogDir => {
let path = app_handle.path_resolver().app_log_dir().unwrap();
if !path.exists() {
fs::create_dir_all(&path).unwrap();
} }
});
}
self.dispatch.apply()?; fern::log_file(get_log_file_path(
&path,
app_name,
&self.rotation_strategy,
self.max_file_size,
)?)?
.into()
}
LogTarget::Webview => {
let app_handle = app_handle.clone();
fern::Output::call(move |record| {
let payload = RecordPayload {
message: record.args().to_string(),
level: record.level().into(),
};
let app_handle = app_handle.clone();
tauri::async_runtime::spawn(async move {
app_handle.emit_all("log://log", payload).unwrap();
});
})
}
};
self.dispatch = self.dispatch.chain(logger);
} }
self.dispatch.apply()?;
Ok(()) Ok(())
}) })
.build() .build()
} }
} }
#[cfg(desktop)]
fn get_log_file_path( fn get_log_file_path(
dir: &impl AsRef<Path>, dir: &impl AsRef<Path>,
app_name: &str, app_name: &str,

Loading…
Cancel
Save