diff --git a/rash_core/src/bin/rash.rs b/rash_core/src/bin/rash.rs index 51596db0..473d23cb 100644 --- a/rash_core/src/bin/rash.rs +++ b/rash_core/src/bin/rash.rs @@ -54,6 +54,9 @@ struct Args { /// It can be accessed from builtin `{{ env }}`. E.g.: `{{ env.USER }}` #[arg(short, long, action = ArgAction::Append, value_parser = parse_key_val::, num_args = 1)] environment: Vec<(String, String)>, + /// Output format. + #[arg(value_enum, short, long, default_value_t=logger::Output::Ansible)] + output: logger::Output, /// Verbose mode (-vv for more) #[arg(short, long, action = ArgAction::Count)] verbose: u8, @@ -107,7 +110,8 @@ fn main() { args.verbose }; - logger::setup_logging(verbose, args.diff).expect("failed to initialize logging."); + logger::setup_logging(verbose, &args.diff, &args.output) + .expect("failed to initialize logging."); trace!("start logger"); trace!("{:?}", &args); let script_path = Path::new(&args.script_file); diff --git a/rash_core/src/logger.rs b/rash_core/src/logger.rs index e51af93a..f6cc34a9 100644 --- a/rash_core/src/logger.rs +++ b/rash_core/src/logger.rs @@ -3,6 +3,7 @@ use crate::error::{Error, ErrorKind, Result}; use std::fmt; use std::io; +use clap::ValueEnum; use console::{style, Style}; use fern::colors::Color; use fern::FormatCallback; @@ -10,6 +11,14 @@ use similar::{Change, ChangeTag, TextDiff}; struct Line(Option); +#[derive(Clone, Debug, ValueEnum)] +pub enum Output { + /// ansible style output with tasks and changed outputs + Ansible, + /// print module outputs without any extra details, omitting task names and separators. + Raw, +} + impl fmt::Display for Line { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.0 { @@ -102,7 +111,7 @@ where } } -fn log_format(out: FormatCallback, message: &fmt::Arguments, record: &log::Record) { +fn ansible_log_format(out: FormatCallback, message: &fmt::Arguments, record: &log::Record) { let log_header = match (record.level(), record.target()) { (log::Level::Error, "task") => "failed: ".to_owned(), (log::Level::Error, _) => "[ERROR] ".to_owned(), @@ -154,8 +163,27 @@ fn log_format(out: FormatCallback, message: &fmt::Arguments, record: &log::Recor )) } +fn raw_log_format(out: FormatCallback, message: &fmt::Arguments, record: &log::Record) { + out.finish(format_args!( + "{color_line}{message}\x1B[0m", + color_line = format_args!( + "\x1B[{}m", + match (record.level(), record.target()) { + (log::Level::Error, _) => Color::Red, + (log::Level::Warn, _) => Color::Magenta, + (log::Level::Info, _) => Color::White, + (log::Level::Debug, _) => Color::BrightBlue, + (log::Level::Trace, "error") => Color::Red, + (log::Level::Trace, _) => Color::BrightBlack, + } + .to_fg_str() + ), + message = &message, + )) +} + /// Setup logging according to the specified verbosity. -pub fn setup_logging(verbosity: u8, diff: bool) -> Result<()> { +pub fn setup_logging(verbosity: u8, diff: &bool, output: &Output) -> Result<()> { let mut base_config = fern::Dispatch::new(); base_config = match verbosity { @@ -169,6 +197,17 @@ pub fn setup_logging(verbosity: u8, diff: bool) -> Result<()> { true => base_config.level_for("diff", log::LevelFilter::Info), }; + // remove task module for raw output + base_config = match output { + Output::Raw => base_config.level_for("task", log::LevelFilter::Error), + _ => base_config, + }; + + let log_format = match output { + Output::Ansible => ansible_log_format, + Output::Raw => raw_log_format, + }; + base_config .format(log_format) .chain(