3131import os
3232import sys
3333from pathlib import Path
34- from typing import Optional , Tuple
34+ from typing import Optional , Sequence , Tuple
3535
3636from pydantic import BaseModel
3737
@@ -187,6 +187,13 @@ def build_config(
187187 return config
188188
189189
190+ def log_cli_text_block (logger : logging .Logger , lines : Sequence [str ]) -> None :
191+ """Emit user-facing multi-line text through logging (respects handlers / --no-console-log)."""
192+ text = "\n " .join (lines ).rstrip ("\n " )
193+ if text :
194+ logger .info ("%s" , text )
195+
196+
190197def parse_describe (
191198 parsed_args : argparse .Namespace ,
192199 plugin_reg : PluginRegistry ,
@@ -202,35 +209,44 @@ def parse_describe(
202209 logger (logging.Logger): logger instance
203210 """
204211 if not parsed_args .name :
212+ out : list [str ] = []
205213 if parsed_args .type == "config" :
206- print ("Available built-in configs:" ) # noqa: T201
214+ out . append ("Available built-in configs:" )
207215 for name in config_reg .configs :
208- print (f" { name } " ) # noqa: T201
216+ out . append (f" { name } " )
209217 elif parsed_args .type == "plugin" :
210- print ("Available plugins:" ) # noqa: T201
218+ out . append ("Available plugins:" )
211219 for name in plugin_reg .plugins :
212- print (f" { name } " ) # noqa: T201
213- print (f"\n Usage: describe { parsed_args .type } <name>" ) # noqa: T201
220+ out .append (f" { name } " )
221+ out .append ("" )
222+ out .append (f"Usage: describe { parsed_args .type } <name>" )
223+ log_cli_text_block (logger , out )
214224 sys .exit (0 )
215225
216226 if parsed_args .type == "config" :
217227 if parsed_args .name not in config_reg .configs :
218228 logger .error ("No config found for name: %s" , parsed_args .name )
219229 sys .exit (1 )
220230 config_model = config_reg .configs [parsed_args .name ]
221- print (f"Config Name: { parsed_args .name } " ) # noqa: T201
222- print (f"Description: { getattr (config_model , 'desc' , '' )} " ) # noqa: T201
223- print ("Plugins:" ) # noqa: T201
231+ out = [
232+ f"Config Name: { parsed_args .name } " ,
233+ f"Description: { getattr (config_model , 'desc' , '' )} " ,
234+ "Plugins:" ,
235+ ]
224236 for plugin in getattr (config_model , "plugins" , []):
225- print (f"\t { plugin } " ) # noqa: T201
237+ out .append (f"\t { plugin } " )
238+ log_cli_text_block (logger , out )
226239
227240 elif parsed_args .type == "plugin" :
228241 if parsed_args .name not in plugin_reg .plugins :
229242 logger .error ("No plugin found for name: %s" , parsed_args .name )
230243 sys .exit (1 )
231244 plugin_class = plugin_reg .plugins [parsed_args .name ]
232- print (f"Plugin Name: { parsed_args .name } " ) # noqa: T201
233- print (f"Description: { getattr (plugin_class , '__doc__' , '' )} " ) # noqa: T201
245+ out = [
246+ f"Plugin Name: { parsed_args .name } " ,
247+ f"Description: { getattr (plugin_class , '__doc__' , '' )} " ,
248+ ]
249+ log_cli_text_block (logger , out )
234250
235251 sys .exit (0 )
236252
@@ -240,6 +256,7 @@ def parse_gen_plugin_config(
240256 plugin_reg : PluginRegistry ,
241257 config_reg : ConfigRegistry ,
242258 logger : logging .Logger ,
259+ artifact_dir : Optional [str ] = None ,
243260):
244261 """parse 'gen_plugin_config' cmd line argument
245262
@@ -248,6 +265,7 @@ def parse_gen_plugin_config(
248265 plugin_reg (PluginRegistry): plugin registry instance
249266 config_reg (ConfigRegistry): config registry instance
250267 logger (logging.Logger): logger instance
268+ artifact_dir (Optional[str]): if set, write the config under this directory (CLI run log dir)
251269 """
252270 try :
253271 config = build_config (
@@ -256,7 +274,8 @@ def parse_gen_plugin_config(
256274
257275 config .name = parsed_args .config_name .split ("." )[0 ]
258276 config .desc = "Auto generated config"
259- output_path = os .path .join (parsed_args .output_path , parsed_args .config_name )
277+ out_dir = artifact_dir if artifact_dir else parsed_args .output_path
278+ output_path = os .path .join (out_dir , parsed_args .config_name )
260279 with open (output_path , "w" , encoding = "utf-8" ) as out_file :
261280 out_file .write (config .model_dump_json (indent = 2 ))
262281
@@ -576,13 +595,19 @@ def dump_to_csv(all_rows: list, filename: str, fieldnames: list[str], logger: lo
576595 logger .info ("Data written to csv file: %s" , filename )
577596
578597
579- def generate_summary (search_path : str , output_path : Optional [str ], logger : logging .Logger ):
598+ def generate_summary (
599+ search_path : str ,
600+ output_path : Optional [str ],
601+ logger : logging .Logger ,
602+ artifact_dir : Optional [str ] = None ,
603+ ):
580604 """Concatenate csv files into 1 summary csv file
581605
582606 Args:
583607 search_path (str): Path for previous runs
584- output_path (Optional[str]): Path for new summary csv file
608+ output_path (Optional[str]): Directory for new summary. csv (ignored when artifact_dir is set)
585609 logger (logging.Logger): instance of logger
610+ artifact_dir (Optional[str]): if set, write summary.csv under this directory (CLI run log dir)
586611 """
587612
588613 fieldnames = ["nodename" , "plugin" , "status" , "timestamp" , "message" ]
@@ -606,8 +631,6 @@ def generate_summary(search_path: str, output_path: Optional[str], logger: loggi
606631 logger .error ("No data rows found in matched CSV files." )
607632 return
608633
609- if not output_path :
610- output_path = os .getcwd ()
611-
612- output_path = os .path .join (output_path , "summary.csv" )
613- dump_to_csv (all_rows , output_path , fieldnames , logger )
634+ base_dir = artifact_dir if artifact_dir else (output_path or os .getcwd ())
635+ out_file = os .path .join (base_dir , "summary.csv" )
636+ dump_to_csv (all_rows , out_file , fieldnames , logger )
0 commit comments