mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-29 00:35:38 +08:00
feat: add clash_verge_logger and clash_verge_service_ipc dependencies; refactor logging and process management
This commit is contained in:
109
src-tauri/Cargo.lock
generated
109
src-tauri/Cargo.lock
generated
@@ -1098,8 +1098,9 @@ dependencies = [
|
|||||||
"backoff",
|
"backoff",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"boa_engine",
|
"boa_engine",
|
||||||
"cfg-if",
|
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"clash_verge_logger",
|
||||||
|
"clash_verge_service_ipc",
|
||||||
"console-subscriber",
|
"console-subscriber",
|
||||||
"criterion",
|
"criterion",
|
||||||
"dashmap 6.1.0",
|
"dashmap 6.1.0",
|
||||||
@@ -1114,12 +1115,10 @@ dependencies = [
|
|||||||
"hex",
|
"hex",
|
||||||
"hmac",
|
"hmac",
|
||||||
"isahc",
|
"isahc",
|
||||||
"kode-bridge",
|
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"nanoid",
|
"nanoid",
|
||||||
"network-interface",
|
"network-interface",
|
||||||
"nu-ansi-term",
|
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"open",
|
"open",
|
||||||
"parking_lot 0.12.5",
|
"parking_lot 0.12.5",
|
||||||
@@ -1162,6 +1161,27 @@ dependencies = [
|
|||||||
"zip 5.1.1",
|
"zip 5.1.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clash_verge_logger"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/clash-verge-rev/clash-verge-logger#d3033b152cbf45fd04d9dee48d7aa9371dbfe99c"
|
||||||
|
dependencies = [
|
||||||
|
"flexi_logger",
|
||||||
|
"log",
|
||||||
|
"nu-ansi-term",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clash_verge_service_ipc"
|
||||||
|
version = "2.0.7"
|
||||||
|
source = "git+https://github.com/clash-verge-rev/clash-verge-service-ipc#119aef152cc4d172d597429cfa704c1915b7c395"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"strum",
|
||||||
|
"strum_macros",
|
||||||
|
"windows-service",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clipboard-win"
|
name = "clipboard-win"
|
||||||
version = "5.4.1"
|
version = "5.4.1"
|
||||||
@@ -1932,12 +1952,6 @@ dependencies = [
|
|||||||
"const-random",
|
"const-random",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "doctest-file"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "aac81fa3e28d21450aa4d2ac065992ba96a1d7303efbce51a95f4fd175b67562"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "document-features"
|
name = "document-features"
|
||||||
version = "0.2.11"
|
version = "0.2.11"
|
||||||
@@ -3523,21 +3537,6 @@ dependencies = [
|
|||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "interprocess"
|
|
||||||
version = "2.2.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d941b405bd2322993887859a8ee6ac9134945a24ec5ec763a8a962fc64dfec2d"
|
|
||||||
dependencies = [
|
|
||||||
"doctest-file",
|
|
||||||
"futures-core",
|
|
||||||
"libc",
|
|
||||||
"recvmsg",
|
|
||||||
"tokio",
|
|
||||||
"widestring",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "intrusive-collections"
|
name = "intrusive-collections"
|
||||||
version = "0.9.7"
|
version = "0.9.7"
|
||||||
@@ -3774,33 +3773,6 @@ dependencies = [
|
|||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "kode-bridge"
|
|
||||||
version = "0.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "414f864db42e2b780d3812cdb45f6715d311b177fbf27185be812b711fa5f939"
|
|
||||||
dependencies = [
|
|
||||||
"bytes",
|
|
||||||
"futures",
|
|
||||||
"http 1.3.1",
|
|
||||||
"httparse",
|
|
||||||
"interprocess",
|
|
||||||
"libc",
|
|
||||||
"parking_lot 0.12.5",
|
|
||||||
"pin-project-lite",
|
|
||||||
"rand 0.9.2",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"thiserror 2.0.16",
|
|
||||||
"tokio",
|
|
||||||
"tokio-stream",
|
|
||||||
"tokio-util",
|
|
||||||
"toml 0.9.7",
|
|
||||||
"tracing",
|
|
||||||
"url",
|
|
||||||
"widestring",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kuchikiki"
|
name = "kuchikiki"
|
||||||
version = "0.8.8-speedreader"
|
version = "0.8.8-speedreader"
|
||||||
@@ -5772,12 +5744,6 @@ dependencies = [
|
|||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "recvmsg"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.2.16"
|
version = "0.2.16"
|
||||||
@@ -6804,6 +6770,24 @@ version = "0.11.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strum"
|
||||||
|
version = "0.27.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strum_macros"
|
||||||
|
version = "0.27.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7"
|
||||||
|
dependencies = [
|
||||||
|
"heck 0.5.0",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.106",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "subtle"
|
name = "subtle"
|
||||||
version = "2.6.1"
|
version = "2.6.1"
|
||||||
@@ -9127,6 +9111,17 @@ dependencies = [
|
|||||||
"windows-link 0.1.3",
|
"windows-link 0.1.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-service"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "193cae8e647981c35bc947fdd57ba7928b1fa0d4a79305f6dd2dc55221ac35ac"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.9.4",
|
||||||
|
"widestring",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-strings"
|
name = "windows-strings"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ hmac = "0.12.1"
|
|||||||
sha2 = "0.10.9"
|
sha2 = "0.10.9"
|
||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
scopeguard = "1.2.0"
|
scopeguard = "1.2.0"
|
||||||
kode-bridge = "0.3.3"
|
|
||||||
dashmap = "6.1.0"
|
dashmap = "6.1.0"
|
||||||
tauri-plugin-notification = "2.3.1"
|
tauri-plugin-notification = "2.3.1"
|
||||||
tokio-stream = "0.1.17"
|
tokio-stream = "0.1.17"
|
||||||
@@ -82,11 +81,11 @@ isahc = { version = "1.7.2", default-features = false, features = [
|
|||||||
backoff = { version = "0.4.0", features = ["tokio"] }
|
backoff = { version = "0.4.0", features = ["tokio"] }
|
||||||
tauri-plugin-http = "2.5.2"
|
tauri-plugin-http = "2.5.2"
|
||||||
flexi_logger = "0.31.5"
|
flexi_logger = "0.31.5"
|
||||||
cfg-if = "1.0.3"
|
|
||||||
nu-ansi-term = { version = "0.50.1", optional = true }
|
|
||||||
console-subscriber = { version = "0.4.1", optional = true }
|
console-subscriber = { version = "0.4.1", optional = true }
|
||||||
tauri-plugin-devtools = { version = "2.0.1" }
|
tauri-plugin-devtools = { version = "2.0.1" }
|
||||||
tauri-plugin-mihomo = { git = "https://github.com/clash-verge-rev/tauri-plugin-mihomo" }
|
tauri-plugin-mihomo = { git = "https://github.com/clash-verge-rev/tauri-plugin-mihomo" }
|
||||||
|
clash_verge_logger = { version = "0.1.0", git = "https://github.com/clash-verge-rev/clash-verge-logger" }
|
||||||
|
clash_verge_service_ipc = { version = "2.0.7", git = "https://github.com/clash-verge-rev/clash-verge-service-ipc" }
|
||||||
|
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
@@ -118,7 +117,7 @@ tauri-plugin-updater = "2.9.0"
|
|||||||
[features]
|
[features]
|
||||||
default = ["custom-protocol"]
|
default = ["custom-protocol"]
|
||||||
custom-protocol = ["tauri/custom-protocol"]
|
custom-protocol = ["tauri/custom-protocol"]
|
||||||
verge-dev = ["nu-ansi-term"]
|
verge-dev = ["clash_verge_logger/color"]
|
||||||
tauri-dev = []
|
tauri-dev = []
|
||||||
tokio-trace = ["console-subscriber"]
|
tokio-trace = ["console-subscriber"]
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
use crate::AsyncHandler;
|
use crate::AsyncHandler;
|
||||||
use crate::core::logger::Logger;
|
use crate::core::logger::Logger;
|
||||||
|
use crate::process::CommandChildGuard;
|
||||||
|
use crate::utils::init::sidecar_writer;
|
||||||
|
use crate::utils::logging::SharedWriter;
|
||||||
use crate::{
|
use crate::{
|
||||||
config::*,
|
config::*,
|
||||||
core::{
|
core::{
|
||||||
@@ -14,16 +17,12 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use chrono::Local;
|
use flexi_logger::DeferredNow;
|
||||||
|
use flexi_logger::writers::LogWriter;
|
||||||
|
use log::Record;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::{
|
use std::{fmt, path::PathBuf, sync::Arc};
|
||||||
fmt,
|
use tauri_plugin_shell::ShellExt;
|
||||||
fs::{File, create_dir_all},
|
|
||||||
io::Write,
|
|
||||||
path::PathBuf,
|
|
||||||
sync::Arc,
|
|
||||||
};
|
|
||||||
use tauri_plugin_shell::{ShellExt, process::CommandChild};
|
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// - 重构,提升模式切换速度
|
// - 重构,提升模式切换速度
|
||||||
@@ -32,7 +31,7 @@ use tauri_plugin_shell::{ShellExt, process::CommandChild};
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CoreManager {
|
pub struct CoreManager {
|
||||||
running: Arc<Mutex<RunningMode>>,
|
running: Arc<Mutex<RunningMode>>,
|
||||||
child_sidecar: Arc<Mutex<Option<CommandChild>>>,
|
child_sidecar: Arc<Mutex<Option<CommandChildGuard>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 内核运行模式
|
/// 内核运行模式
|
||||||
@@ -468,7 +467,7 @@ impl CoreManager {
|
|||||||
for pid in pids {
|
for pid in pids {
|
||||||
// 跳过当前管理的进程
|
// 跳过当前管理的进程
|
||||||
if let Some(current) = current_pid
|
if let Some(current) = current_pid
|
||||||
&& pid == current
|
&& Some(pid) == current
|
||||||
{
|
{
|
||||||
logging!(
|
logging!(
|
||||||
debug,
|
debug,
|
||||||
@@ -741,14 +740,6 @@ impl CoreManager {
|
|||||||
let clash_core = Config::verge().await.latest_ref().get_valid_clash_core();
|
let clash_core = Config::verge().await.latest_ref().get_valid_clash_core();
|
||||||
let config_dir = dirs::app_home_dir()?;
|
let config_dir = dirs::app_home_dir()?;
|
||||||
|
|
||||||
let service_log_dir = dirs::app_home_dir()?.join("logs").join("service");
|
|
||||||
create_dir_all(&service_log_dir)?;
|
|
||||||
|
|
||||||
let now = Local::now();
|
|
||||||
let timestamp = now.format("%Y%m%d_%H%M%S").to_string();
|
|
||||||
|
|
||||||
let log_path = service_log_dir.join(format!("sidecar_{timestamp}.log"));
|
|
||||||
|
|
||||||
let (mut rx, child) = app_handle
|
let (mut rx, child) = app_handle
|
||||||
.shell()
|
.shell()
|
||||||
.sidecar(&clash_core)?
|
.sidecar(&clash_core)?
|
||||||
@@ -768,27 +759,60 @@ impl CoreManager {
|
|||||||
"Started core by sidecar pid: {}",
|
"Started core by sidecar pid: {}",
|
||||||
pid
|
pid
|
||||||
);
|
);
|
||||||
*self.child_sidecar.lock() = Some(child);
|
*self.child_sidecar.lock() = Some(CommandChildGuard::new(child));
|
||||||
self.set_running_mode(RunningMode::Sidecar);
|
self.set_running_mode(RunningMode::Sidecar);
|
||||||
|
|
||||||
let mut log_file = std::io::BufWriter::new(File::create(log_path)?);
|
let shared_writer: SharedWriter =
|
||||||
|
Arc::new(tokio::sync::Mutex::new(sidecar_writer().await?));
|
||||||
|
|
||||||
AsyncHandler::spawn(|| async move {
|
AsyncHandler::spawn(|| async move {
|
||||||
while let Some(event) = rx.recv().await {
|
while let Some(event) = rx.recv().await {
|
||||||
|
let w = shared_writer.lock().await;
|
||||||
match event {
|
match event {
|
||||||
tauri_plugin_shell::process::CommandEvent::Stdout(line) => {
|
tauri_plugin_shell::process::CommandEvent::Stdout(line) => {
|
||||||
|
let mut now = DeferredNow::default();
|
||||||
|
let line_str = String::from_utf8_lossy(&line);
|
||||||
|
let arg = format_args!("{}", line_str);
|
||||||
|
let record = Record::builder()
|
||||||
|
.args(arg)
|
||||||
|
.level(log::Level::Error)
|
||||||
|
.target("sidecar")
|
||||||
|
.build();
|
||||||
|
let _ = w.write(&mut now, &record);
|
||||||
|
|
||||||
let line = String::from_utf8_lossy(&line);
|
let line = String::from_utf8_lossy(&line);
|
||||||
Logger::global().append_log(line.to_string());
|
Logger::global().append_log(line.to_string());
|
||||||
if let Err(e) = writeln!(log_file, "{}", line) {
|
|
||||||
eprintln!("[Sidecar] write stdout failed: {e}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
tauri_plugin_shell::process::CommandEvent::Stderr(line) => {
|
tauri_plugin_shell::process::CommandEvent::Stderr(line) => {
|
||||||
|
let mut now = DeferredNow::default();
|
||||||
|
let line_str = String::from_utf8_lossy(&line);
|
||||||
|
let arg = format_args!("{}", line_str);
|
||||||
|
let record = Record::builder()
|
||||||
|
.args(arg)
|
||||||
|
.level(log::Level::Error)
|
||||||
|
.target("sidecar")
|
||||||
|
.build();
|
||||||
|
let _ = w.write(&mut now, &record);
|
||||||
|
|
||||||
let line = String::from_utf8_lossy(&line);
|
let line = String::from_utf8_lossy(&line);
|
||||||
Logger::global().append_log(line.to_string());
|
Logger::global().append_log(line.to_string());
|
||||||
let _ = writeln!(log_file, "[stderr] {}", line);
|
|
||||||
}
|
}
|
||||||
tauri_plugin_shell::process::CommandEvent::Terminated(term) => {
|
tauri_plugin_shell::process::CommandEvent::Terminated(term) => {
|
||||||
let _ = writeln!(log_file, "[terminated] {:?}", term);
|
let mut now = DeferredNow::default();
|
||||||
|
let output_str = if let Some(code) = term.code {
|
||||||
|
format!("Process terminated with code: {}", code)
|
||||||
|
} else if let Some(signal) = term.signal {
|
||||||
|
format!("Process terminated by signal: {}", signal)
|
||||||
|
} else {
|
||||||
|
"Process terminated".to_string()
|
||||||
|
};
|
||||||
|
let arg = format_args!("{}", output_str);
|
||||||
|
let record = Record::builder()
|
||||||
|
.args(arg)
|
||||||
|
.level(log::Level::Info)
|
||||||
|
.target("sidecar")
|
||||||
|
.build();
|
||||||
|
let _ = w.write(&mut now, &record);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -803,12 +827,12 @@ impl CoreManager {
|
|||||||
|
|
||||||
if let Some(child) = self.child_sidecar.lock().take() {
|
if let Some(child) = self.child_sidecar.lock().take() {
|
||||||
let pid = child.pid();
|
let pid = child.pid();
|
||||||
child.kill()?;
|
drop(child);
|
||||||
logging!(
|
logging!(
|
||||||
trace,
|
trace,
|
||||||
Type::Core,
|
Type::Core,
|
||||||
true,
|
true,
|
||||||
"Stopped core by sidecar pid: {}",
|
"Stopped core by sidecar pid: {:?}",
|
||||||
pid
|
pid
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -381,6 +381,7 @@ pub(super) async fn start_with_existing_service(config_file: &PathBuf) -> Result
|
|||||||
"bin_path": dirs::path_to_str(&bin_path)?,
|
"bin_path": dirs::path_to_str(&bin_path)?,
|
||||||
"config_dir": dirs::path_to_str(&dirs::app_home_dir()?)?,
|
"config_dir": dirs::path_to_str(&dirs::app_home_dir()?)?,
|
||||||
"config_file": dirs::path_to_str(config_file)?,
|
"config_file": dirs::path_to_str(config_file)?,
|
||||||
|
// TODO 迁移 Service日志后删除
|
||||||
"log_file": dirs::path_to_str(&dirs::service_log_file()?)?,
|
"log_file": dirs::path_to_str(&dirs::service_log_file()?)?,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
30
src-tauri/src/process/guard.rs
Normal file
30
src-tauri/src/process/guard.rs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use tauri_plugin_shell::process::CommandChild;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CommandChildGuard(Option<CommandChild>);
|
||||||
|
|
||||||
|
impl Drop for CommandChildGuard {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Err(err) = self.kill() {
|
||||||
|
log::error!(target: "app", "Failed to kill child process: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CommandChildGuard {
|
||||||
|
pub fn new(child: CommandChild) -> Self {
|
||||||
|
Self(Some(child))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kill(&mut self) -> Result<()> {
|
||||||
|
if let Some(child) = self.0.take() {
|
||||||
|
let _ = child.kill();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pid(&self) -> Option<u32> {
|
||||||
|
self.0.as_ref().map(|c| c.pid())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,2 +1,4 @@
|
|||||||
mod async_handler;
|
mod async_handler;
|
||||||
pub use async_handler::AsyncHandler;
|
pub use async_handler::AsyncHandler;
|
||||||
|
mod guard;
|
||||||
|
pub use guard::CommandChildGuard;
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ pub fn service_path() -> Result<PathBuf> {
|
|||||||
Ok(res_dir.join("clash-verge-service.exe"))
|
Ok(res_dir.join("clash-verge-service.exe"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO 迁移 Service日志后删除
|
||||||
pub fn service_log_file() -> Result<PathBuf> {
|
pub fn service_log_file() -> Result<PathBuf> {
|
||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
|
|
||||||
@@ -158,6 +159,20 @@ pub fn service_log_file() -> Result<PathBuf> {
|
|||||||
Ok(log_file)
|
Ok(log_file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sidecar_log_dir() -> Result<PathBuf> {
|
||||||
|
let log_dir = app_logs_dir()?.join("sidecar");
|
||||||
|
let _ = std::fs::create_dir_all(&log_dir);
|
||||||
|
|
||||||
|
Ok(log_dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn service_log_dir() -> Result<PathBuf> {
|
||||||
|
let log_dir = app_logs_dir()?.join("service");
|
||||||
|
let _ = std::fs::create_dir_all(&log_dir);
|
||||||
|
|
||||||
|
Ok(log_dir)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn path_to_str(path: &PathBuf) -> Result<&str> {
|
pub fn path_to_str(path: &PathBuf) -> Result<&str> {
|
||||||
let path_str = path
|
let path_str = path
|
||||||
.as_os_str()
|
.as_os_str()
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
cfg_if::cfg_if! {
|
#[cfg(not(feature = "tauri-dev"))]
|
||||||
if #[cfg(not(feature = "tauri-dev"))] {
|
use crate::utils::logging::NoModuleFilter;
|
||||||
use crate::utils::logging::{console_colored_format, file_format, NoExternModule};
|
|
||||||
use flexi_logger::{Cleanup, Criterion, Duplicate, FileSpec, LogSpecification, Logger};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::*,
|
config::*,
|
||||||
core::handle,
|
core::handle,
|
||||||
logging,
|
logging,
|
||||||
process::AsyncHandler,
|
process::AsyncHandler,
|
||||||
utils::{dirs, help, logging::Type},
|
utils::{
|
||||||
|
dirs::{self, service_log_dir, sidecar_log_dir},
|
||||||
|
help,
|
||||||
|
logging::Type,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use chrono::{Local, TimeZone};
|
use chrono::{Local, TimeZone};
|
||||||
|
use clash_verge_service_ipc::WriterConfig;
|
||||||
|
use flexi_logger::writers::FileLogWriter;
|
||||||
|
use flexi_logger::{Cleanup, Criterion, FileSpec};
|
||||||
|
#[cfg(not(feature = "tauri-dev"))]
|
||||||
|
use flexi_logger::{Duplicate, LogSpecBuilder, Logger};
|
||||||
use std::{path::PathBuf, str::FromStr};
|
use std::{path::PathBuf, str::FromStr};
|
||||||
use tauri_plugin_shell::ShellExt;
|
use tauri_plugin_shell::ShellExt;
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
@@ -34,11 +38,13 @@ pub async fn init_logger() -> Result<()> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let log_dir = dirs::app_logs_dir()?;
|
let log_dir = dirs::app_logs_dir()?;
|
||||||
let logger = Logger::with(LogSpecification::from(log_level))
|
let spec = LogSpecBuilder::new().default(log_level).build();
|
||||||
|
|
||||||
|
let logger = Logger::with(spec)
|
||||||
.log_to_file(FileSpec::default().directory(log_dir).basename(""))
|
.log_to_file(FileSpec::default().directory(log_dir).basename(""))
|
||||||
.duplicate_to_stdout(Duplicate::Debug)
|
.duplicate_to_stdout(Duplicate::Debug)
|
||||||
.format(console_colored_format)
|
.format(clash_verge_logger::console_format)
|
||||||
.format_for_files(file_format)
|
.format_for_files(clash_verge_logger::file_format_with_level)
|
||||||
.rotate(
|
.rotate(
|
||||||
Criterion::Size(log_max_size * 1024),
|
Criterion::Size(log_max_size * 1024),
|
||||||
flexi_logger::Naming::TimestampsCustomFormat {
|
flexi_logger::Naming::TimestampsCustomFormat {
|
||||||
@@ -47,7 +53,7 @@ pub async fn init_logger() -> Result<()> {
|
|||||||
},
|
},
|
||||||
Cleanup::KeepLogFiles(log_max_count),
|
Cleanup::KeepLogFiles(log_max_count),
|
||||||
)
|
)
|
||||||
.filter(Box::new(NoExternModule));
|
.filter(Box::new(NoModuleFilter(&["wry", "tauri"])));
|
||||||
|
|
||||||
let _handle = logger.start()?;
|
let _handle = logger.start()?;
|
||||||
|
|
||||||
@@ -59,6 +65,54 @@ pub async fn init_logger() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn sidecar_writer() -> Result<FileLogWriter> {
|
||||||
|
let (log_max_size, log_max_count) = {
|
||||||
|
let verge_guard = Config::verge().await;
|
||||||
|
let verge = verge_guard.latest_ref();
|
||||||
|
(
|
||||||
|
verge.app_log_max_size.unwrap_or(128),
|
||||||
|
verge.app_log_max_count.unwrap_or(8),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let sidecar_log_dir = sidecar_log_dir()?;
|
||||||
|
Ok(FileLogWriter::builder(
|
||||||
|
FileSpec::default()
|
||||||
|
.directory(sidecar_log_dir)
|
||||||
|
.basename("sidecar")
|
||||||
|
.suppress_timestamp(),
|
||||||
|
)
|
||||||
|
.format(clash_verge_logger::file_format_without_level)
|
||||||
|
.rotate(
|
||||||
|
Criterion::Size(log_max_size * 1024),
|
||||||
|
flexi_logger::Naming::TimestampsCustomFormat {
|
||||||
|
current_infix: Some("latest"),
|
||||||
|
format: "%Y-%m-%d_%H-%M-%S",
|
||||||
|
},
|
||||||
|
Cleanup::KeepLogFiles(log_max_count),
|
||||||
|
)
|
||||||
|
.try_build()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO 后续迁移新 service 时使用
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub async fn service_writer_config() -> Result<WriterConfig> {
|
||||||
|
let (log_max_size, log_max_count) = {
|
||||||
|
let verge_guard = Config::verge().await;
|
||||||
|
let verge = verge_guard.latest_ref();
|
||||||
|
(
|
||||||
|
verge.app_log_max_size.unwrap_or(128),
|
||||||
|
verge.app_log_max_count.unwrap_or(8),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let service_log_dir = dirs::path_to_str(&service_log_dir()?)?.to_string();
|
||||||
|
|
||||||
|
Ok(WriterConfig {
|
||||||
|
directory: service_log_dir,
|
||||||
|
max_log_size: log_max_size * 1024,
|
||||||
|
max_log_files: log_max_count,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// TODO flexi_logger 提供了最大保留天数,或许我们应该用内置删除log文件
|
// TODO flexi_logger 提供了最大保留天数,或许我们应该用内置删除log文件
|
||||||
/// 删除log文件
|
/// 删除log文件
|
||||||
pub async fn delete_log() -> Result<()> {
|
pub async fn delete_log() -> Result<()> {
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
cfg_if::cfg_if! {
|
use flexi_logger::writers::FileLogWriter;
|
||||||
if #[cfg(feature = "tauri-dev")] {
|
#[cfg(not(feature = "tauri-dev"))]
|
||||||
use std::fmt;
|
use flexi_logger::{DeferredNow, filter::LogLineFilter};
|
||||||
} else {
|
#[cfg(not(feature = "tauri-dev"))]
|
||||||
#[cfg(feature = "verge-dev")]
|
use log::Record;
|
||||||
use nu_ansi_term::Color;
|
use std::{fmt, sync::Arc};
|
||||||
use std::{fmt, io::Write, thread};
|
use tokio::sync::Mutex;
|
||||||
use flexi_logger::DeferredNow;
|
|
||||||
use log::{LevelFilter, Record};
|
pub type SharedWriter = Arc<Mutex<FileLogWriter>>;
|
||||||
use flexi_logger::filter::LogLineFilter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
@@ -28,7 +25,6 @@ pub enum Type {
|
|||||||
Lightweight,
|
Lightweight,
|
||||||
Network,
|
Network,
|
||||||
ProxyMode,
|
ProxyMode,
|
||||||
// Ipc,
|
|
||||||
// Cache,
|
// Cache,
|
||||||
ClashVergeRev,
|
ClashVergeRev,
|
||||||
}
|
}
|
||||||
@@ -51,7 +47,6 @@ impl fmt::Display for Type {
|
|||||||
Type::Lightweight => write!(f, "[Lightweight]"),
|
Type::Lightweight => write!(f, "[Lightweight]"),
|
||||||
Type::Network => write!(f, "[Network]"),
|
Type::Network => write!(f, "[Network]"),
|
||||||
Type::ProxyMode => write!(f, "[ProxMode]"),
|
Type::ProxyMode => write!(f, "[ProxMode]"),
|
||||||
// Type::Ipc => write!(f, "[IPC]"),
|
|
||||||
// Type::Cache => write!(f, "[Cache]"),
|
// Type::Cache => write!(f, "[Cache]"),
|
||||||
Type::ClashVergeRev => write!(f, "[ClashVergeRev]"),
|
Type::ClashVergeRev => write!(f, "[ClashVergeRev]"),
|
||||||
}
|
}
|
||||||
@@ -173,75 +168,36 @@ macro_rules! logging_error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "tauri-dev"))]
|
#[cfg(not(feature = "tauri-dev"))]
|
||||||
static IGNORE_MODULES: &[&str] = &["tauri", "wry"];
|
pub struct NoModuleFilter<'a>(pub &'a [&'a str]);
|
||||||
|
|
||||||
#[cfg(not(feature = "tauri-dev"))]
|
#[cfg(not(feature = "tauri-dev"))]
|
||||||
pub struct NoExternModule;
|
impl<'a> NoModuleFilter<'a> {
|
||||||
|
#[inline]
|
||||||
|
pub fn filter(&self, record: &Record) -> bool {
|
||||||
|
if let Some(module) = record.module_path() {
|
||||||
|
for blocked in self.0 {
|
||||||
|
if module.len() >= blocked.len()
|
||||||
|
&& module.as_bytes()[..blocked.len()] == blocked.as_bytes()[..]
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "tauri-dev"))]
|
#[cfg(not(feature = "tauri-dev"))]
|
||||||
impl LogLineFilter for NoExternModule {
|
impl<'a> LogLineFilter for NoModuleFilter<'a> {
|
||||||
fn write(
|
fn write(
|
||||||
&self,
|
&self,
|
||||||
now: &mut DeferredNow,
|
now: &mut DeferredNow,
|
||||||
record: &Record,
|
record: &Record,
|
||||||
log_line_writer: &dyn flexi_logger::filter::LogLineWriter,
|
writer: &dyn flexi_logger::filter::LogLineWriter,
|
||||||
) -> std::io::Result<()> {
|
) -> std::io::Result<()> {
|
||||||
let module_path = record.module_path().unwrap_or_default();
|
if !self.filter(record) {
|
||||||
if IGNORE_MODULES.iter().any(|m| module_path.starts_with(m)) {
|
return Ok(());
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
log_line_writer.write(now, record)
|
|
||||||
}
|
}
|
||||||
|
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(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user