diff --git a/Cargo.lock b/Cargo.lock index 9c2cd0004..1194a406b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -160,6 +160,7 @@ dependencies = [ "credibility 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "ssh2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "vmm 0.1.0", diff --git a/Cargo.toml b/Cargo.toml index 98a0bccc8..38ffb3951 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,8 @@ edition = "2018" [dependencies] clap = "2.33.0" +lazy_static = "1.3.0" +log = { version = "0.4.8", features = ["std"] } vmm = { path = "vmm" } [dev-dependencies] diff --git a/src/main.rs b/src/main.rs index 18a94089e..302817202 100755 --- a/src/main.rs +++ b/src/main.rs @@ -9,9 +9,55 @@ extern crate vmm; extern crate clap; use clap::{App, Arg}; +use log::LevelFilter; use std::process; +use std::sync::Mutex; use vmm::config; +struct Logger { + output: Mutex>, + start: std::time::Instant, +} + +impl log::Log for Logger { + fn enabled(&self, _metadata: &log::Metadata) -> bool { + true + } + + fn log(&self, record: &log::Record) { + if !self.enabled(record.metadata()) { + return; + } + + let now = std::time::Instant::now(); + let duration = now.duration_since(self.start); + + if record.file().is_some() && record.line().is_some() { + writeln!( + *(*(self.output.lock().unwrap())), + "cloud-hypervisor: {:?}: {}:{}:{} -- {}", + duration, + record.level(), + record.file().unwrap(), + record.line().unwrap(), + record.args() + ) + .expect("Failed to write to log file"); + } else { + writeln!( + *(*(self.output.lock().unwrap())), + "cloud-hypervisor: {:?}: {}:{} -- {}", + duration, + record.level(), + record.target(), + record.args() + ) + .expect("Failed to write to log file"); + } + } + fn flush(&self) {} +} + fn main() { let cmd_arguments = App::new("cloud-hypervisor") .version(crate_version!()) @@ -107,6 +153,19 @@ fn main() { .takes_value(true) .min_values(1), ) + .arg( + Arg::with_name("v") + .short("v") + .multiple(true) + .help("Sets the level of debugging output"), + ) + .arg( + Arg::with_name("log-file") + .long("log-file") + .help("Log file. Standard error is used if not specified") + .takes_value(true) + .min_values(1), + ) .get_matches(); // These .unwrap()s cannot fail as there is a default value defined @@ -127,6 +186,30 @@ fn main() { let pmem: Option> = cmd_arguments.values_of("pmem").map(|x| x.collect()); let devices: Option> = cmd_arguments.values_of("device").map(|x| x.collect()); + let log_level = match cmd_arguments.occurrences_of("v") { + 0 => LevelFilter::Error, + 1 => LevelFilter::Warn, + 2 => LevelFilter::Info, + 3 => LevelFilter::Debug, + _ => LevelFilter::Trace, + }; + + let log_file: Box = + if let Some(file) = cmd_arguments.value_of("log-file") { + Box::new( + std::fs::File::create(std::path::Path::new(file)).expect("Error creating log file"), + ) + } else { + Box::new(std::io::stderr()) + }; + + log::set_boxed_logger(Box::new(Logger { + output: Mutex::new(log_file), + start: std::time::Instant::now(), + })) + .map(|()| log::set_max_level(log_level)) + .expect("Expected to be able to setup logger"); + let vm_config = match config::VmConfig::parse(config::VmParams { cpus, memory,