diff --git a/rust/src/logger.rs b/rust/src/logger.rs index 119e5bc5b891c..d48a25efc46ec 100644 --- a/rust/src/logger.rs +++ b/rust/src/logger.rs @@ -18,7 +18,7 @@ use crate::config::BooleanKey; use crate::metadata::now_unix_timestamp; use env_logger::fmt::Color; -use env_logger::Target::Stdout; +use env_logger::Target::{Stderr, Stdout}; use env_logger::DEFAULT_FILTER_ENV; use log::Level; use log::LevelFilter::{Debug, Info, Trace}; @@ -27,7 +27,6 @@ use std::cell::RefCell; use std::env; use std::fmt::Display; use std::io::Write; -use std::ops::Deref; use Color::{Blue, Cyan, Green, Red, Yellow}; pub const DRIVER_PATH: &str = "Driver path: "; @@ -39,6 +38,7 @@ enum OutputType { Logger, Json, Shell, + Mixed, } #[derive(Default)] @@ -47,6 +47,7 @@ pub struct Logger { trace: bool, output: OutputType, json: RefCell, + minimal_json: RefCell, } #[derive(Default, Serialize, Deserialize)] @@ -70,6 +71,12 @@ pub struct JsonOutput { pub result: Result, } +#[derive(Default, Serialize, Deserialize)] +pub struct MinimalJson { + pub driver_path: String, + pub browser_path: String, +} + impl Logger { pub fn new() -> Self { let debug = BooleanKey("debug", false).get_value(); @@ -83,11 +90,13 @@ impl Logger { output_type = OutputType::Json; } else if output.eq_ignore_ascii_case("shell") { output_type = OutputType::Shell; + } else if output.eq_ignore_ascii_case("mixed") { + output_type = OutputType::Mixed; } else { output_type = OutputType::Logger; } match output_type { - OutputType::Logger => { + OutputType::Logger | OutputType::Mixed => { if env::var(DEFAULT_FILTER_ENV).unwrap_or_default().is_empty() { let mut filter = match debug { true => Debug, @@ -96,9 +105,14 @@ impl Logger { if trace { filter = Trace } + let target = if output_type == OutputType::Logger { + Stdout + } else { + Stderr + }; env_logger::Builder::new() .filter_module(env!("CARGO_CRATE_NAME"), filter) - .target(Stdout) + .target(target) .format(|buf, record| { let mut level_style = buf.style(); match record.level() { @@ -141,6 +155,7 @@ impl Logger { browser_path: "".to_string(), }, }), + minimal_json: RefCell::new(Default::default()), } } @@ -178,12 +193,11 @@ impl Logger { } if level == Level::Info || level <= Level::Error { if message.starts_with(DRIVER_PATH) { - let driver_path = message.replace(DRIVER_PATH, ""); - self.json.borrow_mut().result.driver_path = driver_path.to_owned(); - self.json.borrow_mut().result.message = driver_path; + self.json.borrow_mut().result.driver_path = + self.clean_driver_path(&message); } else if message.starts_with(BROWSER_PATH) { - let browser_path = message.replace(BROWSER_PATH, ""); - self.json.borrow_mut().result.browser_path = browser_path; + self.json.borrow_mut().result.browser_path = + self.clean_browser_path(&message); } else { self.json.borrow_mut().result.message = message; } @@ -197,11 +211,28 @@ impl Logger { } } _ => { + if self.output == OutputType::Mixed && level == Level::Info { + if message.starts_with(DRIVER_PATH) { + self.minimal_json.borrow_mut().driver_path = + self.clean_driver_path(&message); + } else if message.starts_with(BROWSER_PATH) { + self.minimal_json.borrow_mut().browser_path = + self.clean_browser_path(&message); + } + } log::log!(level, "{}", message); } } } + fn clean_driver_path(&self, message: &str) -> String { + message.replace(DRIVER_PATH, "") + } + + fn clean_browser_path(&self, message: &str) -> String { + message.replace(BROWSER_PATH, "") + } + fn create_json_log(&self, message: String, level: Level) -> Logs { Logs { level: level.to_string().to_uppercase(), @@ -210,17 +241,22 @@ impl Logger { } } + fn get_json_blog(&self, json_output: &T) -> String + where + T: Serialize, + { + serde_json::to_string_pretty(json_output).unwrap() + } + pub fn set_code(&self, code: i32) { self.json.borrow_mut().result.code = code; } pub fn flush(&self) { - let json_output = &self.json.borrow(); - let json = json_output.deref(); - if !json.logs.is_empty() { - print!("{}", serde_json::to_string_pretty(json).unwrap()); - } else if self.output == OutputType::Json { - panic!("JSON output has been specified, but no entries have been collected") + if self.output == OutputType::Json { + print!("{}", self.get_json_blog(&self.json)); + } else if self.output == OutputType::Mixed { + print!("{}", self.get_json_blog(&self.minimal_json)); } } } diff --git a/rust/src/main.rs b/rust/src/main.rs index ac044b4e8646a..b567cdc9adc97 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -77,7 +77,8 @@ struct Cli { #[clap(long, value_parser)] browser_mirror_url: Option, - /// Output type: LOGGER (using INFO, WARN, etc.), JSON (custom JSON notation), or SHELL (Unix-like) + /// Output type: LOGGER (using INFO, WARN, etc.), JSON (custom JSON notation), SHELL (Unix-like), + /// or MIXED (INFO, WARN, DEBUG, etc. to stderr and minimal JSON to stdout) #[clap(long, value_parser, default_value = "LOGGER")] output: String, diff --git a/rust/tests/grid_tests.rs b/rust/tests/grid_tests.rs index 632ef4e52a2f4..99bbc590d53e3 100644 --- a/rust/tests/grid_tests.rs +++ b/rust/tests/grid_tests.rs @@ -43,7 +43,7 @@ fn grid_latest_test() { let output_code = json.result.code; assert_eq!(output_code, 0); - let jar = Path::new(&json.result.message); + let jar = Path::new(&json.result.driver_path); assert!(jar.exists()); let jar_name = jar.file_name().unwrap().to_str().unwrap(); @@ -66,7 +66,7 @@ fn grid_version_test(#[case] grid_version: &str) { println!("{}", output); let json: JsonOutput = serde_json::from_str(output).unwrap(); - let jar = Path::new(&json.result.message); + let jar = Path::new(&json.result.driver_path); let jar_name = jar.file_name().unwrap().to_str().unwrap(); assert!(jar_name.contains(grid_version)); } diff --git a/rust/tests/output_tests.rs b/rust/tests/output_tests.rs index b8e7b90a428a9..d01e74d1e71fe 100644 --- a/rust/tests/output_tests.rs +++ b/rust/tests/output_tests.rs @@ -16,7 +16,7 @@ // under the License. use assert_cmd::Command; -use selenium_manager::logger::{JsonOutput, DRIVER_PATH}; +use selenium_manager::logger::{JsonOutput, MinimalJson, DRIVER_PATH}; use std::path::Path; use std::str; @@ -38,7 +38,7 @@ fn json_output_test() { let output_code = json.result.code; assert_eq!(output_code, 0); - let driver = Path::new(&json.result.message); + let driver = Path::new(&json.result.driver_path); assert!(driver.exists()); } @@ -55,3 +55,25 @@ fn shell_output_test() { println!("{}", output); assert!(output.contains(DRIVER_PATH)); } + +#[test] +fn mixed_output_test() { + let mut cmd = Command::new(env!("CARGO_BIN_EXE_selenium-manager")); + cmd.args(["--browser", "chrome", "--output", "mixed"]) + .assert() + .success() + .code(0); + + let stdout = &cmd.unwrap().stdout; + let output = str::from_utf8(stdout).unwrap(); + println!("stdout: {}", output); + + let json: MinimalJson = serde_json::from_str(output).unwrap(); + let driver = Path::new(&json.driver_path); + assert!(driver.exists()); + + let stderr = &cmd.unwrap().stderr; + let err_output = str::from_utf8(stderr).unwrap(); + println!("stderr: {}", err_output); + assert!(!err_output.is_empty()); +}