diff --git a/Cargo.lock b/Cargo.lock index 40bf1cc..bd2c390 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -322,6 +322,25 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +[[package]] +name = "env_filter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +dependencies = [ + "log", +] + +[[package]] +name = "env_logger" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "env_filter", + "log", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -431,6 +450,7 @@ dependencies = [ "bytes", "copypasta", "crossterm", + "env_logger", "home", "indoc", "log", @@ -768,9 +788,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "malloc_buf" diff --git a/Cargo.toml b/Cargo.toml index 03af888..73c009c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ bollard = "0.17.0" bytes = "1" copypasta = "0.10.1" crossterm = { version = "0.25", features = ["event-stream"] } +env_logger = { version = "0.11.5", default-features = false } home = "0.5.4" indoc = "1" log = { version = "0.4", features = ["std"] } diff --git a/src/client/mod.rs b/src/client/mod.rs index e13b779..79b4b15 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -323,6 +323,7 @@ async fn client_main( async fn spawn_ssh( server: &str, sudo: bool, + log_filter: &str, ) -> Result<(tokio::process::Child, u16), std::io::Error> { let socks_port = { let listener = TcpListener::bind("127.0.0.1:0").await?; @@ -337,7 +338,9 @@ async fn spawn_ssh( if sudo { cmd.arg("sudo"); } - cmd.arg("fwd").arg("--server"); + cmd.arg(format!("FWD_LOG={log_filter}")) + .arg("fwd") + .arg("--server"); cmd.stdout(std::process::Stdio::piped()); cmd.stdin(std::process::Stdio::piped()); @@ -367,13 +370,15 @@ fn is_sigint(status: std::process::ExitStatus) -> bool { async fn client_connect_loop( remote: &str, sudo: bool, + log_filter: &str, events: mpsc::Sender, ) { loop { _ = events.send(ui::UIEvent::Disconnected).await; - let (mut child, socks_port) = - spawn_ssh(remote, sudo).await.expect("failed to spawn"); + let (mut child, socks_port) = spawn_ssh(remote, sudo, log_filter) + .await + .expect("failed to spawn"); let mut stderr = child .stderr @@ -431,7 +436,7 @@ async fn client_connect_loop( } } -pub async fn run_client(remote: &str, sudo: bool) { +pub async fn run_client(remote: &str, sudo: bool, log_filter: &str) { let (event_sender, event_receiver) = mpsc::channel(1024); _ = log::set_boxed_logger(ui::Logger::new(event_sender.clone())); log::set_max_level(LevelFilter::Info); @@ -449,7 +454,7 @@ pub async fn run_client(remote: &str, sudo: bool) { // Start the reconnect loop. tokio::select! { _ = ui.run() => (), - _ = client_connect_loop(remote, sudo, event_sender) => () + _ = client_connect_loop(remote, sudo, log_filter, event_sender) => () } } diff --git a/src/main.rs b/src/main.rs index 004739d..dcc0009 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,6 +26,10 @@ Options: run as root), but requires sudo access on the server and *might* end up forwarding ports that you do not want forwarded (e.g., port 22 for sshd, or port 53 for systemd.) + --log-filter FILTER + Set remote server's log level. Default is `warn`. Supports + all of Rust's env_logger filter syntax, e.g. + `--log-filter=fwd::trace`. "}); } @@ -34,7 +38,7 @@ enum Args { Help, Version, Server, - Client(String, bool), + Client(String, bool, String), Browse(String), Clip(String), Error, @@ -43,9 +47,11 @@ enum Args { fn parse_args(args: Vec) -> Args { let mut server = None; let mut sudo = None; + let mut log_filter = None; let mut rest = Vec::new(); - for arg in args.into_iter().skip(1) { + let mut arg_iter = args.into_iter().skip(1); + while let Some(arg) = arg_iter.next() { if arg == "--help" || arg == "-?" || arg == "-h" { return Args::Help; } else if arg == "--version" { @@ -54,6 +60,14 @@ fn parse_args(args: Vec) -> Args { server = Some(true) } else if arg == "--sudo" || arg == "-s" { sudo = Some(true) + } else if arg.starts_with("--log-filter") { + if arg.contains('=') { + log_filter = Some(arg.split('=').nth(1).unwrap().to_owned()); + } else if let Some(arg) = arg_iter.next() { + log_filter = Some(arg); + } else { + return Args::Error; + } } else { rest.push(arg) } @@ -71,20 +85,32 @@ fn parse_args(args: Vec) -> Args { if rest.len() == 2 { Args::Browse(rest[1].to_string()) } else if rest.len() == 1 { - Args::Client(rest[0].to_string(), sudo.unwrap_or(false)) + Args::Client( + rest[0].to_string(), + sudo.unwrap_or(false), + log_filter.unwrap_or("warn".to_owned()), + ) } else { Args::Error } } else if rest[0] == "clip" { if rest.len() == 1 { - Args::Client(rest[0].to_string(), sudo.unwrap_or(false)) + Args::Client( + rest[0].to_string(), + sudo.unwrap_or(false), + log_filter.unwrap_or("warn".to_owned()), + ) } else if rest.len() == 2 { Args::Clip(rest[1].to_string()) } else { Args::Error } } else if rest.len() == 1 { - Args::Client(rest[0].to_string(), sudo.unwrap_or(false)) + Args::Client( + rest[0].to_string(), + sudo.unwrap_or(false), + log_filter.unwrap_or("warn".to_owned()), + ) } else { Args::Error } @@ -124,8 +150,8 @@ async fn main() { Args::Clip(file) => { clip_file(file).await; } - Args::Client(server, sudo) => { - fwd::run_client(&server, sudo).await; + Args::Client(server, sudo, log_filter) => { + fwd::run_client(&server, sudo, &log_filter).await; } Args::Error => { usage(); @@ -175,14 +201,14 @@ mod tests { #[test] fn client() { - assert_arg_parse!(&["foo.com"], Args::Client(_, false)); - assert_arg_parse!(&["a"], Args::Client(_, false)); - assert_arg_parse!(&["browse"], Args::Client(_, false)); - assert_arg_parse!(&["clip"], Args::Client(_, false)); - assert_arg_parse!(&["foo.com", "--sudo"], Args::Client(_, true)); - assert_arg_parse!(&["a", "-s"], Args::Client(_, true)); - assert_arg_parse!(&["-s", "browse"], Args::Client(_, true)); - assert_arg_parse!(&["-s", "clip"], Args::Client(_, true)); + assert_arg_parse!(&["foo.com"], Args::Client(_, false, _)); + assert_arg_parse!(&["a"], Args::Client(_, false, _)); + assert_arg_parse!(&["browse"], Args::Client(_, false, _)); + assert_arg_parse!(&["clip"], Args::Client(_, false, _)); + assert_arg_parse!(&["foo.com", "--sudo"], Args::Client(_, true, _)); + assert_arg_parse!(&["a", "-s"], Args::Client(_, true, _)); + assert_arg_parse!(&["-s", "browse"], Args::Client(_, true, _)); + assert_arg_parse!(&["-s", "clip"], Args::Client(_, true, _)); } #[test] diff --git a/src/server/mod.rs b/src/server/mod.rs index de61f52..1188c98 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -82,6 +82,10 @@ async fn server_main< } pub async fn run_server() { + env_logger::Builder::from_env( + env_logger::Env::new().filter_or("FWD_LOG", "warn"), + ) + .init(); let stdin = tokio::io::stdin(); let stdout = tokio::io::stdout(); if let Err(e) = server_main(stdin, stdout).await {