Handle log file error more consistently with other error. Add --log-file-verbosity flag. Add docs.
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details

This commit is contained in:
Dan Helfman 2019-11-02 11:23:18 -07:00
parent 06f134cc71
commit a9104ed090
7 changed files with 57 additions and 23 deletions

3
NEWS
View File

@ -1,3 +1,6 @@
1.4.5
* Log to file instead of syslog via command-line "--log-file" flag.
1.4.4
* #234: Support for Borg --keep-exclude-tags and --exclude-nodump options.

View File

@ -147,13 +147,20 @@ def parse_arguments(*unparsed_arguments):
type=int,
choices=range(0, 3),
default=0,
help='Display verbose progress to syslog (from none to lots: 0, 1, or 2). Ignored when console is interactive',
help='Log verbose progress to syslog (from none to lots: 0, 1, or 2). Ignored when console is interactive or --log-file is given',
)
global_group.add_argument(
'--log-file-verbosity',
type=int,
choices=range(0, 3),
default=1,
help='Log verbose progress to log file (from none to lots: 0, 1, or 2). Only used when --log-file is given',
)
global_group.add_argument(
'--log-file',
type=str,
default=None,
help='Write log messages to this file instead of concole and syslog',
help='Write log messages to this file instead of syslog',
)
global_group.add_argument(
'--version',

View File

@ -484,11 +484,17 @@ def main(): # pragma: no cover
configs, parse_logs = load_configurations(config_filenames)
colorama.init(autoreset=True, strip=not should_do_markup(global_arguments.no_color, configs))
configure_logging(
verbosity_to_log_level(global_arguments.verbosity),
verbosity_to_log_level(global_arguments.syslog_verbosity),
global_arguments.log_file,
)
try:
configure_logging(
verbosity_to_log_level(global_arguments.verbosity),
verbosity_to_log_level(global_arguments.syslog_verbosity),
verbosity_to_log_level(global_arguments.log_file_verbosity),
global_arguments.log_file,
)
except (FileNotFoundError, PermissionError) as error:
configure_logging(logging.CRITICAL)
logger.critical('Error configuring logging: {}'.format(error))
exit_with_help_link()
logger.debug('Ensuring legacy configuration is upgraded')
convert.guard_configuration_upgraded(LEGACY_CONFIG_PATH, config_filenames)

View File

@ -73,12 +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, log_file=None):
def configure_logging(
console_log_level, syslog_log_level=None, log_file_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 or log file). Use the given log levels,
respectively.
Raise FileNotFoundError or PermissionError if the log file could not be opened for writing.
'''
if syslog_log_level is None:
syslog_log_level = console_log_level
if log_file_log_level is None:
log_file_log_level = console_log_level
console_handler = logging.StreamHandler()
console_handler.setFormatter(Console_color_formatter())
@ -97,18 +104,13 @@ 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:
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 = logging.FileHandler(log_file)
file_handler.setFormatter(logging.Formatter('[%(asctime)s] %(levelname)s: %(message)s'))
file_handler.setLevel(syslog_log_level)
file_handler.setLevel(log_file_log_level)
handlers = (console_handler, file_handler)
else:
handlers = (console_handler,)
logging.basicConfig(level=min(console_log_level, syslog_log_level), handlers=handlers)
logging.basicConfig(
level=min(console_log_level, syslog_log_level, log_file_log_level), handlers=handlers
)

View File

@ -70,6 +70,20 @@ Or to increase syslog logging to include debug spew:
borgmatic --syslog-verbosity 2
```
### Logging to file
If you don't want to use syslog, and you'd rather borgmatic log to a plain
file, use the `--log-file` flag:
```bash
borgmatic --log-file /path/to/file.log
```
Note that if you use the `--log-file` flag, you are responsible for rotating
the log file so it doesn't grow too large. Also, there is also
`--log-file-verbosity` flag to customize the log file's log level.
### systemd journal
If your local syslog daemon is systemd's journal, be aware that journald by

View File

@ -1,6 +1,6 @@
from setuptools import find_packages, setup
VERSION = '1.4.4'
VERSION = '1.4.5'
setup(

View File

@ -195,11 +195,11 @@ def test_configure_logging_skips_syslog_if_interactive_console():
module.configure_logging(console_log_level=logging.INFO)
def test_configure_logging_to_logfile_instead_syslog():
def test_configure_logging_to_logfile_instead_of_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
level=logging.DEBUG, handlers=tuple
)
flexmock(module.os.path).should_receive('exists').with_args('/dev/log').and_return(True)
flexmock(module.logging.handlers).should_receive('SysLogHandler').never()
@ -208,7 +208,9 @@ def test_configure_logging_to_logfile_instead_syslog():
file_handler
).once()
module.configure_logging(console_log_level=logging.INFO, log_file='/tmp/logfile')
module.configure_logging(
console_log_level=logging.INFO, log_file_log_level=logging.DEBUG, log_file='/tmp/logfile'
)
def test_configure_logging_skips_logfile_if_argument_is_none():