Files
clash-proxy/src-tauri/src/utils/logging.rs
2025-10-01 10:17:08 +08:00

248 lines
6.9 KiB
Rust

cfg_if::cfg_if! {
if #[cfg(feature = "tauri-dev")] {
use std::fmt;
} else {
#[cfg(feature = "verge-dev")]
use nu_ansi_term::Color;
use std::{fmt, io::Write, thread};
use flexi_logger::DeferredNow;
use log::{LevelFilter, Record};
use flexi_logger::filter::LogLineFilter;
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Type {
Cmd,
Core,
Config,
Setup,
System,
Service,
Hotkey,
Window,
Tray,
Timer,
Frontend,
Backup,
Lightweight,
Network,
ProxyMode,
// Ipc,
// Cache,
ClashVergeRev,
}
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Type::Cmd => write!(f, "[Cmd]"),
Type::Core => write!(f, "[Core]"),
Type::Config => write!(f, "[Config]"),
Type::Setup => write!(f, "[Setup]"),
Type::System => write!(f, "[System]"),
Type::Service => write!(f, "[Service]"),
Type::Hotkey => write!(f, "[Hotkey]"),
Type::Window => write!(f, "[Window]"),
Type::Tray => write!(f, "[Tray]"),
Type::Timer => write!(f, "[Timer]"),
Type::Frontend => write!(f, "[Frontend]"),
Type::Backup => write!(f, "[Backup]"),
Type::Lightweight => write!(f, "[Lightweight]"),
Type::Network => write!(f, "[Network]"),
Type::ProxyMode => write!(f, "[ProxMode]"),
// Type::Ipc => write!(f, "[IPC]"),
// Type::Cache => write!(f, "[Cache]"),
Type::ClashVergeRev => write!(f, "[ClashVergeRev]"),
}
}
}
#[macro_export]
macro_rules! error {
($result: expr) => {
log::error!(target: "app", "{}", $result);
};
}
#[macro_export]
macro_rules! log_err {
($result: expr) => {
if let Err(err) = $result {
log::error!(target: "app", "{err}");
}
};
($result: expr, $err_str: expr) => {
if let Err(_) = $result {
log::error!(target: "app", "{}", $err_str);
}
};
}
#[macro_export]
macro_rules! trace_err {
($result: expr, $err_str: expr) => {
if let Err(err) = $result {
log::trace!(target: "app", "{}, err {}", $err_str, err);
}
}
}
/// wrap the anyhow error
/// transform the error to String
#[macro_export]
macro_rules! wrap_err {
// Case 1: Future<Result<T, E>>
($stat:expr, async) => {{
match $stat.await {
Ok(a) => Ok(a),
Err(err) => {
log::error!(target: "app", "{}", err);
Err(err.to_string())
}
}
}};
// Case 2: Result<T, E>
($stat:expr) => {{
match $stat {
Ok(a) => Ok(a),
Err(err) => {
log::error!(target: "app", "{}", err);
Err(err.to_string())
}
}
}};
}
#[macro_export]
macro_rules! logging {
// 带 println 的版本(支持格式化参数)
($level:ident, $type:expr, true, $($arg:tt)*) => {
// We dont need println here anymore
// println!("{} {}", $type, format_args!($($arg)*));
log::$level!(target: "app", "{} {}", $type, format_args!($($arg)*));
};
// 带 println 的版本(使用 false 明确不打印)
($level:ident, $type:expr, false, $($arg:tt)*) => {
log::$level!(target: "app", "{} {}", $type, format_args!($($arg)*));
};
// 不带 print 参数的版本(默认不打印)
($level:ident, $type:expr, $($arg:tt)*) => {
log::$level!(target: "app", "{} {}", $type, format_args!($($arg)*));
};
}
#[macro_export]
macro_rules! logging_error {
// 1. 处理 Result<T, E>,带打印控制
($type:expr, $print:expr, $expr:expr) => {
match $expr {
Ok(_) => {},
Err(err) => {
if $print {
println!("[{}] Error: {}", $type, err);
}
log::error!(target: "app", "[{}] {}", $type, err);
}
}
};
// 2. 处理 Result<T, E>,默认不打印
($type:expr, $expr:expr) => {
if let Err(err) = $expr {
log::error!(target: "app", "[{}] {}", $type, err);
}
};
// 3. 处理格式化字符串,带打印控制
($type:expr, $print:expr, $fmt:literal $(, $arg:expr)*) => {
if $print {
println!("[{}] {}", $type, format_args!($fmt $(, $arg)*));
}
log::error!(target: "app", "[{}] {}", $type, format_args!($fmt $(, $arg)*));
};
// 4. 处理格式化字符串,不带 bool 时,默认 `false`
($type:expr, $fmt:literal $(, $arg:expr)*) => {
logging_error!($type, false, $fmt $(, $arg)*);
};
}
#[cfg(not(feature = "tauri-dev"))]
static IGNORE_MODULES: &[&str] = &["tauri", "wry"];
#[cfg(not(feature = "tauri-dev"))]
pub struct NoExternModule;
#[cfg(not(feature = "tauri-dev"))]
impl LogLineFilter for NoExternModule {
fn write(
&self,
now: &mut DeferredNow,
record: &Record,
log_line_writer: &dyn flexi_logger::filter::LogLineWriter,
) -> std::io::Result<()> {
let module_path = record.module_path().unwrap_or_default();
if IGNORE_MODULES.iter().any(|m| module_path.starts_with(m)) {
Ok(())
} else {
log_line_writer.write(now, record)
}
}
}
#[cfg(not(feature = "tauri-dev"))]
pub fn get_log_level(log_level: &LevelFilter) -> String {
#[cfg(feature = "verge-dev")]
match log_level {
LevelFilter::Off => Color::Fixed(8).paint("OFF").to_string(),
LevelFilter::Error => Color::Red.paint("ERROR").to_string(),
LevelFilter::Warn => Color::Yellow.paint("WARN ").to_string(),
LevelFilter::Info => Color::Green.paint("INFO ").to_string(),
LevelFilter::Debug => Color::Blue.paint("DEBUG").to_string(),
LevelFilter::Trace => Color::Purple.paint("TRACE").to_string(),
}
#[cfg(not(feature = "verge-dev"))]
log_level.to_string()
}
#[cfg(not(feature = "tauri-dev"))]
pub fn console_colored_format(
w: &mut dyn Write,
now: &mut DeferredNow,
record: &log::Record,
) -> std::io::Result<()> {
let current_thread = thread::current();
let thread_name = current_thread.name().unwrap_or("unnamed");
let level = get_log_level(&record.level().to_level_filter());
let line = record.line().unwrap_or(0);
write!(
w,
"[{}] {} [{}:{}] T[{}] {}",
now.format("%H:%M:%S%.3f"),
level,
record.module_path().unwrap_or("<unnamed>"),
line,
thread_name,
record.args(),
)
}
#[cfg(not(feature = "tauri-dev"))]
pub fn file_format(
w: &mut dyn Write,
now: &mut DeferredNow,
record: &Record,
) -> std::io::Result<()> {
write!(
w,
"[{}] {} {}",
now.format("%Y-%m-%d %H:%M:%S%.3f"),
record.level(),
record.args(),
)
}