Handle log file error more consistently with other error. Add --log-file-verbosity flag. Add docs.
This commit is contained in:
parent
06f134cc71
commit
a9104ed090
7 changed files with 57 additions and 23 deletions
3
NEWS
3
NEWS
|
@ -1,3 +1,6 @@
|
||||||
|
1.4.5
|
||||||
|
* Log to file instead of syslog via command-line "--log-file" flag.
|
||||||
|
|
||||||
1.4.4
|
1.4.4
|
||||||
* #234: Support for Borg --keep-exclude-tags and --exclude-nodump options.
|
* #234: Support for Borg --keep-exclude-tags and --exclude-nodump options.
|
||||||
|
|
||||||
|
|
|
@ -147,13 +147,20 @@ def parse_arguments(*unparsed_arguments):
|
||||||
type=int,
|
type=int,
|
||||||
choices=range(0, 3),
|
choices=range(0, 3),
|
||||||
default=0,
|
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(
|
global_group.add_argument(
|
||||||
'--log-file',
|
'--log-file',
|
||||||
type=str,
|
type=str,
|
||||||
default=None,
|
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(
|
global_group.add_argument(
|
||||||
'--version',
|
'--version',
|
||||||
|
|
|
@ -484,11 +484,17 @@ def main(): # pragma: no cover
|
||||||
configs, parse_logs = load_configurations(config_filenames)
|
configs, parse_logs = load_configurations(config_filenames)
|
||||||
|
|
||||||
colorama.init(autoreset=True, strip=not should_do_markup(global_arguments.no_color, configs))
|
colorama.init(autoreset=True, strip=not should_do_markup(global_arguments.no_color, configs))
|
||||||
|
try:
|
||||||
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),
|
||||||
|
verbosity_to_log_level(global_arguments.log_file_verbosity),
|
||||||
global_arguments.log_file,
|
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')
|
logger.debug('Ensuring legacy configuration is upgraded')
|
||||||
convert.guard_configuration_upgraded(LEGACY_CONFIG_PATH, config_filenames)
|
convert.guard_configuration_upgraded(LEGACY_CONFIG_PATH, config_filenames)
|
||||||
|
|
|
@ -73,12 +73,19 @@ 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, 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:
|
if syslog_log_level is None:
|
||||||
syslog_log_level = console_log_level
|
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 = logging.StreamHandler()
|
||||||
console_handler.setFormatter(Console_color_formatter())
|
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)
|
syslog_handler.setLevel(syslog_log_level)
|
||||||
handlers = (console_handler, syslog_handler)
|
handlers = (console_handler, syslog_handler)
|
||||||
elif log_file:
|
elif log_file:
|
||||||
try:
|
|
||||||
file_handler = logging.FileHandler(log_file)
|
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.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)
|
handlers = (console_handler, file_handler)
|
||||||
else:
|
else:
|
||||||
handlers = (console_handler,)
|
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
|
||||||
|
)
|
||||||
|
|
|
@ -70,6 +70,20 @@ Or to increase syslog logging to include debug spew:
|
||||||
borgmatic --syslog-verbosity 2
|
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
|
### systemd journal
|
||||||
|
|
||||||
If your local syslog daemon is systemd's journal, be aware that journald by
|
If your local syslog daemon is systemd's journal, be aware that journald by
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -1,6 +1,6 @@
|
||||||
from setuptools import find_packages, setup
|
from setuptools import find_packages, setup
|
||||||
|
|
||||||
VERSION = '1.4.4'
|
VERSION = '1.4.5'
|
||||||
|
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
|
|
|
@ -195,11 +195,11 @@ def test_configure_logging_skips_syslog_if_interactive_console():
|
||||||
module.configure_logging(console_log_level=logging.INFO)
|
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
|
# syslog skipped in non-interactive console if --log-file argument provided
|
||||||
flexmock(module).should_receive('interactive_console').and_return(False)
|
flexmock(module).should_receive('interactive_console').and_return(False)
|
||||||
flexmock(module.logging).should_receive('basicConfig').with_args(
|
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.os.path).should_receive('exists').with_args('/dev/log').and_return(True)
|
||||||
flexmock(module.logging.handlers).should_receive('SysLogHandler').never()
|
flexmock(module.logging.handlers).should_receive('SysLogHandler').never()
|
||||||
|
@ -208,7 +208,9 @@ def test_configure_logging_to_logfile_instead_syslog():
|
||||||
file_handler
|
file_handler
|
||||||
).once()
|
).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():
|
def test_configure_logging_skips_logfile_if_argument_is_none():
|
||||||
|
|
Loading…
Reference in a new issue