Log to file instead of syslog via command-line "--log-file" flag (#233).

This commit is contained in:
Dan Helfman 2019-11-02 17:43:39 +00:00 committed by Gitea
commit 06f134cc71
4 changed files with 53 additions and 5 deletions

View File

@ -149,6 +149,12 @@ def parse_arguments(*unparsed_arguments):
default=0, default=0,
help='Display verbose progress to syslog (from none to lots: 0, 1, or 2). Ignored when console is interactive', 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( global_group.add_argument(
'--version', '--version',
dest='version', dest='version',

View File

@ -487,6 +487,7 @@ def main(): # pragma: no cover
configure_logging( configure_logging(
verbosity_to_log_level(global_arguments.verbosity), verbosity_to_log_level(global_arguments.verbosity),
verbosity_to_log_level(global_arguments.syslog_verbosity), verbosity_to_log_level(global_arguments.syslog_verbosity),
global_arguments.log_file,
) )
logger.debug('Ensuring legacy configuration is upgraded') logger.debug('Ensuring legacy configuration is upgraded')

View File

@ -73,7 +73,7 @@ def color_text(color, message):
return '{}{}{}'.format(color, message, colorama.Style.RESET_ALL) 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. Configure logging to go to both the console and syslog. Use the given log levels, respectively.
''' '''
@ -85,16 +85,29 @@ def configure_logging(console_log_level, syslog_log_level=None):
console_handler.setLevel(console_log_level) console_handler.setLevel(console_log_level)
syslog_path = None syslog_path = None
if os.path.exists('/dev/log'): if log_file is None:
syslog_path = '/dev/log' if os.path.exists('/dev/log'):
elif os.path.exists('/var/run/syslog'): syslog_path = '/dev/log'
syslog_path = '/var/run/syslog' 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():
syslog_handler = logging.handlers.SysLogHandler(address=syslog_path) syslog_handler = logging.handlers.SysLogHandler(address=syslog_path)
syslog_handler.setFormatter(logging.Formatter('borgmatic: %(levelname)s %(message)s')) syslog_handler.setFormatter(logging.Formatter('borgmatic: %(levelname)s %(message)s'))
syslog_handler.setLevel(syslog_log_level) syslog_handler.setLevel(syslog_log_level)
handlers = (console_handler, syslog_handler) handlers = (console_handler, syslog_handler)
elif 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)
else: else:
handlers = (console_handler,) handlers = (console_handler,)

View File

@ -193,3 +193,31 @@ def test_configure_logging_skips_syslog_if_interactive_console():
flexmock(module.logging.handlers).should_receive('SysLogHandler').never() flexmock(module.logging.handlers).should_receive('SysLogHandler').never()
module.configure_logging(console_log_level=logging.INFO) 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)