forked from NationTech/harmony
		
	Merge pull request 'fix: remove indicatif in harmony_cli to simplify logging and fixing interactions' (#109) from rip-indicatif into master
Reviewed-on: https://git.nationtech.io/NationTech/harmony/pulls/109
This commit is contained in:
		
						commit
						7d027bcfc4
					
				
							
								
								
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -1834,6 +1834,7 @@ name = "harmony_cli" | |||||||
| version = "0.1.0" | version = "0.1.0" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "assert_cmd", |  "assert_cmd", | ||||||
|  |  "chrono", | ||||||
|  "clap", |  "clap", | ||||||
|  "console", |  "console", | ||||||
|  "env_logger", |  "env_logger", | ||||||
|  | |||||||
| @ -20,7 +20,7 @@ readme = "README.md" | |||||||
| license = "GNU AGPL v3" | license = "GNU AGPL v3" | ||||||
| 
 | 
 | ||||||
| [workspace.dependencies] | [workspace.dependencies] | ||||||
| log = "0.4" | log = { version = "0.4", features = ["kv"] } | ||||||
| env_logger = "0.11" | env_logger = "0.11" | ||||||
| derive-new = "0.7" | derive-new = "0.7" | ||||||
| async-trait = "0.1" | async-trait = "0.1" | ||||||
|  | |||||||
| @ -22,6 +22,7 @@ indicatif = "0.18.0" | |||||||
| lazy_static = "1.5.0" | lazy_static = "1.5.0" | ||||||
| log.workspace = true | log.workspace = true | ||||||
| indicatif-log-bridge = "0.2.3" | indicatif-log-bridge = "0.2.3" | ||||||
|  | chrono.workspace = true | ||||||
| 
 | 
 | ||||||
| [dev-dependencies] | [dev-dependencies] | ||||||
| harmony = { path = "../harmony", features = ["testing"] } | harmony = { path = "../harmony", features = ["testing"] } | ||||||
|  | |||||||
| @ -1,22 +1,17 @@ | |||||||
|  | use chrono::Local; | ||||||
|  | use console::style; | ||||||
| use harmony::{ | use harmony::{ | ||||||
|     instrumentation::{self, HarmonyEvent}, |     instrumentation::{self, HarmonyEvent}, | ||||||
|     modules::application::ApplicationFeatureStatus, |     modules::application::ApplicationFeatureStatus, | ||||||
|     topology::TopologyStatus, |     topology::TopologyStatus, | ||||||
| }; | }; | ||||||
| use indicatif::MultiProgress; | use log::{error, info, log_enabled}; | ||||||
| use indicatif_log_bridge::LogWrapper; | use std::io::Write; | ||||||
| use log::error; | use std::sync::{Arc, Mutex}; | ||||||
| use std::{ |  | ||||||
|     sync::{Arc, Mutex}, |  | ||||||
|     thread, |  | ||||||
|     time::Duration, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| use crate::progress::{IndicatifProgressTracker, ProgressTracker}; |  | ||||||
| 
 | 
 | ||||||
| pub fn init() -> tokio::task::JoinHandle<()> { | pub fn init() -> tokio::task::JoinHandle<()> { | ||||||
|     let base_progress = configure_logger(); |     configure_logger(); | ||||||
|     let handle = tokio::spawn(handle_events(base_progress)); |     let handle = tokio::spawn(handle_events()); | ||||||
| 
 | 
 | ||||||
|     loop { |     loop { | ||||||
|         if instrumentation::instrument(HarmonyEvent::HarmonyStarted).is_ok() { |         if instrumentation::instrument(HarmonyEvent::HarmonyStarted).is_ok() { | ||||||
| @ -27,28 +22,76 @@ pub fn init() -> tokio::task::JoinHandle<()> { | |||||||
|     handle |     handle | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn configure_logger() -> MultiProgress { | fn configure_logger() { | ||||||
|     let logger = |     env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")) | ||||||
|         env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).build(); |         .format(|buf, record| { | ||||||
|     let level = logger.filter(); |             let debug_mode = log_enabled!(log::Level::Debug); | ||||||
|     let progress = MultiProgress::new(); |             let timestamp = Local::now().format("%Y-%m-%d %H:%M:%S"); | ||||||
| 
 | 
 | ||||||
|     LogWrapper::new(progress.clone(), logger) |             let level = match record.level() { | ||||||
|         .try_init() |                 log::Level::Error => style("ERROR").red(), | ||||||
|         .unwrap(); |                 log::Level::Warn => style("WARN").yellow(), | ||||||
|     log::set_max_level(level); |                 log::Level::Info => style("INFO").green(), | ||||||
| 
 |                 log::Level::Debug => style("DEBUG").blue(), | ||||||
|     progress |                 log::Level::Trace => style("TRACE").magenta(), | ||||||
|  |             }; | ||||||
|  |             if let Some(status) = record.key_values().get(log::kv::Key::from("status")) { | ||||||
|  |                 let status = status.to_borrowed_str().unwrap(); | ||||||
|  |                 let emoji = match status { | ||||||
|  |                     "finished" => style(crate::theme::EMOJI_SUCCESS.to_string()).green(), | ||||||
|  |                     "skipped" => style(crate::theme::EMOJI_SKIP.to_string()).yellow(), | ||||||
|  |                     "failed" => style(crate::theme::EMOJI_ERROR.to_string()).red(), | ||||||
|  |                     _ => style("".into()), | ||||||
|  |                 }; | ||||||
|  |                 if debug_mode { | ||||||
|  |                     writeln!( | ||||||
|  |                         buf, | ||||||
|  |                         "[{} {:<5} {}] {} {}", | ||||||
|  |                         timestamp, | ||||||
|  |                         level, | ||||||
|  |                         record.target(), | ||||||
|  |                         emoji, | ||||||
|  |                         record.args() | ||||||
|  |                     ) | ||||||
|  |                 } else { | ||||||
|  |                     writeln!(buf, "[{:<5}] {} {}", level, emoji, record.args()) | ||||||
|  |                 } | ||||||
|  |             } else if let Some(emoji) = record.key_values().get(log::kv::Key::from("emoji")) { | ||||||
|  |                 if debug_mode { | ||||||
|  |                     writeln!( | ||||||
|  |                         buf, | ||||||
|  |                         "[{} {:<5} {}] {} {}", | ||||||
|  |                         timestamp, | ||||||
|  |                         level, | ||||||
|  |                         record.target(), | ||||||
|  |                         emoji, | ||||||
|  |                         record.args() | ||||||
|  |                     ) | ||||||
|  |                 } else { | ||||||
|  |                     writeln!(buf, "[{:<5}] {} {}", level, emoji, record.args()) | ||||||
|  |                 } | ||||||
|  |             } else if debug_mode { | ||||||
|  |                 writeln!( | ||||||
|  |                     buf, | ||||||
|  |                     "[{} {:<5} {}] {}", | ||||||
|  |                     timestamp, | ||||||
|  |                     level, | ||||||
|  |                     record.target(), | ||||||
|  |                     record.args() | ||||||
|  |                 ) | ||||||
|  |             } else { | ||||||
|  |                 writeln!(buf, "[{:<5}] {}", level, record.args()) | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .init(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async fn handle_events(base_progress: MultiProgress) { | async fn handle_events() { | ||||||
|     let progress_tracker = Arc::new(IndicatifProgressTracker::new(base_progress.clone())); |  | ||||||
|     let preparing_topology = Arc::new(Mutex::new(false)); |     let preparing_topology = Arc::new(Mutex::new(false)); | ||||||
|     let current_score: Arc<Mutex<Option<String>>> = Arc::new(Mutex::new(None)); |     let current_score: Arc<Mutex<Option<String>>> = Arc::new(Mutex::new(None)); | ||||||
| 
 | 
 | ||||||
|     instrumentation::subscribe("Harmony CLI Logger", { |     instrumentation::subscribe("Harmony CLI Logger", { | ||||||
|         move |event| { |         move |event| { | ||||||
|             let progress_tracker = Arc::clone(&progress_tracker); |  | ||||||
|             let preparing_topology = Arc::clone(&preparing_topology); |             let preparing_topology = Arc::clone(&preparing_topology); | ||||||
|             let current_score = Arc::clone(¤t_score); |             let current_score = Arc::clone(¤t_score); | ||||||
| 
 | 
 | ||||||
| @ -59,90 +102,57 @@ async fn handle_events(base_progress: MultiProgress) { | |||||||
|                 match event { |                 match event { | ||||||
|                     HarmonyEvent::HarmonyStarted => {} |                     HarmonyEvent::HarmonyStarted => {} | ||||||
|                     HarmonyEvent::HarmonyFinished => { |                     HarmonyEvent::HarmonyFinished => { | ||||||
|                         progress_tracker.add_section( |                         let emoji = crate::theme::EMOJI_HARMONY.to_string(); | ||||||
|                             "harmony-summary", |                         info!(emoji = emoji.as_str(); "Harmony completed"); | ||||||
|                             &format!("\n{} Harmony completed\n\n", crate::theme::EMOJI_HARMONY), |  | ||||||
|                         ); |  | ||||||
|                         progress_tracker.add_section("harmony-finished", "\n\n"); |  | ||||||
|                         thread::sleep(Duration::from_millis(200)); |  | ||||||
|                         return false; |                         return false; | ||||||
|                     } |                     } | ||||||
|                     HarmonyEvent::TopologyStateChanged { |                     HarmonyEvent::TopologyStateChanged { | ||||||
|                         topology, |                         topology, | ||||||
|                         status, |                         status, | ||||||
|                         message, |                         message, | ||||||
|                     } => { |                     } => match status { | ||||||
|                         let section_key = topology_key(&topology); |                         TopologyStatus::Queued => {} | ||||||
| 
 |                         TopologyStatus::Preparing => { | ||||||
|                         match status { |                             let emoji = format!("{}", style(crate::theme::EMOJI_TOPOLOGY.to_string()).yellow()); | ||||||
|                             TopologyStatus::Queued => {} |                             info!(emoji = emoji.as_str(); "Preparing environment: {topology}..."); | ||||||
|                             TopologyStatus::Preparing => { |                             (*preparing_topology) = true; | ||||||
|                                 progress_tracker.add_section( |                         } | ||||||
|                                     §ion_key, |                         TopologyStatus::Success => { | ||||||
|                                     &format!( |                             (*preparing_topology) = false; | ||||||
|                                         "\n{} Preparing environment: {topology}...", |                             if let Some(message) = message { | ||||||
|                                         crate::theme::EMOJI_TOPOLOGY |                                 info!(status = "finished"; "{message}"); | ||||||
|                                     ), |  | ||||||
|                                 ); |  | ||||||
|                                 (*preparing_topology) = true; |  | ||||||
|                             } |  | ||||||
|                             TopologyStatus::Success => { |  | ||||||
|                                 (*preparing_topology) = false; |  | ||||||
|                                 progress_tracker.add_task(§ion_key, "topology-success", ""); |  | ||||||
|                                 progress_tracker |  | ||||||
|                                     .finish_task("topology-success", &message.unwrap_or("".into())); |  | ||||||
|                             } |  | ||||||
|                             TopologyStatus::Noop => { |  | ||||||
|                                 (*preparing_topology) = false; |  | ||||||
|                                 progress_tracker.add_task(§ion_key, "topology-skip", ""); |  | ||||||
|                                 progress_tracker |  | ||||||
|                                     .skip_task("topology-skip", &message.unwrap_or("".into())); |  | ||||||
|                             } |  | ||||||
|                             TopologyStatus::Error => { |  | ||||||
|                                 progress_tracker.add_task(§ion_key, "topology-error", ""); |  | ||||||
|                                 (*preparing_topology) = false; |  | ||||||
|                                 progress_tracker |  | ||||||
|                                     .fail_task("topology-error", &message.unwrap_or("".into())); |  | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|                     } |                         TopologyStatus::Noop => { | ||||||
|  |                             (*preparing_topology) = false; | ||||||
|  |                             if let Some(message) = message { | ||||||
|  |                                 info!(status = "skipped"; "{message}"); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                         TopologyStatus::Error => { | ||||||
|  |                             (*preparing_topology) = false; | ||||||
|  |                             if let Some(message) = message { | ||||||
|  |                                 error!(status = "failed"; "{message}"); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     }, | ||||||
|                     HarmonyEvent::InterpretExecutionStarted { |                     HarmonyEvent::InterpretExecutionStarted { | ||||||
|                         execution_id: task_key, |                         execution_id: _, | ||||||
|                         topology, |                         topology: _, | ||||||
|                         interpret: _, |                         interpret: _, | ||||||
|                         score, |                         score, | ||||||
|                         message, |                         message, | ||||||
|                     } => { |                     } => { | ||||||
|                         let is_key_topology = (*preparing_topology) |                         if *preparing_topology || current_score.is_some() { | ||||||
|                             && progress_tracker.contains_section(&topology_key(&topology)); |                             info!("{message}"); | ||||||
|                         let is_key_current_score = current_score.is_some() |  | ||||||
|                             && progress_tracker |  | ||||||
|                                 .contains_section(&score_key(¤t_score.clone().unwrap())); |  | ||||||
|                         let is_key_score = progress_tracker.contains_section(&score_key(&score)); |  | ||||||
| 
 |  | ||||||
|                         let section_key = if is_key_topology { |  | ||||||
|                             topology_key(&topology) |  | ||||||
|                         } else if is_key_current_score { |  | ||||||
|                             score_key(¤t_score.clone().unwrap()) |  | ||||||
|                         } else if is_key_score { |  | ||||||
|                             score_key(&score) |  | ||||||
|                         } else { |                         } else { | ||||||
|                             (*current_score) = Some(score.clone()); |                             (*current_score) = Some(score.clone()); | ||||||
|                             let key = score_key(&score); |                             let emoji = format!("{}", style(crate::theme::EMOJI_SCORE).blue()); | ||||||
|                             progress_tracker.add_section( |                             info!(emoji = emoji.as_str(); "Interpreting score: {score}..."); | ||||||
|                                 &key, |                         } | ||||||
|                                 &format!( |  | ||||||
|                                     "{} Interpreting score: {score}...", |  | ||||||
|                                     crate::theme::EMOJI_SCORE |  | ||||||
|                                 ), |  | ||||||
|                             ); |  | ||||||
|                             key |  | ||||||
|                         }; |  | ||||||
| 
 |  | ||||||
|                         progress_tracker.add_task(§ion_key, &task_key, &message); |  | ||||||
|                     } |                     } | ||||||
|                     HarmonyEvent::InterpretExecutionFinished { |                     HarmonyEvent::InterpretExecutionFinished { | ||||||
|                         execution_id: task_key, |                         execution_id: _, | ||||||
|                         topology: _, |                         topology: _, | ||||||
|                         interpret: _, |                         interpret: _, | ||||||
|                         score, |                         score, | ||||||
| @ -155,16 +165,17 @@ async fn handle_events(base_progress: MultiProgress) { | |||||||
|                         match outcome { |                         match outcome { | ||||||
|                             Ok(outcome) => match outcome.status { |                             Ok(outcome) => match outcome.status { | ||||||
|                                 harmony::interpret::InterpretStatus::SUCCESS => { |                                 harmony::interpret::InterpretStatus::SUCCESS => { | ||||||
|                                     progress_tracker.finish_task(&task_key, &outcome.message); |                                     info!(status = "finished"; "{}", outcome.message); | ||||||
|                                 } |                                 } | ||||||
|                                 harmony::interpret::InterpretStatus::NOOP => { |                                 harmony::interpret::InterpretStatus::NOOP => { | ||||||
|                                     progress_tracker.skip_task(&task_key, &outcome.message); |                                     info!(status = "skipped"; "{}", outcome.message); | ||||||
|  |                                 } | ||||||
|  |                                 _ => { | ||||||
|  |                                     error!(status = "failed"; "{}", outcome.message); | ||||||
|                                 } |                                 } | ||||||
|                                 _ => progress_tracker.fail_task(&task_key, &outcome.message), |  | ||||||
|                             }, |                             }, | ||||||
|                             Err(err) => { |                             Err(err) => { | ||||||
|                                 error!("Interpret error: {err}"); |                                 error!(status = "failed"; "{}", err); | ||||||
|                                 progress_tracker.fail_task(&task_key, &err.to_string()); |  | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
| @ -173,30 +184,17 @@ async fn handle_events(base_progress: MultiProgress) { | |||||||
|                         application, |                         application, | ||||||
|                         feature, |                         feature, | ||||||
|                         status, |                         status, | ||||||
|                     } => { |                     } => match status { | ||||||
|                         if let Some(score) = &(*current_score) { |                         ApplicationFeatureStatus::Installing => { | ||||||
|                             let section_key = score_key(score); |                             info!("Installing feature '{}' for '{}'...", feature, application); | ||||||
|                             let task_key = app_feature_key(&application, &feature); |  | ||||||
| 
 |  | ||||||
|                             match status { |  | ||||||
|                                 ApplicationFeatureStatus::Installing => { |  | ||||||
|                                     let message = format!("Feature '{}' installing...", feature); |  | ||||||
|                                     progress_tracker.add_task(§ion_key, &task_key, &message); |  | ||||||
|                                 } |  | ||||||
|                                 ApplicationFeatureStatus::Installed => { |  | ||||||
|                                     let message = format!("Feature '{}' installed", feature); |  | ||||||
|                                     progress_tracker.finish_task(&task_key, &message); |  | ||||||
|                                 } |  | ||||||
|                                 ApplicationFeatureStatus::Failed { details } => { |  | ||||||
|                                     let message = format!( |  | ||||||
|                                         "Feature '{}' installation failed: {}", |  | ||||||
|                                         feature, details |  | ||||||
|                                     ); |  | ||||||
|                                     progress_tracker.fail_task(&task_key, &message); |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                         } |                         } | ||||||
|                     } |                         ApplicationFeatureStatus::Installed => { | ||||||
|  |                             info!(status = "finished"; "Feature '{}' installed", feature); | ||||||
|  |                         } | ||||||
|  |                         ApplicationFeatureStatus::Failed { details } => { | ||||||
|  |                             error!(status = "failed"; "Feature '{}' installation failed: {}", feature, details); | ||||||
|  |                         } | ||||||
|  |                     }, | ||||||
|                 } |                 } | ||||||
|                 true |                 true | ||||||
|             } |             } | ||||||
| @ -204,15 +202,3 @@ async fn handle_events(base_progress: MultiProgress) { | |||||||
|     }) |     }) | ||||||
|     .await; |     .await; | ||||||
| } | } | ||||||
| 
 |  | ||||||
| fn topology_key(topology: &str) -> String { |  | ||||||
|     format!("topology-{topology}") |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn score_key(score: &str) -> String { |  | ||||||
|     format!("score-{score}") |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn app_feature_key(application: &str, feature: &str) -> String { |  | ||||||
|     format!("app-{application}-{feature}") |  | ||||||
| } |  | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user