diff --git a/.vscode/launch.json b/.vscode/launch.json index 8ca27d87836..021b8f048cf 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -120,6 +120,12 @@ "sourceMaps": true, "outFiles": [ "${workspaceFolder}/editors/code/out/tests/unit/**/*.js" ], "preLaunchTask": "Pretest" + }, + { + "name": "Win Attach to Server", + "type": "cppvsdbg", + "processId":"${command:pickProcess}", + "request": "attach" } ] } diff --git a/crates/rust-analyzer/src/bin/args.rs b/crates/rust-analyzer/src/bin/args.rs index 7d917946e33..37d8414f4e6 100644 --- a/crates/rust-analyzer/src/bin/args.rs +++ b/crates/rust-analyzer/src/bin/args.rs @@ -14,7 +14,9 @@ use vfs::AbsPathBuf; pub(crate) struct Args { pub(crate) verbosity: Verbosity, pub(crate) log_file: Option, + pub(crate) no_buffering: bool, pub(crate) command: Command, + pub(crate) wait_dbg: bool, } pub(crate) enum Command { @@ -47,11 +49,17 @@ FLAGS: -vv, --spammy -q, --quiet Set verbosity - --log-file Log to the specified filed instead of stderr + --log-file Log to the specified file instead of stderr + --no-log-buffering + Flush log records to the file immediately + + --wait-dbg Wait until a debugger is attached to. + The flag is valid for debug builds only ENVIRONMENTAL VARIABLES: RA_LOG Set log filter in env_logger format RA_PROFILE Enable hierarchical profiler + RA_WAIT_DBG If set acts like a --wait-dbg flag COMMANDS: @@ -114,6 +122,8 @@ impl Args { verbosity: Verbosity::Normal, log_file: None, command: Command::Version, + no_buffering: false, + wait_dbg: false, }); } @@ -130,21 +140,41 @@ impl Args { (false, true, true) => bail!("Invalid flags: -q conflicts with -v"), }; let log_file = matches.opt_value_from_str("--log-file")?; + let no_buffering = matches.contains("--no-log-buffering"); + let wait_dbg = matches.contains("--wait-dbg"); if matches.contains(["-h", "--help"]) { eprintln!("{}", HELP); - return Ok(Args { verbosity, log_file: None, command: Command::Help }); + return Ok(Args { + verbosity, + log_file: None, + command: Command::Help, + no_buffering, + wait_dbg, + }); } if matches.contains("--print-config-schema") { - return Ok(Args { verbosity, log_file, command: Command::PrintConfigSchema }); + return Ok(Args { + verbosity, + log_file, + command: Command::PrintConfigSchema, + no_buffering, + wait_dbg, + }); } let subcommand = match matches.subcommand()? { Some(it) => it, None => { finish_args(matches)?; - return Ok(Args { verbosity, log_file, command: Command::RunServer }); + return Ok(Args { + verbosity, + log_file, + command: Command::RunServer, + no_buffering, + wait_dbg, + }); } }; let command = match subcommand.as_str() { @@ -219,11 +249,17 @@ impl Args { }, _ => { eprintln!("{}", HELP); - return Ok(Args { verbosity, log_file: None, command: Command::Help }); + return Ok(Args { + verbosity, + log_file: None, + command: Command::Help, + no_buffering, + wait_dbg, + }); } }; finish_args(matches)?; - Ok(Args { verbosity, log_file, command }) + Ok(Args { verbosity, log_file, command, no_buffering, wait_dbg }) } } diff --git a/crates/rust-analyzer/src/bin/logger.rs b/crates/rust-analyzer/src/bin/logger.rs index 3bcb1ae37d4..14887c5ccfe 100644 --- a/crates/rust-analyzer/src/bin/logger.rs +++ b/crates/rust-analyzer/src/bin/logger.rs @@ -4,7 +4,7 @@ use std::{ fs::File, - io::{BufWriter, Write}, + io::{self, BufWriter, Write}, }; use env_logger::filter::{Builder, Filter}; @@ -14,10 +14,11 @@ use parking_lot::Mutex; pub(crate) struct Logger { filter: Filter, file: Option>>, + no_buffering: bool, } impl Logger { - pub(crate) fn new(log_file: Option, filter: Option<&str>) -> Logger { + pub(crate) fn new(log_file: Option, no_buffering: bool, filter: Option<&str>) -> Logger { let filter = { let mut builder = Builder::new(); if let Some(filter) = filter { @@ -28,7 +29,7 @@ impl Logger { let file = log_file.map(|it| Mutex::new(BufWriter::new(it))); - Logger { filter, file } + Logger { filter, file, no_buffering } } pub(crate) fn install(self) { @@ -46,7 +47,8 @@ impl Log for Logger { if !self.filter.matches(record) { return; } - match &self.file { + + let should_flush = match &self.file { Some(w) => { let _ = writeln!( w.lock(), @@ -55,19 +57,32 @@ impl Log for Logger { record.module_path().unwrap_or_default(), record.args(), ); + self.no_buffering } - None => eprintln!( - "[{} {}] {}", - record.level(), - record.module_path().unwrap_or_default(), - record.args(), - ), + None => { + eprintln!( + "[{} {}] {}", + record.level(), + record.module_path().unwrap_or_default(), + record.args(), + ); + true // flush stderr unconditionally + } + }; + + if should_flush { + self.flush(); } } fn flush(&self) { - if let Some(w) = &self.file { - let _ = w.lock().flush(); + match &self.file { + Some(w) => { + let _ = w.lock().flush(); + } + None => { + let _ = io::stderr().flush(); + } } } } diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index bee2eedbccb..088b17b03b7 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs @@ -21,6 +21,7 @@ static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; fn main() { if let Err(err) = try_main() { + log::error!("Unexpected error: {}", err); eprintln!("{}", err); process::exit(101); } @@ -28,7 +29,17 @@ fn main() { fn try_main() -> Result<()> { let args = args::Args::parse()?; - setup_logging(args.log_file)?; + + #[cfg(debug_assertions)] + if args.wait_dbg || env::var("RA_WAIT_DBG").is_ok() { + #[allow(unused_mut)] + let mut d = 4; + while d == 4 { + d = 4; + } + } + + setup_logging(args.log_file, args.no_buffering)?; match args.command { args::Command::RunServer => run_server()?, args::Command::PrintConfigSchema => { @@ -56,7 +67,7 @@ fn try_main() -> Result<()> { Ok(()) } -fn setup_logging(log_file: Option) -> Result<()> { +fn setup_logging(log_file: Option, no_buffering: bool) -> Result<()> { env::set_var("RUST_BACKTRACE", "short"); let log_file = match log_file { @@ -69,7 +80,7 @@ fn setup_logging(log_file: Option) -> Result<()> { None => None, }; let filter = env::var("RA_LOG").ok(); - logger::Logger::new(log_file, filter.as_deref()).install(); + logger::Logger::new(log_file, no_buffering, filter.as_deref()).install(); tracing_setup::setup_tracing()?; diff --git a/docs/dev/debugging.md b/docs/dev/debugging.md index 8c48fd5a1fe..cc7a790ff46 100644 --- a/docs/dev/debugging.md +++ b/docs/dev/debugging.md @@ -57,6 +57,14 @@ To apply changes to an already running debug process, press Ctrl+Shift+P