make server logging show messages in the frontend

now you can use the log crate and get messages in the frontend.
This commit is contained in:
Brandon W Maister 2024-07-31 10:43:02 -04:00 committed by John Doty
parent 6c10d8eece
commit 05c0a0a4de
5 changed files with 78 additions and 22 deletions

24
Cargo.lock generated
View file

@ -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"

View file

@ -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"] }

View file

@ -323,6 +323,7 @@ async fn client_main<Reader: AsyncRead + Unpin, Writer: AsyncWrite + Unpin>(
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<ui::UIEvent>,
) {
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) => ()
}
}

View file

@ -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<String>) -> 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<String>) -> 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<String>) -> 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]

View file

@ -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 {