pub(crate) struct Args {
pub(crate) verbosity: Verbosity,
+ pub(crate) log_file: Option<PathBuf>,
pub(crate) command: Command,
}
if matches.contains("--version") {
matches.finish().or_else(handle_extra_flags)?;
- return Ok(Args { verbosity: Verbosity::Normal, command: Command::Version });
+ return Ok(Args {
+ verbosity: Verbosity::Normal,
+ log_file: None,
+ command: Command::Version,
+ });
}
let verbosity = match (
(false, true, false) => Verbosity::Verbose,
(false, true, true) => bail!("Invalid flags: -q conflicts with -v"),
};
+ let log_file = matches.opt_value_from_str("--log-file")?;
- let help = Ok(Args { verbosity, command: Command::Help });
+ let help = Ok(Args { verbosity, log_file: None, command: Command::Help });
let subcommand = match matches.subcommand()? {
Some(it) => it,
None => {
return help;
}
matches.finish().or_else(handle_extra_flags)?;
- return Ok(Args { verbosity, command: Command::RunServer });
+ return Ok(Args { verbosity, log_file, command: Command::RunServer });
}
};
let command = match subcommand.as_str() {
return help;
}
};
- Ok(Args { verbosity, command })
+ Ok(Args { verbosity, log_file, command })
}
}
--- /dev/null
+//! Simple logger that logs either to stderr or to a file, using `env_logger`
+//! filter syntax. Amusingly, there's no crates.io crate that can do this and
+//! only this.
+
+use std::{
+ fs::File,
+ io::{BufWriter, Write},
+};
+
+use env_logger::filter::{Builder, Filter};
+use log::{Log, Metadata, Record};
+use parking_lot::Mutex;
+
+pub(crate) struct Logger {
+ filter: Filter,
+ file: Option<Mutex<BufWriter<File>>>,
+}
+
+impl Logger {
+ pub(crate) fn new(log_file: Option<File>, filter: Option<&str>) -> Logger {
+ let filter = {
+ let mut builder = Builder::new();
+ if let Some(filter) = filter {
+ builder.parse(filter);
+ }
+ builder.build()
+ };
+
+ let file = log_file.map(|it| Mutex::new(BufWriter::new(it)));
+
+ Logger { filter, file }
+ }
+
+ pub(crate) fn install(self) {
+ let max_level = self.filter.filter();
+ let _ = log::set_boxed_logger(Box::new(self)).map(|()| log::set_max_level(max_level));
+ }
+}
+
+impl Log for Logger {
+ fn enabled(&self, metadata: &Metadata) -> bool {
+ self.filter.enabled(metadata)
+ }
+
+ fn log(&self, record: &Record) {
+ if !self.filter.matches(record) {
+ return;
+ }
+ match &self.file {
+ Some(w) => {
+ let _ = writeln!(
+ w.lock(),
+ "[{} {}] {}",
+ record.level(),
+ record.module_path().unwrap_or_default(),
+ record.args(),
+ );
+ }
+ None => eprintln!(
+ "[{} {}] {}",
+ record.level(),
+ record.module_path().unwrap_or_default(),
+ record.args(),
+ ),
+ }
+ }
+
+ fn flush(&self) {
+ if let Some(w) = &self.file {
+ let _ = w.lock().flush();
+ }
+ }
+}
//!
//! Based on cli flags, either spawns an LSP server, or runs a batch analysis
mod args;
+mod logger;
-use std::{convert::TryFrom, process};
+use std::{convert::TryFrom, env, fs, path::PathBuf, process};
use lsp_server::Connection;
use project_model::ProjectManifest;
}
fn try_main() -> Result<()> {
- setup_logging()?;
let args = args::Args::parse()?;
+ setup_logging(args.log_file)?;
match args.command {
args::Command::RunServer => run_server()?,
args::Command::ProcMacro => proc_macro_srv::cli::run()?,
Ok(())
}
-fn setup_logging() -> Result<()> {
- std::env::set_var("RUST_BACKTRACE", "short");
- env_logger::try_init_from_env("RA_LOG")?;
+fn setup_logging(log_file: Option<PathBuf>) -> Result<()> {
+ env::set_var("RUST_BACKTRACE", "short");
+
+ let log_file = match log_file {
+ Some(path) => {
+ if let Some(parent) = path.parent() {
+ let _ = fs::create_dir_all(parent);
+ }
+ Some(fs::File::create(path)?)
+ }
+ None => None,
+ };
+ let filter = env::var("RA_LOG").ok();
+ logger::Logger::new(log_file, filter.as_deref()).install();
+
profile::init();
Ok(())
}
{
Some(it) => it,
None => {
- let cwd = std::env::current_dir()?;
+ let cwd = env::current_dir()?;
AbsPathBuf::assert(cwd)
}
};
See https://github.com/rust-analyzer/rust-project.json-example for a small example.
-You can set `RA_LOG` environmental variable to `"'rust_analyzer=info"` to inspect how rust-analyzer handles config and project loading.
+You can set `RA_LOG` environmental variable to `rust_analyzer=info` to inspect how rust-analyzer handles config and project loading.
== Features