From f4744826fedab1e70dc0993112444288bf5a84c1 Mon Sep 17 00:00:00 2001 From: Dan Helfman Date: Sun, 11 Feb 2024 17:44:43 -0800 Subject: [PATCH] When the "--json" flag is given, suppress console escape codes so as not to interfere with JSON output (#827). --- NEWS | 2 + borgmatic/commands/borgmatic.py | 7 ++- borgmatic/logger.py | 8 ++- tests/unit/test_logger.py | 96 ++++++++++++++++----------------- 4 files changed, 57 insertions(+), 56 deletions(-) diff --git a/NEWS b/NEWS index abee6fd..054142c 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,6 @@ 1.8.9.dev0 + * #827: When the "--json" flag is given, suppress console escape codes so as not to + interfere with JSON output. * Clarify documentation about restoring a database: borgmatic does not create the database upon restore. diff --git a/borgmatic/commands/borgmatic.py b/borgmatic/commands/borgmatic.py index d4d68d5..ad79045 100644 --- a/borgmatic/commands/borgmatic.py +++ b/borgmatic/commands/borgmatic.py @@ -872,10 +872,8 @@ def main(extra_summary_logs=[]): # pragma: no cover any_json_flags = any( getattr(sub_arguments, 'json', False) for sub_arguments in arguments.values() ) - colorama.init( - autoreset=True, - strip=not should_do_markup(global_arguments.no_color or any_json_flags, configs), - ) + color_enabled = should_do_markup(global_arguments.no_color or any_json_flags, configs) + colorama.init(autoreset=color_enabled, strip=not color_enabled) try: configure_logging( verbosity_to_log_level(global_arguments.verbosity), @@ -884,6 +882,7 @@ def main(extra_summary_logs=[]): # pragma: no cover verbosity_to_log_level(global_arguments.monitoring_verbosity), global_arguments.log_file, global_arguments.log_file_format, + color_enabled=color_enabled, ) except (FileNotFoundError, PermissionError) as error: configure_logging(logging.CRITICAL) diff --git a/borgmatic/logger.py b/borgmatic/logger.py index 9703924..bb9cbee 100644 --- a/borgmatic/logger.py +++ b/borgmatic/logger.py @@ -159,10 +159,11 @@ def configure_logging( monitoring_log_level=None, log_file=None, log_file_format=None, + color_enabled=True, ): ''' Configure logging to go to both the console and (syslog or log file). Use the given log levels, - respectively. + respectively. If color is enabled, set up log formatting accordingly. Raise FileNotFoundError or PermissionError if the log file could not be opened for writing. ''' @@ -191,7 +192,10 @@ def configure_logging( logging.DEBUG: console_standard_handler, } ) - console_handler.setFormatter(Console_color_formatter()) + + if color_enabled: + console_handler.setFormatter(Console_color_formatter()) + console_handler.setLevel(console_log_level) handlers = [console_handler] diff --git a/tests/unit/test_logger.py b/tests/unit/test_logger.py index 71348a4..c69b932 100644 --- a/tests/unit/test_logger.py +++ b/tests/unit/test_logger.py @@ -177,11 +177,9 @@ def test_add_logging_level_skips_global_setting_if_already_set(): def test_configure_logging_with_syslog_log_level_probes_for_log_socket_on_linux(): flexmock(module).should_receive('add_custom_log_levels') flexmock(module.logging).ANSWER = module.ANSWER - flexmock(module).should_receive('Multi_stream_handler').and_return( - flexmock( - setFormatter=lambda formatter: None, setLevel=lambda level: None, level=logging.INFO - ) - ) + multi_stream_handler = flexmock(setLevel=lambda level: None, level=logging.INFO) + multi_stream_handler.should_receive('setFormatter').once() + flexmock(module).should_receive('Multi_stream_handler').and_return(multi_stream_handler) flexmock(module).should_receive('Console_color_formatter') flexmock(module).should_receive('interactive_console').and_return(False) flexmock(module.logging).should_receive('basicConfig').with_args( @@ -199,11 +197,9 @@ def test_configure_logging_with_syslog_log_level_probes_for_log_socket_on_linux( def test_configure_logging_with_syslog_log_level_probes_for_log_socket_on_macos(): flexmock(module).should_receive('add_custom_log_levels') flexmock(module.logging).ANSWER = module.ANSWER - flexmock(module).should_receive('Multi_stream_handler').and_return( - flexmock( - setFormatter=lambda formatter: None, setLevel=lambda level: None, level=logging.INFO - ) - ) + multi_stream_handler = flexmock(setLevel=lambda level: None, level=logging.INFO) + multi_stream_handler.should_receive('setFormatter').once() + flexmock(module).should_receive('Multi_stream_handler').and_return(multi_stream_handler) flexmock(module).should_receive('Console_color_formatter') flexmock(module).should_receive('interactive_console').and_return(False) flexmock(module.logging).should_receive('basicConfig').with_args( @@ -222,11 +218,9 @@ def test_configure_logging_with_syslog_log_level_probes_for_log_socket_on_macos( def test_configure_logging_with_syslog_log_level_probes_for_log_socket_on_freebsd(): flexmock(module).should_receive('add_custom_log_levels') flexmock(module.logging).ANSWER = module.ANSWER - flexmock(module).should_receive('Multi_stream_handler').and_return( - flexmock( - setFormatter=lambda formatter: None, setLevel=lambda level: None, level=logging.INFO - ) - ) + multi_stream_handler = flexmock(setLevel=lambda level: None, level=logging.INFO) + multi_stream_handler.should_receive('setFormatter').once() + flexmock(module).should_receive('Multi_stream_handler').and_return(multi_stream_handler) flexmock(module).should_receive('Console_color_formatter') flexmock(module).should_receive('interactive_console').and_return(False) flexmock(module.logging).should_receive('basicConfig').with_args( @@ -246,11 +240,9 @@ def test_configure_logging_with_syslog_log_level_probes_for_log_socket_on_freebs def test_configure_logging_without_syslog_log_level_skips_syslog(): flexmock(module).should_receive('add_custom_log_levels') flexmock(module.logging).ANSWER = module.ANSWER - flexmock(module).should_receive('Multi_stream_handler').and_return( - flexmock( - setFormatter=lambda formatter: None, setLevel=lambda level: None, level=logging.INFO - ) - ) + multi_stream_handler = flexmock(setLevel=lambda level: None, level=logging.INFO) + multi_stream_handler.should_receive('setFormatter').once() + flexmock(module).should_receive('Multi_stream_handler').and_return(multi_stream_handler) flexmock(module).should_receive('Console_color_formatter') flexmock(module.logging).should_receive('basicConfig').with_args( level=logging.INFO, handlers=list @@ -264,11 +256,9 @@ def test_configure_logging_without_syslog_log_level_skips_syslog(): def test_configure_logging_skips_syslog_if_not_found(): flexmock(module).should_receive('add_custom_log_levels') flexmock(module.logging).ANSWER = module.ANSWER - flexmock(module).should_receive('Multi_stream_handler').and_return( - flexmock( - setFormatter=lambda formatter: None, setLevel=lambda level: None, level=logging.INFO - ) - ) + multi_stream_handler = flexmock(setLevel=lambda level: None, level=logging.INFO) + multi_stream_handler.should_receive('setFormatter').once() + flexmock(module).should_receive('Multi_stream_handler').and_return(multi_stream_handler) flexmock(module).should_receive('Console_color_formatter') flexmock(module.logging).should_receive('basicConfig').with_args( level=logging.INFO, handlers=list @@ -282,11 +272,9 @@ def test_configure_logging_skips_syslog_if_not_found(): def test_configure_logging_skips_log_file_if_log_file_logging_is_disabled(): flexmock(module).should_receive('add_custom_log_levels') flexmock(module.logging).DISABLED = module.DISABLED - flexmock(module).should_receive('Multi_stream_handler').and_return( - flexmock( - setFormatter=lambda formatter: None, setLevel=lambda level: None, level=logging.INFO - ) - ) + multi_stream_handler = flexmock(setLevel=lambda level: None, level=logging.INFO) + multi_stream_handler.should_receive('setFormatter').once() + flexmock(module).should_receive('Multi_stream_handler').and_return(multi_stream_handler) flexmock(module.logging).should_receive('basicConfig').with_args( level=logging.INFO, handlers=list @@ -303,11 +291,9 @@ def test_configure_logging_skips_log_file_if_log_file_logging_is_disabled(): def test_configure_logging_to_log_file_instead_of_syslog(): flexmock(module).should_receive('add_custom_log_levels') flexmock(module.logging).ANSWER = module.ANSWER - flexmock(module).should_receive('Multi_stream_handler').and_return( - flexmock( - setFormatter=lambda formatter: None, setLevel=lambda level: None, level=logging.INFO - ) - ) + multi_stream_handler = flexmock(setLevel=lambda level: None, level=logging.INFO) + multi_stream_handler.should_receive('setFormatter').once() + flexmock(module).should_receive('Multi_stream_handler').and_return(multi_stream_handler) flexmock(module.logging).should_receive('basicConfig').with_args( level=logging.DEBUG, handlers=list @@ -330,11 +316,9 @@ def test_configure_logging_to_log_file_instead_of_syslog(): def test_configure_logging_to_both_log_file_and_syslog(): flexmock(module).should_receive('add_custom_log_levels') flexmock(module.logging).ANSWER = module.ANSWER - flexmock(module).should_receive('Multi_stream_handler').and_return( - flexmock( - setFormatter=lambda formatter: None, setLevel=lambda level: None, level=logging.INFO - ) - ) + multi_stream_handler = flexmock(setLevel=lambda level: None, level=logging.INFO) + multi_stream_handler.should_receive('setFormatter').once() + flexmock(module).should_receive('Multi_stream_handler').and_return(multi_stream_handler) flexmock(module.logging).should_receive('basicConfig').with_args( level=logging.DEBUG, handlers=list @@ -363,11 +347,9 @@ def test_configure_logging_to_log_file_formats_with_custom_log_format(): flexmock(module.logging).should_receive('Formatter').with_args( '{message}', style='{' # noqa: FS003 ).once() - flexmock(module).should_receive('Multi_stream_handler').and_return( - flexmock( - setFormatter=lambda formatter: None, setLevel=lambda level: None, level=logging.INFO - ) - ) + multi_stream_handler = flexmock(setLevel=lambda level: None, level=logging.INFO) + multi_stream_handler.should_receive('setFormatter').once() + flexmock(module).should_receive('Multi_stream_handler').and_return(multi_stream_handler) flexmock(module).should_receive('interactive_console').and_return(False) flexmock(module.logging).should_receive('basicConfig').with_args( @@ -391,11 +373,9 @@ def test_configure_logging_to_log_file_formats_with_custom_log_format(): def test_configure_logging_skips_log_file_if_argument_is_none(): flexmock(module).should_receive('add_custom_log_levels') flexmock(module.logging).ANSWER = module.ANSWER - flexmock(module).should_receive('Multi_stream_handler').and_return( - flexmock( - setFormatter=lambda formatter: None, setLevel=lambda level: None, level=logging.INFO - ) - ) + multi_stream_handler = flexmock(setLevel=lambda level: None, level=logging.INFO) + multi_stream_handler.should_receive('setFormatter').once() + flexmock(module).should_receive('Multi_stream_handler').and_return(multi_stream_handler) flexmock(module.logging).should_receive('basicConfig').with_args( level=logging.INFO, handlers=list @@ -404,3 +384,19 @@ def test_configure_logging_skips_log_file_if_argument_is_none(): flexmock(module.logging.handlers).should_receive('WatchedFileHandler').never() module.configure_logging(console_log_level=logging.INFO, log_file=None) + + +def test_configure_logging_skips_console_color_formatter_if_color_disabled(): + flexmock(module).should_receive('add_custom_log_levels') + flexmock(module.logging).ANSWER = module.ANSWER + multi_stream_handler = flexmock(setLevel=lambda level: None, level=logging.INFO) + multi_stream_handler.should_receive('setFormatter').never() + flexmock(module).should_receive('Multi_stream_handler').and_return(multi_stream_handler) + + flexmock(module.logging).should_receive('basicConfig').with_args( + level=logging.INFO, handlers=list + ) + flexmock(module.os.path).should_receive('exists').and_return(False) + flexmock(module.logging.handlers).should_receive('WatchedFileHandler').never() + + module.configure_logging(console_log_level=logging.INFO, log_file=None, color_enabled=False)