diff --git a/Cargo.lock b/Cargo.lock index 9ce977d..42b78ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,6 +28,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + [[package]] name = "anstream" version = "0.6.4" @@ -106,6 +115,7 @@ dependencies = [ "tokio", "tokio-stream", "tower-http", + "tracing-subscriber", "uuid", "which", ] @@ -1021,6 +1031,15 @@ dependencies = [ "tendril", ] +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "matches" version = "0.1.10" @@ -1123,6 +1142,16 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num_cpus" version = "1.16.0" @@ -1164,6 +1193,12 @@ dependencies = [ "hashbrown 0.12.3", ] +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parking_lot" version = "0.12.1" @@ -1477,6 +1512,50 @@ dependencies = [ "redox_syscall 0.2.16", ] +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.4", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + [[package]] name = "reqwest" version = "0.11.23" @@ -1829,6 +1908,15 @@ dependencies = [ "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "signal-hook" version = "0.3.17" @@ -2028,6 +2116,16 @@ dependencies = [ "syn 2.0.38", ] +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -2160,6 +2258,7 @@ dependencies = [ "pin-project-lite", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -2192,6 +2291,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", ] [[package]] @@ -2305,6 +2434,12 @@ dependencies = [ "getrandom 0.2.10", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "version_check" version = "0.9.4" diff --git a/Cargo.toml b/Cargo.toml index 2584bd4..2f05d69 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,4 +32,5 @@ futures-util = "0.3.30" tokio-stream = { version = "0.1.14", features = ["sync"] } rust-embed = "8.2.0" mime_guess = "2.0.4" -tower-http = "0.5.1" +tower-http = { version = "0.5.1", features = ["trace"] } +tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } diff --git a/src/cmd/stream.rs b/src/cmd/stream.rs index 5970e17..4f531b8 100644 --- a/src/cmd/stream.rs +++ b/src/cmd/stream.rs @@ -4,9 +4,11 @@ use crate::logger; use crate::pty; use crate::streamer::{self, KeyBindings}; use crate::tty; -use anyhow::Result; +use anyhow::{anyhow, Result}; use clap::Args; +use std::fs; use std::net::SocketAddr; +use std::path::PathBuf; #[derive(Debug, Args)] pub struct Cli { @@ -25,6 +27,10 @@ pub struct Cli { /// Override terminal size for the session #[arg(long, value_name = "COLSxROWS")] tty_size: Option, + + /// Log file path + #[arg(long)] + log_file: Option, } impl Cli { @@ -56,6 +62,8 @@ impl Cli { Box::new(tty::NullTty::open()?) }; + self.init_logging()?; + pty::exec( &exec_command, &exec_extra_env, @@ -76,6 +84,23 @@ impl Cli { .cloned() .or(config.cmd_stream_command()) } + + fn init_logging(&self) -> Result<()> { + if let Some(path) = self.log_file.as_ref() { + let file = fs::OpenOptions::new() + .create(true) + .append(true) + .open(path) + .map_err(|e| anyhow!("cannot open log file {}: {}", path.to_string_lossy(), e))?; + + tracing_subscriber::fmt() + .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) + .with_writer(file) + .init(); + } + + Ok(()) + } } fn get_key_bindings(config: &Config) -> Result { diff --git a/src/streamer/server.rs b/src/streamer/server.rs index 75b8664..31d09c0 100644 --- a/src/streamer/server.rs +++ b/src/streamer/server.rs @@ -17,6 +17,7 @@ use std::io; use std::net::SocketAddr; use tokio::sync::{mpsc, oneshot}; use tokio_stream::wrappers::errors::BroadcastStreamRecvError; +use tower_http::trace; #[derive(RustEmbed)] #[folder = "assets/"] @@ -30,10 +31,14 @@ pub async fn serve( listener.set_nonblocking(true)?; let listener = tokio::net::TcpListener::from_std(listener)?; + let trace = trace::TraceLayer::new_for_http() + .make_span_with(trace::DefaultMakeSpan::default().include_headers(true)); + let app = Router::new() .route("/ws", get(ws_handler)) .with_state(clients_tx) - .fallback(static_handler); + .fallback(static_handler) + .layer(trace); let signal = async { let _ = shutdown_rx.await;