refactor: 使用 tracing 输出日志 (#1856)

* change all println to tracing
This commit is contained in:
Luna Yao
2026-03-04 02:52:23 +01:00
committed by GitHub
parent 1d25240d8c
commit 5f31583a84
18 changed files with 488 additions and 384 deletions
Generated
+11
View File
@@ -2207,6 +2207,7 @@ dependencies = [
"humansize",
"humantime-serde",
"idna 1.0.3",
"indoc",
"kcp-sys",
"machine-uid",
"maplit",
@@ -2222,6 +2223,7 @@ dependencies = [
"openssl",
"ordered_hash_map",
"parking_lot",
"paste",
"percent-encoding",
"petgraph 0.8.1",
"pin-project-lite",
@@ -4163,6 +4165,15 @@ dependencies = [
"serde",
]
[[package]]
name = "indoc"
version = "2.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
dependencies = [
"rustversion",
]
[[package]]
name = "infer"
version = "0.19.0"
+11
View File
@@ -1130,6 +1130,7 @@ dependencies = [
"humansize",
"humantime-serde",
"idna",
"indoc",
"kcp-sys",
"machine-uid",
"multimap",
@@ -1142,6 +1143,7 @@ dependencies = [
"once_cell",
"ordered_hash_map",
"parking_lot",
"paste",
"percent-encoding",
"petgraph 0.8.2",
"pin-project-lite",
@@ -2197,6 +2199,15 @@ dependencies = [
"hashbrown 0.16.0",
]
[[package]]
name = "indoc"
version = "2.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
dependencies = [
"rustversion",
]
[[package]]
name = "inout"
version = "0.1.4"
+2 -2
View File
@@ -11,7 +11,7 @@ use api::routes::create_routes;
use clap::Parser;
use config::AppConfig;
use db::{operations::NodeOperations, Db};
use easytier::utils::init_logger;
use easytier::common::log;
use health_checker::HealthChecker;
use health_checker_manager::HealthCheckerManager;
use std::env;
@@ -42,7 +42,7 @@ async fn main() -> anyhow::Result<()> {
let config = AppConfig::default();
// 初始化日志
let _ = init_logger(&config.logging, false);
let _ = log::init(&config.logging, false);
// 解析命令行参数
let args = Args::parse();
+5 -2
View File
@@ -14,7 +14,10 @@ use easytier::rpc_service::remote_client::{
};
use easytier::web_client::{self, WebClient};
use easytier::{
common::config::{ConfigLoader, FileLoggerConfig, LoggingConfigBuilder, TomlConfigLoader},
common::{
config::{ConfigLoader, FileLoggerConfig, LoggingConfigBuilder, TomlConfigLoader},
log,
},
instance_manager::NetworkInstanceManager,
launcher::NetworkConfig,
rpc_service::ApiRpcServer,
@@ -1119,7 +1122,7 @@ pub fn run_gui() -> std::process::ExitCode {
})
.build()
.map_err(|e| e.to_string())?;
let Ok(_) = utils::init_logger(&config, true) else {
let Ok(_) = log::init(&config, true) else {
return Ok(());
};
+3 -2
View File
@@ -13,10 +13,11 @@ use easytier::{
config::{ConsoleLoggerConfig, FileLoggerConfig, LoggingConfigLoader},
constants::EASYTIER_VERSION,
error::Error,
log,
network::{local_ipv4, local_ipv6},
},
tunnel::{tcp::TcpTunnelListener, udp::UdpTunnelListener, TunnelListener},
utils::{init_logger, setup_panic_handler},
utils::setup_panic_handler,
};
use mimalloc::MiMalloc;
@@ -205,7 +206,7 @@ async fn main() {
setup_panic_handler();
let cli = Cli::parse();
init_logger(&cli, false).unwrap();
log::init(&cli, false).unwrap();
// Validate OIDC configuration: check split-deploy specific requirements
// Basic OIDC parameter validation is handled in OidcConfig::from_params
+3
View File
@@ -39,6 +39,9 @@ tracing-subscriber = { version = "0.3", features = [
derivative = "2.2.0"
derive_more = {version = "2.1.1", features = ["full"]}
console-subscriber = { version = "0.4.1", optional = true }
indoc = "2.0.7"
regex = "1.8"
paste = "1.0"
thiserror = "1.0"
auto_impl = "1.1.0"
crossbeam = "0.8.4"
+219
View File
@@ -0,0 +1,219 @@
use crate::common::config::LoggingConfigLoader;
use crate::common::get_logger_timer_rfc3339;
use crate::common::tracing_rolling_appender::{FileAppenderWrapper, RollingFileAppenderBase};
use crate::rpc_service::logger::{CURRENT_LOG_LEVEL, LOGGER_LEVEL_SENDER};
use anyhow::Context;
use paste::paste;
use regex::Regex;
use tracing::level_filters::LevelFilter;
use tracing::{Level, Metadata};
use tracing_subscriber::filter::{filter_fn, FilterExt};
use tracing_subscriber::fmt::layer;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::Registry;
use tracing_subscriber::{EnvFilter, Layer};
macro_rules! __log__ {
(const $var:ident = $target:expr) => {
const $var: &'static str = $target;
__log__!(@impl $target, $);
};
(@impl $target:expr, $_:tt) => {
__log__!(@impl $_, $target, error, warn, info, debug, trace);
};
(@impl $_:tt, $target:expr, $($lvl:ident),+) => {
paste! {
$(
macro_rules! [< __ $lvl __ >] {
(category: $cat:expr, $_ ($arg:tt)+) => {
tracing::$lvl!(target: concat!($target, "::", $cat), $_ ($arg)+)
};
($_ ($arg:tt)+) => {
tracing::$lvl!(target: $target, $_ ($arg)+)
};
}
#[allow(unused_imports)]
pub(crate) use [< __ $lvl __ >] as $lvl;
)+
}
};
}
__log__!(const LOG_TARGET = "CORE");
fn parse_env_filter(default_level: LevelFilter) -> Result<EnvFilter, anyhow::Error> {
let mut filter = EnvFilter::builder()
.with_default_directive(default_level.into())
.from_env()
.with_context(|| "failed to create env filter")?;
let pattern = Regex::new(&format!(r"(^|,){}\s*=", regex::escape(LOG_TARGET)))?;
if !pattern.is_match(&filter.to_string()) {
filter = filter.add_directive(format!("{LOG_TARGET}=info").parse()?);
}
Ok(filter)
}
fn is_log(meta: &Metadata) -> bool {
meta.target() == LOG_TARGET || meta.target().starts_with(&format!("{LOG_TARGET}::"))
}
pub type NewFilterSender = std::sync::mpsc::Sender<String>;
macro_rules! tracing_layer {
($layer:expr) => {
$layer.with_filter(filter_fn(is_log).not()).boxed()
};
}
macro_rules! log_layer {
($layer:expr) => {
$layer
.with_file(false)
.with_line_number(false)
.with_ansi(true)
.with_filter(filter_fn(is_log))
.boxed()
};
}
pub fn init(
config: impl LoggingConfigLoader,
need_reload: bool,
) -> Result<Option<NewFilterSender>, anyhow::Error> {
let mut layers = Vec::new();
let file_config = config.get_file_logger_config();
let file_level = file_config
.level
.map(|s| s.parse().unwrap())
.unwrap_or(LevelFilter::OFF);
let mut ret_sender: Option<NewFilterSender> = None;
// logger to a rolling file
if file_level != LevelFilter::OFF || need_reload {
let dir = file_config.dir.as_deref().unwrap_or(".");
let file = file_config.file.as_deref().unwrap_or("easytier.log");
let path = std::path::Path::new(dir).join(file);
let path_str = path.to_string_lossy().into_owned();
let builder = RollingFileAppenderBase::builder();
let file_appender = builder
.filename(path_str)
.condition_daily()
.max_filecount(file_config.count.unwrap_or(10))
.condition_max_file_size(file_config.size_mb.unwrap_or(100) * 1024 * 1024)
.build()
.unwrap();
// Create a simple wrapper that implements MakeWriter
let wrapper = FileAppenderWrapper::new(file_appender);
let (file_filter, file_filter_reloader) =
tracing_subscriber::reload::Layer::<_, Registry>::new(parse_env_filter(file_level)?);
let layer = |wrapper| {
layer()
.with_ansi(false)
.with_writer(wrapper)
.with_timer(get_logger_timer_rfc3339())
};
layers.push(
vec![
tracing_layer!(layer(wrapper.clone())),
log_layer!(layer(wrapper.clone())),
]
.with_filter(file_filter)
.boxed(),
);
if need_reload {
let (sender, recver) = std::sync::mpsc::channel();
ret_sender = Some(sender.clone());
// 初始化全局状态
let _ = LOGGER_LEVEL_SENDER.set(std::sync::Mutex::new(sender));
let _ = CURRENT_LOG_LEVEL.set(std::sync::Mutex::new(file_level.to_string()));
std::thread::spawn(move || {
while let Ok(lf) = recver.recv() {
let e = file_filter_reloader.modify(|f| {
if let Ok(nf) = EnvFilter::builder()
.with_default_directive(lf.parse::<LevelFilter>().unwrap().into())
.from_env()
.with_context(|| "failed to create file filter")
{
info!("Reload log filter succeed, new filter level: {:?}", lf);
*f = nf;
}
});
if e.is_err() {
error!("Failed to reload log filter: {:?}", e);
}
}
info!("Stop log filter reloader");
});
}
}
// logger to console
let console_config = config.get_console_logger_config();
let console_level = console_config
.level
.map(|s| s.parse().unwrap())
.unwrap_or(LevelFilter::OFF);
let (console_filter, _) =
tracing_subscriber::reload::Layer::new(parse_env_filter(console_level)?);
let layer = || {
layer()
.pretty()
.with_timer(get_logger_timer_rfc3339())
.with_writer(std::io::stderr)
};
layers.push(
vec![
tracing_layer!(layer()),
log_layer!(layer()).with_filter(LevelFilter::WARN).boxed(),
log_layer!(layer().with_writer(std::io::stdout))
.with_filter(filter_fn(|metadata| *metadata.level() > Level::WARN))
.boxed(),
]
.with_filter(console_filter)
.boxed(),
);
#[cfg(feature = "tracing")]
{
layers.push(console_subscriber::ConsoleLayer::builder().spawn().boxed());
}
Registry::default().with(layers).init();
Ok(ret_sender)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::common::config::{self};
async fn test_logger_reload() {
println!("current working dir: {:?}", std::env::current_dir());
let config = config::LoggingConfigBuilder::default().build().unwrap();
let s = init(&config, true).unwrap();
tracing::debug!("test not display debug");
s.unwrap().send(LevelFilter::DEBUG.to_string()).unwrap();
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
tracing::debug!("test display debug");
}
}
+1
View File
@@ -21,6 +21,7 @@ pub mod error;
pub mod global_ctx;
pub mod idn;
pub mod ifcfg;
pub mod log;
pub mod netns;
pub mod network;
pub mod scoped_task;
@@ -184,6 +184,7 @@ where
}
}
#[derive(Debug, Clone)]
pub struct FileAppenderWrapper {
appender: std::sync::Arc<parking_lot::Mutex<RollingFileAppenderBase>>,
}
@@ -206,6 +207,7 @@ impl FileAppenderWrapper {
}
}
#[derive(Debug, Clone)]
pub struct FileAppenderWriter {
appender: std::sync::Arc<parking_lot::Mutex<RollingFileAppenderBase>>,
}
+2 -1
View File
@@ -5,6 +5,7 @@ use crate::{
dns::{resolve_txt_record, RESOLVER},
error::Error,
global_ctx::ArcGlobalCtx,
log,
},
tunnel::{IpVersion, Tunnel, TunnelConnector, TunnelError, PROTO_PORT_OFFSET},
};
@@ -131,7 +132,7 @@ impl DNSTunnelConnector {
let parsed_record = Self::handle_one_srv_record(record, protocol);
tracing::info!(?parsed_record, ?srv_domain, "parsed_record");
if let Err(e) = &parsed_record {
eprintln!("got invalid srv record {:?}", e);
log::warn!("got invalid srv record {:?}", e);
continue;
}
responses.insert(parsed_record.unwrap());
+36 -31
View File
@@ -15,6 +15,7 @@ use crate::{
PeerConfig, PortForwardConfig, TomlConfigLoader, VpnPortalConfig,
},
constants::EASYTIER_VERSION,
log,
},
defer,
instance_manager::NetworkInstanceManager,
@@ -22,7 +23,7 @@ use crate::{
proto::common::{CompressionAlgoPb, SecureModeConfig},
rpc_service::ApiRpcServer,
tunnel::PROTO_PORT_OFFSET,
utils::{init_logger, setup_panic_handler},
utils::setup_panic_handler,
web_client, ShellType,
};
use anyhow::Context;
@@ -1163,7 +1164,7 @@ fn win_service_event_loop(
}
Err(e) => {
status_handle.set_service_status(error_status).unwrap();
eprintln!("error: {}", e);
log::error!("{}", e);
}
}
},
@@ -1231,7 +1232,7 @@ fn win_service_main(arg: Vec<std::ffi::OsString>) {
async fn run_main(cli: Cli) -> anyhow::Result<()> {
defer!(dump_profile(0););
init_logger(&cli.logging_options, true)?;
log::init(&cli.logging_options, true)?;
let manager = Arc::new(NetworkInstanceManager::new().with_config_path(cli.config_dir.clone()));
@@ -1253,12 +1254,12 @@ async fn run_main(cli: Cli) -> anyhow::Result<()> {
)
.await
.inspect(|_| {
println!(
"Web client started successfully...\nserver: {}",
config_server_url_s,
log::info!(
server = config_server_url_s,
"Web client started successfully...",
);
println!("Official config website: https://easytier.cn/web");
log::info!("Official config website: https://easytier.cn/web");
})?;
Some(wc)
@@ -1324,13 +1325,17 @@ async fn run_main(cli: Cli) -> anyhow::Result<()> {
control.set_no_delete(true);
}
println!(
"Starting easytier from config file {:?}({:?}) with config:",
config_file, control.permission
log::info!(
"\
Starting easytier from config file {:?}({:?}) with config:\n\
############### TOML ###############\n\
{}\n\
-----------------------------------\n\
",
config_file,
control.permission,
cfg.dump()
);
println!("############### TOML ###############\n");
println!("{}", cfg.dump());
println!("-----------------------------------");
manager.run_network_instance(cfg, true, control)?;
}
@@ -1339,10 +1344,15 @@ async fn run_main(cli: Cli) -> anyhow::Result<()> {
cli.network_options
.merge_into(&cfg)
.with_context(|| "failed to create config from cli".to_string())?;
println!("Starting easytier from cli with config:");
println!("############### TOML ###############\n");
println!("{}", cfg.dump());
println!("-----------------------------------");
log::info!(
"\
Starting easytier from cli with config:\n\
############### TOML ###############\n\
{}\n\
-----------------------------------\n\
",
cfg.dump()
);
manager.run_network_instance(cfg, true, ConfigFileControl::STATIC_CONFIG)?;
}
@@ -1363,11 +1373,11 @@ async fn run_main(cli: Cli) -> anyhow::Result<()> {
}
}
_ = tokio::signal::ctrl_c() => {
println!("ctrl-c received, exiting...");
log::info!("ctrl-c received, exiting...");
}
_ = sigterm, if cfg!(unix) => {
println!("terminate signal received, exiting...");
log::warn!("terminate signal received, exiting...");
}
}
Ok(())
@@ -1384,11 +1394,7 @@ fn memory_monitor(_force_dump: Arc<AtomicBool>) {
e.advance().unwrap();
let new_heap_size = allocated_stats.read().unwrap();
println!(
"heap size: {} bytes, time: {}",
new_heap_size,
chrono::Local::now().format("%Y-%m-%d %H:%M:%S")
);
log::debug!("heap size: {} bytes", new_heap_size);
// dump every 75MB
if (last_peak_size > 0
@@ -1396,10 +1402,9 @@ fn memory_monitor(_force_dump: Arc<AtomicBool>) {
&& new_heap_size - last_peak_size > 10 * 1024 * 1024)
|| _force_dump.load(std::sync::atomic::Ordering::Relaxed)
{
println!(
"heap size increased: {} bytes, time: {}",
log::debug!(
"heap size increased: {} bytes",
new_heap_size - last_peak_size,
chrono::Local::now().format("%Y-%m-%d %H:%M:%S")
);
dump_profile(new_heap_size);
last_peak_size = new_heap_size;
@@ -1475,7 +1480,7 @@ pub async fn main() -> ExitCode {
// Verify configurations
if cli.check_config {
if let Err(e) = validate_config(&cli).await {
eprintln!("Config validation failed: {:?}", e);
log::error!("Config validation failed: {:?}", e);
return ExitCode::FAILURE;
} else {
return ExitCode::SUCCESS;
@@ -1484,12 +1489,12 @@ pub async fn main() -> ExitCode {
let mut ret_code = 0;
if let Err(e) = run_main(cli).await {
eprintln!("error: {:?}", e);
if let Err(error) = run_main(cli).await {
log::error!(%error);
ret_code = 1;
}
println!("Stopping easytier...");
log::info!("Stopping easytier...");
set_prof_active(false);
ExitCode::from(ret_code)
+4 -4
View File
@@ -23,7 +23,7 @@ use tracing::Instrument;
use crate::common::error::Result;
use crate::common::global_ctx::{ArcGlobalCtx, GlobalCtx};
use crate::common::join_joinset_background;
use crate::common::log;
use crate::common::stats_manager::{LabelSet, LabelType, MetricName};
use crate::peers::peer_manager::PeerManager;
use crate::peers::{NicPacketFilter, PeerPacketFilter};
@@ -66,9 +66,9 @@ impl NatDstConnector for NatDstTcpConnector {
async fn connect(&self, _src: SocketAddr, nat_dst: SocketAddr) -> Result<Self::DstStream> {
let socket = match TcpSocket::new_v4() {
Ok(s) => s,
Err(e) => {
eprintln!("create v4 socket failed: {:?}", e);
return Err(e.into());
Err(error) => {
log::error!(%error, "create v4 socket failed");
return Err(error.into());
}
};
+37 -53
View File
@@ -12,6 +12,7 @@ use crate::{
error::Error,
global_ctx::{ArcGlobalCtx, GlobalCtxEvent},
ifcfg::{IfConfiger, IfConfiguerTrait},
log,
},
instance::proxy_cidrs_monitor::ProxyCidrsMonitor,
peers::{peer_manager::PeerManager, recv_packet_from_chan, PacketRecvChanReceiver},
@@ -95,7 +96,7 @@ impl Stream for TunStream {
match ret {
Ok(_) => Poll::Ready(Some(Ok(ZCPacket::new_from_buf(ret_buf, ZCPacketType::NIC)))),
Err(err) => {
println!("tun stream error: {:?}", err);
log::error!("tun stream error: {:?}", err);
Poll::Ready(None)
}
}
@@ -249,10 +250,11 @@ impl Drop for VirtualNic {
{
if let Some(ref ifname) = self.ifname {
// Try to clean up firewall rules, but don't panic in destructor
if let Err(e) = crate::arch::windows::remove_interface_firewall_rules(ifname) {
eprintln!(
"Warning: Failed to remove firewall rules for interface {}: {}",
ifname, e
if let Err(error) = crate::arch::windows::remove_interface_firewall_rules(ifname) {
log::warn!(
%error,
"failed to remove firewall rules for interface {}",
ifname
);
}
}
@@ -293,25 +295,20 @@ impl VirtualNic {
.unwrap_or(false);
if !tun_module_available {
tracing::warn!("TUN kernel module may not be loaded");
println!("⚠ Warning: TUN kernel module may not be available.");
println!(" You may need to load it with: sudo modprobe tun");
log::warn!("TUN kernel module may not be available.");
log::warn!("\tYou may need to load it with: sudo modprobe tun.");
}
// Try to create /dev/net directory if it doesn't exist
if tokio::fs::metadata(TUN_DIR_PATH).await.is_err() {
if let Err(e) = tokio::fs::create_dir_all(TUN_DIR_PATH).await {
tracing::warn!(
"Failed to create directory {}: {}. Continuing anyway.",
TUN_DIR_PATH,
e
);
println!(
"⚠ Warning: Failed to create directory {}. TUN device creation may fail.",
if let Err(error) = tokio::fs::create_dir_all(TUN_DIR_PATH).await {
log::warn!(
?error,
"Failed to create directory {}. TUN device creation may fail. Continuing anyway.",
TUN_DIR_PATH
);
println!(
" You may need to run with root privileges or manually create the TUN device."
log::warn!(
"\tYou may need to run with root privileges or manually create the TUN device."
);
Self::print_troubleshooting_info();
return;
@@ -330,20 +327,14 @@ impl VirtualNic {
dev_node,
) {
Ok(_) => {
tracing::info!("Successfully created TUN device node {}", TUN_DEV_PATH);
println!("✓ Created TUN device node {}", TUN_DEV_PATH);
log::info!("Successfully created TUN device node {}", TUN_DEV_PATH);
}
Err(e) => {
Err(error) => {
tracing::warn!(
"Failed to create TUN device node {}: {}. Continuing anyway.",
%error,
"Failed to create TUN device node {}. Continuing anyway.",
TUN_DEV_PATH,
e
);
println!(
"⚠ Warning: Failed to create TUN device node {}.",
TUN_DEV_PATH
);
println!(" Error: {}", e);
Self::print_troubleshooting_info();
}
}
@@ -352,13 +343,15 @@ impl VirtualNic {
/// Print troubleshooting information for TUN device issues
#[cfg(target_os = "linux")]
fn print_troubleshooting_info() {
println!(" Possible solutions:");
println!(" 1. Run with root privileges: sudo ./easytier-core [options]");
println!(" 2. Manually create TUN device: sudo mkdir -p /dev/net && sudo mknod /dev/net/tun c 10 200");
println!(" 3. Load TUN kernel module: sudo modprobe tun");
println!(" 4. Use --no-tun flag if TUN functionality is not needed");
println!(" 5. Check if your system/container supports TUN devices");
println!(" Note: TUN functionality may still work if the kernel supports dynamic device creation.");
log::info!(
"Possible solutions:\
\n\t1. Run with root privileges: sudo ./easytier-core [options]\
\n\t2. Manually create TUN device: sudo mkdir -p /dev/net && sudo mknod /dev/net/tun c 10 200\
\n\t3. Load TUN kernel module: sudo modprobe tun\
\n\t4. Use --no-tun flag if TUN functionality is not needed\
\n\t5. Check if your system/container supports TUN devices\
\nNote: TUN functionality may still work if the kernel supports dynamic device creation."
);
}
/// For non-Linux systems, this is a no-op
@@ -535,10 +528,9 @@ impl VirtualNic {
match crate::arch::windows::add_self_to_firewall_allowlist() {
Ok(_) => tracing::info!("add_self_to_firewall_allowlist successful!"),
Err(e) => {
println!("Failed to add Easytier to firewall allowlist, Subnet proxy and KCP proxy may not work properly. error: {}", e);
println!("You can add firewall rules manually, or use --use-smoltcp to run with user-space TCP/IP stack.");
println!();
Err(error) => {
log::warn!(%error, "Failed to add Easytier to firewall allowlist, Subnet proxy and KCP proxy may not work properly.");
log::warn!("You can add firewall rules manually, or use --use-smoltcp to run with user-space TCP/IP stack.");
}
}
@@ -592,7 +584,7 @@ impl VirtualNic {
&mut self,
tun_fd: std::os::fd::RawFd,
) -> Result<Box<dyn Tunnel>, Error> {
println!("tun_fd: {}", tun_fd);
log::debug!(%tun_fd);
let mut config = Configuration::default();
config.layer(Layer::L3);
@@ -711,19 +703,11 @@ impl VirtualNic {
ifname
);
}
Err(e) => {
tracing::warn!("Failed to configure Windows Firewall for {}: {}", ifname, e);
println!(
"⚠ Warning: Failed to configure Windows Firewall for interface {}.",
ifname
);
println!(" This may cause connectivity issues with ping and other network functions.");
println!(
" Please run as Administrator or manually configure Windows Firewall."
);
println!(
" Alternatively, you can disable Windows Firewall for testing purposes."
);
Err(error) => {
log::warn!(%error, "Failed to configure Windows Firewall for interface {}\
\n\tThis may cause connectivity issues with ping and other network functions.\
\n\tPlease run as Administrator or manually configure Windows Firewall.\
\n\tAlternatively, you can disable Windows Firewall for testing purposes.", ifname);
}
}
}
+101 -108
View File
@@ -1,11 +1,12 @@
use std::{collections::BTreeMap, path::PathBuf, sync::Arc};
use dashmap::DashMap;
use std::fmt::{Display, Formatter};
use std::{collections::BTreeMap, path::PathBuf, sync::Arc};
use crate::{
common::{
config::{ConfigFileControl, ConfigLoader, TomlConfigLoader},
global_ctx::{EventBusSubscriber, GlobalCtxEvent},
log,
scoped_task::ScopedTask,
},
launcher::{NetworkInstance, NetworkInstanceRunningInfo},
@@ -85,10 +86,9 @@ impl NetworkInstanceManager {
.map(|event| ScopedTask::from(handle_event(instance_id, event)));
instance_stop_notifier.notified().await;
if let Some(instance) = instance_map.get(&instance_id) {
if let Some(e) = instance.get_latest_error_msg() {
tracing::error!(?e, ?instance_id, "instance stopped with error");
eprintln!("instance {} stopped with error: {}", instance_id, e);
instance_error_messages.insert(instance_id, e);
if let Some(error) = instance.get_latest_error_msg() {
log::error!(%error, "instance {} stopped", instance_id);
instance_error_messages.insert(instance_id, error);
}
}
stop_check_notifier.notify_one();
@@ -261,6 +261,23 @@ impl NetworkInstanceManager {
}
}
macro_rules! event {
($lvl:ident, category: $cat:expr, $($args:tt)+) => {
event!(@impl $lvl, concat!("INSTANCE::", $cat), $($args)+)
};
($lvl:ident, $($args:tt)+) => {
event!(@impl $lvl, "INSTANCE", $($args)+)
};
(@impl $lvl:ident, $cat:expr, $($args:tt)+) => {
log::$lvl!(
category: $cat,
$($args)+
);
};
}
#[tracing::instrument]
fn handle_event(
instance_id: uuid::Uuid,
@@ -270,158 +287,140 @@ fn handle_event(
loop {
if let Ok(e) = events.recv().await {
match e {
GlobalCtxEvent::PeerAdded(p) => {
print_event(instance_id, format!("new peer added. peer_id: {}", p));
GlobalCtxEvent::PeerAdded(peer_id) => {
event!(info, peer_id, "[{}] new peer added", instance_id);
}
GlobalCtxEvent::PeerRemoved(p) => {
print_event(instance_id, format!("peer removed. peer_id: {}", p));
GlobalCtxEvent::PeerRemoved(peer_id) => {
event!(info, peer_id, "[{}] peer removed", instance_id);
}
GlobalCtxEvent::PeerConnAdded(p) => {
print_event(
GlobalCtxEvent::PeerConnAdded(conn_info) => {
event!(
info,
category: "CONNECTION",
%conn_info,
"[{}] new peer connection added",
instance_id,
format!(
"new peer connection added. conn_info: {}",
peer_conn_info_to_string(p)
),
);
}
GlobalCtxEvent::PeerConnRemoved(p) => {
print_event(
GlobalCtxEvent::PeerConnRemoved(conn_info) => {
event!(
info,
category: "CONNECTION",
%conn_info,
"[{}] peer connection removed",
instance_id,
format!(
"peer connection removed. conn_info: {}",
peer_conn_info_to_string(p)
),
);
}
GlobalCtxEvent::ListenerAddFailed(p, msg) => {
print_event(
instance_id,
format!("listener add failed. listener: {}, msg: {}", p, msg),
);
GlobalCtxEvent::ListenerAddFailed(listener, msg) => {
event!(warn, %listener, msg, "[{}] listener add failed", instance_id);
}
GlobalCtxEvent::ListenerAcceptFailed(p, msg) => {
print_event(
instance_id,
format!("listener accept failed. listener: {}, msg: {}", p, msg),
);
GlobalCtxEvent::ListenerAcceptFailed(listener, msg) => {
event!(warn, %listener, msg, "[{}] listener accept failed", instance_id);
}
GlobalCtxEvent::ListenerAdded(p) => {
if p.scheme() == "ring" {
GlobalCtxEvent::ListenerAdded(listener) => {
if listener.scheme() == "ring" {
continue;
}
print_event(instance_id, format!("new listener added. listener: {}", p));
event!(
info,
%listener,
"[{}] new listener added",
instance_id
);
}
GlobalCtxEvent::ConnectionAccepted(local, remote) => {
print_event(
instance_id,
format!(
"new connection accepted. local: {}, remote: {}",
local, remote
),
);
event!(info, category: "CONNECTION", local, remote, "[{}] new connection accepted", instance_id);
}
GlobalCtxEvent::ConnectionError(local, remote, err) => {
print_event(
instance_id,
format!(
"connection error. local: {}, remote: {}, err: {}",
local, remote, err
),
);
event!(info, category: "CONNECTION", local, remote, err, "[{}] connection error", instance_id);
}
GlobalCtxEvent::TunDeviceReady(dev) => {
print_event(instance_id, format!("tun device ready. dev: {}", dev));
event!(info, dev, "[{}] tun device ready", instance_id);
}
GlobalCtxEvent::TunDeviceError(err) => {
print_event(instance_id, format!("tun device error. err: {}", err));
event!(error, %err, "[{}] tun device error", instance_id);
}
GlobalCtxEvent::Connecting(dst) => {
print_event(instance_id, format!("connecting to peer. dst: {}", dst));
event!(info, category: "CONNECTION", %dst, "[{}] connecting to peer", instance_id);
}
GlobalCtxEvent::ConnectError(dst, ip_version, err) => {
print_event(
instance_id,
format!(
"connect to peer error. dst: {}, ip_version: {}, err: {}",
dst, ip_version, err
),
GlobalCtxEvent::ConnectError(dst, ip_version, error) => {
event!(
info,
category: "CONNECTION",
dst,
ip_version,
%error,
"[{}] connect to peer error",
instance_id
);
}
GlobalCtxEvent::VpnPortalStarted(portal) => {
print_event(
instance_id,
format!("vpn portal started. portal: {}", portal),
);
event!(info, portal, "[{}] vpn portal started", instance_id);
}
GlobalCtxEvent::VpnPortalClientConnected(portal, client_addr) => {
print_event(
instance_id,
format!(
"vpn portal client connected. portal: {}, client_addr: {}",
portal, client_addr
),
event!(
info,
portal,
client_addr,
"[{}] vpn portal client connected",
instance_id
);
}
GlobalCtxEvent::VpnPortalClientDisconnected(portal, client_addr) => {
print_event(
instance_id,
format!(
"vpn portal client disconnected. portal: {}, client_addr: {}",
portal, client_addr
),
event!(
info,
portal,
client_addr,
"[{}] vpn portal client disconnected",
instance_id
);
}
GlobalCtxEvent::DhcpIpv4Changed(old, new) => {
print_event(
instance_id,
format!("dhcp ip changed. old: {:?}, new: {:?}", old, new),
);
event!(info, ?old, ?new, "[{}] dhcp ip changed", instance_id);
}
GlobalCtxEvent::DhcpIpv4Conflicted(ip) => {
print_event(instance_id, format!("dhcp ip conflict. ip: {:?}", ip));
event!(info, ?ip, "[{}] dhcp ip conflict", instance_id);
}
GlobalCtxEvent::PortForwardAdded(cfg) => {
print_event(
event!(
info,
local = %cfg.bind_addr.unwrap(),
remote = %cfg.dst_addr.unwrap(),
proto = %cfg.socket_type().as_str_name(),
"[{}] port forward added",
instance_id,
format!(
"port forward added. local: {}, remote: {}, proto: {}",
cfg.bind_addr.unwrap(),
cfg.dst_addr.unwrap(),
cfg.socket_type().as_str_name()
),
);
}
GlobalCtxEvent::ConfigPatched(patch) => {
print_event(instance_id, format!("config patched. patch: {:?}", patch));
event!(info, ?patch, "[{}] config patched", instance_id);
}
GlobalCtxEvent::ProxyCidrsUpdated(added, removed) => {
print_event(
instance_id,
format!(
"proxy CIDRs updated. added: {:?}, removed: {:?}",
added, removed
),
event!(
info,
?added,
?removed,
"[{}] proxy CIDRs updated",
instance_id
);
}
}
@@ -432,20 +431,14 @@ fn handle_event(
})
}
fn print_event(instance_id: uuid::Uuid, msg: String) {
println!(
"{}: [{}] {}",
chrono::Local::now().format("%Y-%m-%d %H:%M:%S"),
instance_id,
msg
);
}
fn peer_conn_info_to_string(p: proto::api::instance::PeerConnInfo) -> String {
format!(
"my_peer_id: {}, dst_peer_id: {}, tunnel_info: {:?}",
p.my_peer_id, p.peer_id, p.tunnel
)
impl Display for proto::api::instance::PeerConnInfo {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PeerConnInfo")
.field("my_peer_id", &self.my_peer_id)
.field("dst_peer_id", &self.peer_id)
.field("tunnel_info", &self.tunnel)
.finish()
}
}
#[cfg(test)]
+5 -2
View File
@@ -1,6 +1,9 @@
use std::sync::Arc;
use crate::{common::config::EncryptionAlgorithm, tunnel::packet_def::ZCPacket};
use crate::{
common::{config::EncryptionAlgorithm, log},
tunnel::packet_def::ZCPacket,
};
#[cfg(feature = "wireguard")]
pub mod ring_aes_gcm;
@@ -66,7 +69,7 @@ pub fn create_encryptor(
let algorithm = match EncryptionAlgorithm::try_from(algorithm) {
Ok(algorithm) => algorithm,
Err(_) => {
eprintln!(
log::warn!(
"Unknown encryption algorithm: {}, falling back to default AES-GCM",
algorithm
);
+5 -3
View File
@@ -4,6 +4,8 @@ use std::path::PathBuf;
use service_manager::ServiceManager as _;
use crate::common::log;
#[derive(Debug)]
pub struct ServiceInstallOptions {
pub program: PathBuf,
@@ -72,7 +74,7 @@ impl Service {
let kind = service_manager::ServiceManagerKind::native()?;
println!("service manager kind: {:?}", kind);
log::info!("service manager kind: {:?}", kind);
Ok(Self {
label: name.parse()?,
@@ -98,7 +100,7 @@ impl Service {
self.service_manager
.update(ctx)
.map_err(|e| anyhow::anyhow!("failed to update service: {:?}", e))?;
println!("Service updated successfully! Service Name: {}", self.label);
log::info!("Service updated successfully! Service Name: {}", self.label);
return Ok(());
}
@@ -106,7 +108,7 @@ impl Service {
.install(ctx)
.map_err(|e| anyhow::anyhow!("failed to install service: {:?}", e))?;
println!(
log::info!(
"Service installed successfully! Service Name: {}",
self.label
);
+35 -168
View File
@@ -1,15 +1,7 @@
use crate::common::log;
use indoc::formatdoc;
use std::{fs::OpenOptions, str::FromStr};
use anyhow::Context;
use tracing::level_filters::LevelFilter;
use tracing_subscriber::{
layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Layer, Registry,
};
use crate::common::{
config::LoggingConfigLoader, get_logger_timer_rfc3339, tracing_rolling_appender::*,
};
pub type PeerRoutePair = crate::proto::api::instance::PeerRoutePair;
pub fn cost_to_str(cost: i32) -> String {
@@ -24,124 +16,6 @@ pub fn float_to_str(f: f64, precision: usize) -> String {
format!("{:.1$}", f, precision)
}
pub type NewFilterSender = std::sync::mpsc::Sender<String>;
pub fn init_logger(
config: impl LoggingConfigLoader,
need_reload: bool,
) -> Result<Option<NewFilterSender>, anyhow::Error> {
use crate::rpc_service::logger::{CURRENT_LOG_LEVEL, LOGGER_LEVEL_SENDER};
let file_config = config.get_file_logger_config();
let file_level = file_config
.level
.map(|s| s.parse().unwrap())
.unwrap_or(LevelFilter::OFF);
let mut ret_sender: Option<NewFilterSender> = None;
// logger to rolling file
let mut file_layer = None;
if file_level != LevelFilter::OFF || need_reload {
let mut l = tracing_subscriber::fmt::layer();
l.set_ansi(false);
let file_filter = EnvFilter::builder()
.with_default_directive(file_level.into())
.from_env()
.with_context(|| "failed to create file filter")?;
let (file_filter, file_filter_reloader) =
tracing_subscriber::reload::Layer::new(file_filter);
if need_reload {
let (sender, recver) = std::sync::mpsc::channel();
ret_sender = Some(sender.clone());
// 初始化全局状态
let _ = LOGGER_LEVEL_SENDER.set(std::sync::Mutex::new(sender));
let _ = CURRENT_LOG_LEVEL.set(std::sync::Mutex::new(file_level.to_string()));
std::thread::spawn(move || {
while let Ok(lf) = recver.recv() {
let e = file_filter_reloader.modify(|f| {
if let Ok(nf) = EnvFilter::builder()
.with_default_directive(lf.parse::<LevelFilter>().unwrap().into())
.from_env()
.with_context(|| "failed to create file filter")
{
println!("Reload log filter succeed, new filter level: {:?}", lf);
*f = nf;
}
});
if e.is_err() {
println!("Failed to reload log filter: {:?}", e);
}
}
println!("Stop log filter reloader");
});
}
let dir = file_config.dir.as_deref().unwrap_or(".");
let file = file_config.file.as_deref().unwrap_or("easytier.log");
let path = std::path::Path::new(dir).join(file);
let path_str = path.to_string_lossy().into_owned();
let builder = RollingFileAppenderBase::builder();
let file_appender = builder
.filename(path_str)
.condition_daily()
.max_filecount(file_config.count.unwrap_or(10))
.condition_max_file_size(file_config.size_mb.unwrap_or(100) * 1024 * 1024)
.build()
.unwrap();
let wrapper = FileAppenderWrapper::new(file_appender);
// Create a simple wrapper that implements MakeWriter
file_layer = Some(
l.with_writer(wrapper)
.with_timer(get_logger_timer_rfc3339())
.with_filter(file_filter),
);
}
// logger to console
let console_config = config.get_console_logger_config();
let console_level = console_config
.level
.map(|s| s.parse().unwrap())
.unwrap_or(LevelFilter::OFF);
let console_filter = EnvFilter::builder()
.with_default_directive(console_level.into())
.from_env()
.unwrap();
let console_layer = tracing_subscriber::fmt::layer()
.pretty()
.with_timer(get_logger_timer_rfc3339())
.with_writer(std::io::stderr)
.with_filter(console_filter);
let registry = Registry::default();
#[cfg(not(feature = "tracing"))]
{
registry.with(console_layer).with(file_layer).init();
}
#[cfg(feature = "tracing")]
{
let console_subscriber_layer = console_subscriber::ConsoleLayer::builder().spawn();
registry
.with(console_layer)
.with(file_layer)
.with(console_subscriber_layer)
.init();
}
Ok(ret_sender)
}
#[cfg(target_os = "windows")]
pub fn utf8_or_gbk_to_string(s: &[u8]) -> String {
use encoding::{all::GBK, DecoderTrap, Encoding};
@@ -165,13 +39,17 @@ pub fn setup_panic_handler() {
use std::backtrace;
use std::io::Write;
std::panic::set_hook(Box::new(|info| {
let mut stderr = std::io::stderr();
let sep = format!("{}\n", "=======".repeat(10));
let _ = stderr.write_all(format!("{sep}{}\n{sep}", "!PANIC!".repeat(10)).as_bytes());
PANIC_COUNT.with(|c| {
let mut count = c.borrow_mut();
*count += 1;
});
let panic_count = PANIC_COUNT.with(|c| *c.borrow());
if panic_count > 1 {
println!("panic happened more than once, exit immediately");
log::error!("panic happened more than once, exit immediately");
std::process::exit(1);
}
@@ -208,36 +86,42 @@ pub fn setup_panic_handler() {
}
}
println!("{}", rust_i18n::t!("core_app.panic_backtrace_save"));
log::error!("{}", rust_i18n::t!("core_app.panic_backtrace_save"));
// write str to stderr & file
let write_err = |s: String| {
let mut stderr = std::io::stderr();
let content = format!("{}: {}", chrono::Local::now(), s);
let _ = writeln!(stderr, "{}", content);
let mut write_err = |s: String| {
let _ = stderr.write_all(s.as_bytes());
if let Some(mut f) = file.as_ref() {
let _ = writeln!(f, "{}", content);
let _ = f.write_all(s.as_bytes());
}
};
write_err("panic occurred, if this is a bug, please report this issue on github (https://github.com/easytier/easytier/issues)".to_string());
write_err(format!("easytier version: {}", crate::VERSION));
write_err(format!("os version: {}", std::env::consts::OS));
write_err(format!("arch: {}", std::env::consts::ARCH));
write_err(format!(
"panic is recorded in: {}",
file_path
let msg = formatdoc! {"
panic occurred, if this is a bug, please report this issue on github (https://github.com/easytier/easytier/issues)
easytier version: {version}
os: {os}
arch: {arch}
panic is recorded in: {file}
thread: {thread}
time: {time}
location: {location}
panic info: {payload}
",
version = crate::VERSION,
os = std::env::consts::OS,
arch = std::env::consts::ARCH,
file = file_path
.and_then(|p| p.to_str().map(|x| x.to_string()))
.unwrap_or("<no file>".to_string())
));
write_err(format!("thread: {}", thread));
write_err(format!("time: {}", chrono::Local::now()));
write_err(format!("location: {}", location));
write_err(format!("panic info: {}", payload_str));
.unwrap_or("<no file>".to_string()),
thread = thread,
time = chrono::Local::now(),
location = location,
payload = payload_str,
};
// backtrace is risky, so use it last
let backtrace = backtrace::Backtrace::force_capture();
write_err(format!("backtrace: {:#?}", backtrace));
write_err(msg);
write_err(sep);
write_err(format!("{:#?}", backtrace::Backtrace::force_capture()));
std::process::exit(1);
}));
@@ -257,20 +141,3 @@ pub fn weak_upgrade<T>(weak: &std::sync::Weak<T>) -> anyhow::Result<std::sync::A
weak.upgrade()
.ok_or_else(|| anyhow::anyhow!("{} not available", std::any::type_name::<T>()))
}
#[cfg(test)]
mod tests {
use crate::common::config::{self};
use super::*;
async fn test_logger_reload() {
println!("current working dir: {:?}", std::env::current_dir());
let config = config::LoggingConfigBuilder::default().build().unwrap();
let s = init_logger(&config, true).unwrap();
tracing::debug!("test not display debug");
s.unwrap().send(LevelFilter::DEBUG.to_string()).unwrap();
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
tracing::debug!("test display debug");
}
}
+6 -8
View File
@@ -2,7 +2,7 @@ use std::sync::Arc;
use crate::{
common::{
config::TomlConfigLoader, global_ctx::GlobalCtx, scoped_task::ScopedTask,
config::TomlConfigLoader, global_ctx::GlobalCtx, log, scoped_task::ScopedTask,
set_default_machine_id, stun::MockStunInfoCollector,
},
connector::create_connector_by_url,
@@ -87,18 +87,16 @@ impl WebClient {
loop {
let conn = match connector.connect().await {
Ok(conn) => conn,
Err(e) => {
println!(
"Failed to connect to the server ({}), retrying in 5 seconds...",
e
);
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
Err(error) => {
let wait = 1;
log::warn!(%error, "Failed to connect to the server, retrying in {} seconds...", wait);
tokio::time::sleep(std::time::Duration::from_secs(wait)).await;
continue;
}
};
connected.store(true, Ordering::Release);
println!("Successfully connected to {:?}", conn.info());
log::info!("Successfully connected to {:?}", conn.info());
let mut session = session::Session::new(conn, controller.clone());
session.wait().await;