diff --git a/docs/resources/log.config b/docs/resources/log.config index 5c263efe22..f36fcb1914 100644 --- a/docs/resources/log.config +++ b/docs/resources/log.config @@ -1,21 +1,15 @@ [loggers] -keys=root,modelLogger +keys=root [handlers] -keys=consoleHandler +keys=consoleHandler,errorFileHandler [formatters] keys=fullFormatter [logger_root] level=INFO -handlers=consoleHandler - -[logger_modelLogger] -level=DEBUG -handlers=consoleHandler -qualname=modelLogger -propagate=0 +handlers=consoleHandler,errorFileHandler [handler_consoleHandler] class=StreamHandler @@ -23,5 +17,11 @@ level=DEBUG formatter=fullFormatter args=(sys.stdout,) +[handler_errorFileHandler] +class=FileHandler +level=ERROR +formatter=fullFormatter +args=('error.log', 'a') + [formatter_fullFormatter] format=%(asctime)s - %(name)s - %(levelname)s - %(message)s \ No newline at end of file diff --git a/nvflare/lighter/impl/master_template.yml b/nvflare/lighter/impl/master_template.yml index e4c4e72fdd..1265d1206e 100644 --- a/nvflare/lighter/impl/master_template.yml +++ b/nvflare/lighter/impl/master_template.yml @@ -302,14 +302,14 @@ log_config: | keys=root [handlers] - keys=consoleHandler + keys=consoleHandler,errorFileHandler [formatters] keys=fullFormatter [logger_root] level=INFO - handlers=consoleHandler + handlers=consoleHandler,errorFileHandler [handler_consoleHandler] class=StreamHandler @@ -317,6 +317,12 @@ log_config: | formatter=fullFormatter args=(sys.stdout,) + [handler_errorFileHandler] + class=FileHandler + level=ERROR + formatter=fullFormatter + args=('error.log', 'a') + [formatter_fullFormatter] format=%(asctime)s - %(name)s - %(levelname)s - %(message)s diff --git a/nvflare/private/fed/app/simulator/log.config b/nvflare/private/fed/app/simulator/log.config index ceadd4c93e..3b85259cfd 100644 --- a/nvflare/private/fed/app/simulator/log.config +++ b/nvflare/private/fed/app/simulator/log.config @@ -2,14 +2,14 @@ keys=root [handlers] -keys=consoleHandler +keys=consoleHandler,errorFileHandler [formatters] keys=fullFormatter [logger_root] level=INFO -handlers=consoleHandler +handlers=consoleHandler,errorFileHandler [handler_consoleHandler] class=StreamHandler @@ -17,5 +17,11 @@ level=DEBUG formatter=fullFormatter args=(sys.stdout,) +[handler_errorFileHandler] +class=FileHandler +level=ERROR +formatter=fullFormatter +args=('error.log', 'a') + [formatter_fullFormatter] format=%(asctime)s - %(name)s - %(levelname)s - %(message)s diff --git a/nvflare/private/fed/utils/fed_utils.py b/nvflare/private/fed/utils/fed_utils.py index 8e807e5fe9..2b3052ee3d 100644 --- a/nvflare/private/fed/utils/fed_utils.py +++ b/nvflare/private/fed/utils/fed_utils.py @@ -59,14 +59,45 @@ from .app_authz import AppAuthzService -def add_logfile_handler(log_file): +def add_logfile_handler(log_file: str): + """Adds a log file handler to the root logger. + + The purpose for this is to handle dynamic log file locations. + + If a handler named errorFileHandler is found, it will be used as a template to + create a new handler for writing to the error.log file at the same directory as log_file. + The original errorFileHandler will be removed and replaced by the new handler. + + Each log file will be rotated when it reaches 20MB. + + Args: + log_file (str): log file path + """ root_logger = logging.getLogger() + configured_handlers = root_logger.handlers main_handler = root_logger.handlers[0] file_handler = RotatingFileHandler(log_file, maxBytes=20 * 1024 * 1024, backupCount=10) file_handler.setLevel(main_handler.level) file_handler.setFormatter(main_handler.formatter) root_logger.addHandler(file_handler) + configured_error_handler = None + for handler in configured_handlers: + if handler.get_name() == "errorFileHandler": + configured_error_handler = handler + break + + if not configured_error_handler: + return + + error_log_file = os.path.join(os.path.dirname(log_file), "error.log") + error_file_handler = RotatingFileHandler(error_log_file, maxBytes=20 * 1024 * 1024, backupCount=10) + error_file_handler.setLevel(configured_error_handler.level) + error_file_handler.setFormatter(configured_error_handler.formatter) + + root_logger.addHandler(error_file_handler) + root_logger.removeHandler(configured_error_handler) + def _check_secure_content(site_type: str) -> List[str]: """To check the security contents.