main: Add logging support controlled by command line

This makes the log macros (error!, warn!, info!, etc) in the code work.
It currently defaults to showing only error! messages, but by passing an
increasing number of "-v"s on the command line the verbosity can be
increased.

By default log output goes onto stderr but it can also be sent to a
file.

Fixes: #121

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2019-08-07 12:19:21 +01:00
parent 91ce39e2a6
commit fca911e5f3
3 changed files with 86 additions and 0 deletions

1
Cargo.lock generated
View File

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

View File

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

View File

@ -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<Box<std::io::Write + Send>>,
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<Vec<&str>> = cmd_arguments.values_of("pmem").map(|x| x.collect());
let devices: Option<Vec<&str>> = 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<std::io::Write + Send> =
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,