From 22640a9ca0712ae0220e7892169817492fb8a961 Mon Sep 17 00:00:00 2001 From: palto42 <12280188+palto42@users.noreply.github.com> Date: Thu, 31 Oct 2019 10:44:22 +0100 Subject: [PATCH 1/5] new option for log-file --- borgmatic/commands/arguments.py | 6 ++++++ borgmatic/commands/borgmatic.py | 1 + borgmatic/logger.py | 12 ++++++++---- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/borgmatic/commands/arguments.py b/borgmatic/commands/arguments.py index db92bdcc6..0e72d8ec8 100644 --- a/borgmatic/commands/arguments.py +++ b/borgmatic/commands/arguments.py @@ -148,6 +148,12 @@ def parse_arguments(*unparsed_arguments): default=0, help='Display verbose progress to syslog (from none to lots: 0, 1, or 2). Ignored when console is interactive', ) + global_group.add_argument( + '--log-file', + type=str, + default=None, + help='Write log messages to this file instead of concole and syslog', + ) global_group.add_argument( '--version', dest='version', diff --git a/borgmatic/commands/borgmatic.py b/borgmatic/commands/borgmatic.py index 71abd05f2..7c6139963 100644 --- a/borgmatic/commands/borgmatic.py +++ b/borgmatic/commands/borgmatic.py @@ -433,6 +433,7 @@ def main(): # pragma: no cover configure_logging( verbosity_to_log_level(global_arguments.verbosity), verbosity_to_log_level(global_arguments.syslog_verbosity), + global_arguments.log_file, ) logger.debug('Ensuring legacy configuration is upgraded') diff --git a/borgmatic/logger.py b/borgmatic/logger.py index 7bbb912b1..9d14c3d72 100644 --- a/borgmatic/logger.py +++ b/borgmatic/logger.py @@ -73,15 +73,19 @@ def color_text(color, message): return '{}{}{}'.format(color, message, colorama.Style.RESET_ALL) -def configure_logging(console_log_level, syslog_log_level=None): +def configure_logging(console_log_level, syslog_log_level=None, log_file=None): ''' Configure logging to go to both the console and syslog. Use the given log levels, respectively. ''' if syslog_log_level is None: syslog_log_level = console_log_level - console_handler = logging.StreamHandler() - console_handler.setFormatter(Console_color_formatter()) + if log_file is None: + console_handler = logging.StreamHandler() + console_handler.setFormatter(Console_color_formatter()) + else: + console_handler = logging.FileHandler(log_file) + console_handler.setFormatter(logging.Formatter('[%(asctime)s] %(levelname)s: %(message)s')) console_handler.setLevel(console_log_level) syslog_path = None @@ -90,7 +94,7 @@ def configure_logging(console_log_level, syslog_log_level=None): elif os.path.exists('/var/run/syslog'): syslog_path = '/var/run/syslog' - if syslog_path and not interactive_console(): + if syslog_path and not interactive_console() and log_file is None: syslog_handler = logging.handlers.SysLogHandler(address=syslog_path) syslog_handler.setFormatter(logging.Formatter('borgmatic: %(levelname)s %(message)s')) syslog_handler.setLevel(syslog_log_level) From 8c8640d0abe6d98c837fb7840f9bffa99cee9dc6 Mon Sep 17 00:00:00 2001 From: palto42 <12280188+palto42@users.noreply.github.com> Date: Fri, 1 Nov 2019 18:42:24 +0100 Subject: [PATCH 2/5] file-logger replaces syslog --- borgmatic/logger.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/borgmatic/logger.py b/borgmatic/logger.py index 9d14c3d72..9b4a7954b 100644 --- a/borgmatic/logger.py +++ b/borgmatic/logger.py @@ -80,25 +80,27 @@ def configure_logging(console_log_level, syslog_log_level=None, log_file=None): if syslog_log_level is None: syslog_log_level = console_log_level - if log_file is None: - console_handler = logging.StreamHandler() - console_handler.setFormatter(Console_color_formatter()) - else: - console_handler = logging.FileHandler(log_file) - console_handler.setFormatter(logging.Formatter('[%(asctime)s] %(levelname)s: %(message)s')) + console_handler = logging.StreamHandler() + console_handler.setFormatter(Console_color_formatter()) console_handler.setLevel(console_log_level) syslog_path = None - if os.path.exists('/dev/log'): - syslog_path = '/dev/log' - elif os.path.exists('/var/run/syslog'): - syslog_path = '/var/run/syslog' + if log_file is None: + if os.path.exists('/dev/log'): + syslog_path = '/dev/log' + elif os.path.exists('/var/run/syslog'): + syslog_path = '/var/run/syslog' - if syslog_path and not interactive_console() and log_file is None: + if syslog_path and not interactive_console(): syslog_handler = logging.handlers.SysLogHandler(address=syslog_path) syslog_handler.setFormatter(logging.Formatter('borgmatic: %(levelname)s %(message)s')) syslog_handler.setLevel(syslog_log_level) handlers = (console_handler, syslog_handler) + elif log_file: + file_handler = logging.FileHandler(log_file) + file_handler.setFormatter(logging.Formatter('[%(asctime)s] %(levelname)s: %(message)s')) + file_handler.setLevel(syslog_log_level) + handlers = (console_handler, file_handler) else: handlers = (console_handler,) From 6da05cbe2ddcd76a6468cb116d4c3932cbed838b Mon Sep 17 00:00:00 2001 From: palto42 <12280188+palto42@users.noreply.github.com> Date: Sat, 2 Nov 2019 14:33:57 +0100 Subject: [PATCH 3/5] Exception handling for logfile option --- borgmatic/logger.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/borgmatic/logger.py b/borgmatic/logger.py index 9b4a7954b..01b286f6f 100644 --- a/borgmatic/logger.py +++ b/borgmatic/logger.py @@ -97,7 +97,14 @@ def configure_logging(console_log_level, syslog_log_level=None, log_file=None): syslog_handler.setLevel(syslog_log_level) handlers = (console_handler, syslog_handler) elif log_file: - file_handler = logging.FileHandler(log_file) + try: + file_handler = logging.FileHandler(log_file) + except FileNotFoundError: + print("ERROR: Path to log-file doesn't exist: {}".format(log_file)) + sys.exit(1) + except PermissionError: + print("ERROR: No write access to log-file: {}".format(log_file)) + sys.exit(1) file_handler.setFormatter(logging.Formatter('[%(asctime)s] %(levelname)s: %(message)s')) file_handler.setLevel(syslog_log_level) handlers = (console_handler, file_handler) From 26a1a3d1e075a9247e60a40aed0303b96808a840 Mon Sep 17 00:00:00 2001 From: palto42 <12280188+palto42@users.noreply.github.com> Date: Sat, 2 Nov 2019 14:34:16 +0100 Subject: [PATCH 4/5] test cases for logfile option --- .gitignore | 4 ++++ tests/unit/test_logger.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/.gitignore b/.gitignore index f5883b582..fa9862025 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,7 @@ __pycache__ build/ dist/ pip-wheel-metadata/ + + +.vscode +.venv \ No newline at end of file diff --git a/tests/unit/test_logger.py b/tests/unit/test_logger.py index 5cec8767a..c2955df42 100644 --- a/tests/unit/test_logger.py +++ b/tests/unit/test_logger.py @@ -193,3 +193,31 @@ def test_configure_logging_skips_syslog_if_interactive_console(): flexmock(module.logging.handlers).should_receive('SysLogHandler').never() module.configure_logging(console_log_level=logging.INFO) + + +def test_configure_logging_to_logfile_instead_syslog(): + # syslog skipped in non-interactive console if --log-file argument provided + flexmock(module).should_receive('interactive_console').and_return(False) + flexmock(module.logging).should_receive('basicConfig').with_args( + level=logging.INFO, handlers=tuple + ) + flexmock(module.os.path).should_receive('exists').with_args('/dev/log').and_return(True) + flexmock(module.logging.handlers).should_receive('SysLogHandler').never() + file_handler = logging.FileHandler('/tmp/logfile') + flexmock(module.logging).should_receive('FileHandler').with_args('/tmp/logfile').and_return( + file_handler + ).once() + + module.configure_logging(console_log_level=logging.INFO, log_file='/tmp/logfile') + + +def test_configure_logging_skips_logfile_if_argument_is_none(): + # No FileHandler added if argument --log-file is None + flexmock(module).should_receive('interactive_console').and_return(False) + flexmock(module.logging).should_receive('basicConfig').with_args( + level=logging.INFO, handlers=tuple + ) + flexmock(module.os.path).should_receive('exists').and_return(False) + flexmock(module.logging).should_receive('FileHandler').never() + + module.configure_logging(console_log_level=logging.INFO, log_file=None) From 584359b6c0abe9a9e4aaf9612eca2a0c2a764bb9 Mon Sep 17 00:00:00 2001 From: palto42 <12280188+palto42@users.noreply.github.com> Date: Sat, 2 Nov 2019 14:36:31 +0100 Subject: [PATCH 5/5] .gitignore --- .gitignore | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.gitignore b/.gitignore index fa9862025..f5883b582 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,3 @@ __pycache__ build/ dist/ pip-wheel-metadata/ - - -.vscode -.venv \ No newline at end of file