@@ -99,7 +99,12 @@ def configure(format=LOG_DEFAULT_FORMAT, level=lg.DEBUG, stream=sys.stdout):
9999
100100
101101# noinspection PyShadowingBuiltins
102- def run_main (main_fn : Callable [..., T ], format = LOG_DEFAULT_FORMAT , level = lg .DEBUG ) -> T :
102+ def run_main (main_fn : Callable [..., T ],
103+ format = LOG_DEFAULT_FORMAT ,
104+ level = lg .DEBUG ,
105+ logfile : Optional [str ] = None ,
106+ append : bool = True ,
107+ stream = sys .stdout ) -> T :
103108 """
104109 Configures logging with the given parameters, ensuring that any exceptions that occur during
105110 the execution of the given function are logged.
@@ -108,9 +113,15 @@ def run_main(main_fn: Callable[..., T], format=LOG_DEFAULT_FORMAT, level=lg.DEBU
108113 :param main_fn: the function to be executed
109114 :param format: the log message format
110115 :param level: the minimum log level
116+ :param logfile: the path of a file to write logs to (in addition to console outputs);
117+ directories will be created as needed
118+ :param append: whether to append to the log file if it already exists
119+ :param stream: the output stream for console log messages
111120 :return: the result of `main_fn`
112121 """
113- configure (format = format , level = level )
122+ configure (format = format , level = level , stream = stream )
123+ if logfile is not None :
124+ add_file_logger (logfile , append = append )
114125 log .info ("Starting" )
115126 try :
116127 result = main_fn ()
@@ -121,7 +132,12 @@ def run_main(main_fn: Callable[..., T], format=LOG_DEFAULT_FORMAT, level=lg.DEBU
121132
122133
123134# noinspection PyShadowingBuiltins
124- def run_cli (main_fn : Callable [..., T ], format : str = LOG_DEFAULT_FORMAT , level : int = lg .DEBUG ) -> Optional [T ]:
135+ def run_cli (main_fn : Callable [..., T ],
136+ format : str = LOG_DEFAULT_FORMAT ,
137+ level : int = lg .DEBUG ,
138+ logfile : Optional [str ] = None ,
139+ append : bool = True ,
140+ stream = sys .stdout ) -> Optional [T ]:
125141 """
126142 Configures logging with the given parameters and runs the given main function as a
127143 CLI using `jsonargparse` (which is configured to also parse attribute docstrings, such
@@ -133,12 +149,14 @@ def run_cli(main_fn: Callable[..., T], format: str = LOG_DEFAULT_FORMAT, level:
133149 :param main_fn: the function to be executed
134150 :param format: the log message format
135151 :param level: the minimum log level
152+ :param logfile: path of a file to write logs to (in addition to console outputs);
153+ directories will be created as needed
136154 :return: the result of `main_fn`
137155 """
138156 from jsonargparse import set_docstring_parse_options , CLI
139157
140158 set_docstring_parse_options (attribute_docstrings = True )
141- return run_main (lambda : CLI (main_fn ), format = format , level = level )
159+ return run_main (lambda : CLI (main_fn ), format = format , level = level , logfile = logfile , append = append , stream = stream )
142160
143161
144162def datetime_tag () -> str :
@@ -161,14 +179,17 @@ def add_file_logger(path, append=True, register_atexit=True, encoding=LOG_FILE_D
161179 """
162180 Adds a file logger which logs to the given path.
163181
164- :param path: the path to the log file
182+ :param path: the path to the log file; directories will be created as needed
165183 :param append: whether to append in case the file already exists
166184 :param register_atexit: whether to register an atexit handler which reports the path to the log file upon program termination
167185 :param encoding: the encoding to use for the log file
168186 :return: the created file handler
169187 """
170188 global _isAtExitReportFileLoggerRegistered
171189 log .info (f"Logging to { path } ..." )
190+ dirname = os .path .dirname (path )
191+ if dirname and not os .path .exists (dirname ):
192+ os .makedirs (dirname )
172193 mode = "a" if append else "w"
173194 handler = FileHandler (path , mode = mode , encoding = encoding )
174195 handler .setFormatter (Formatter (_logFormat ))
@@ -397,7 +418,7 @@ class FileLoggerContext(LoggerContext[FileHandler]):
397418
398419 def __init__ (self , path : str , append = True , enabled = True , encoding = LOG_FILE_DEFAULT_ENCODING ):
399420 """
400- :param path: the path to the log file
421+ :param path: the path to the log file; directories will be created as needed
401422 :param append: whether to append in case the file already exists; if False, always create a new file.
402423 :param enabled: whether to actually perform any logging.
403424 This switch allows the with statement to be applied regardless of whether logging shall be enabled.
0 commit comments