Add option to disable syslog output (#484).
Reviewed-on: https://projects.torsion.org/borgmatic-collective/borgmatic/pulls/675
This commit is contained in:
commit
c0aaba6891
8 changed files with 78 additions and 19 deletions
|
@ -152,30 +152,30 @@ def make_parsers():
|
||||||
'-v',
|
'-v',
|
||||||
'--verbosity',
|
'--verbosity',
|
||||||
type=int,
|
type=int,
|
||||||
choices=range(-1, 3),
|
choices=range(-2, 3),
|
||||||
default=0,
|
default=0,
|
||||||
help='Display verbose progress to the console (from only errors to very verbose: -1, 0, 1, or 2)',
|
help='Display verbose progress to the console (disabled, errors only, default, some, or lots: -2, -1, 0, 1, or 2)',
|
||||||
)
|
)
|
||||||
global_group.add_argument(
|
global_group.add_argument(
|
||||||
'--syslog-verbosity',
|
'--syslog-verbosity',
|
||||||
type=int,
|
type=int,
|
||||||
choices=range(-1, 3),
|
choices=range(-2, 3),
|
||||||
default=0,
|
default=0,
|
||||||
help='Log verbose progress to syslog (from only errors to very verbose: -1, 0, 1, or 2). Ignored when console is interactive or --log-file is given',
|
help='Log verbose progress to syslog (disabled, errors only, default, some, or lots: -2, -1, 0, 1, or 2). Ignored when console is interactive or --log-file is given',
|
||||||
)
|
)
|
||||||
global_group.add_argument(
|
global_group.add_argument(
|
||||||
'--log-file-verbosity',
|
'--log-file-verbosity',
|
||||||
type=int,
|
type=int,
|
||||||
choices=range(-1, 3),
|
choices=range(-2, 3),
|
||||||
default=0,
|
default=0,
|
||||||
help='Log verbose progress to log file (from only errors to very verbose: -1, 0, 1, or 2). Only used when --log-file is given',
|
help='Log verbose progress to log file (disabled, errors only, default, some, or lots: -2, -1, 0, 1, or 2). Only used when --log-file is given',
|
||||||
)
|
)
|
||||||
global_group.add_argument(
|
global_group.add_argument(
|
||||||
'--monitoring-verbosity',
|
'--monitoring-verbosity',
|
||||||
type=int,
|
type=int,
|
||||||
choices=range(-1, 3),
|
choices=range(-2, 3),
|
||||||
default=0,
|
default=0,
|
||||||
help='Log verbose progress to monitoring integrations that support logging (from only errors to very verbose: -1, 0, 1, or 2)',
|
help='Log verbose progress to monitoring integrations that support logging (from disabled, errors only, default, some, or lots: -2, -1, 0, 1, or 2)',
|
||||||
)
|
)
|
||||||
global_group.add_argument(
|
global_group.add_argument(
|
||||||
'--log-file',
|
'--log-file',
|
||||||
|
|
|
@ -36,7 +36,7 @@ from borgmatic.borg import version as borg_version
|
||||||
from borgmatic.commands.arguments import parse_arguments
|
from borgmatic.commands.arguments import parse_arguments
|
||||||
from borgmatic.config import checks, collect, convert, validate
|
from borgmatic.config import checks, collect, convert, validate
|
||||||
from borgmatic.hooks import command, dispatch, monitor
|
from borgmatic.hooks import command, dispatch, monitor
|
||||||
from borgmatic.logger import add_custom_log_levels, configure_logging, should_do_markup
|
from borgmatic.logger import add_custom_log_levels, configure_logging, should_do_markup, DISABLED
|
||||||
from borgmatic.signals import configure_signals
|
from borgmatic.signals import configure_signals
|
||||||
from borgmatic.verbosity import verbosity_to_log_level
|
from borgmatic.verbosity import verbosity_to_log_level
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@ def run_configuration(config_filename, config, arguments):
|
||||||
error_repository = ''
|
error_repository = ''
|
||||||
using_primary_action = {'create', 'prune', 'compact', 'check'}.intersection(arguments)
|
using_primary_action = {'create', 'prune', 'compact', 'check'}.intersection(arguments)
|
||||||
monitoring_log_level = verbosity_to_log_level(global_arguments.monitoring_verbosity)
|
monitoring_log_level = verbosity_to_log_level(global_arguments.monitoring_verbosity)
|
||||||
|
monitoring_hooks_are_activated = using_primary_action and monitoring_log_level != DISABLED
|
||||||
|
|
||||||
try:
|
try:
|
||||||
local_borg_version = borg_version.local_borg_version(storage, local_path)
|
local_borg_version = borg_version.local_borg_version(storage, local_path)
|
||||||
|
@ -78,7 +79,7 @@ def run_configuration(config_filename, config, arguments):
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if using_primary_action:
|
if monitoring_hooks_are_activated:
|
||||||
dispatch.call_hooks(
|
dispatch.call_hooks(
|
||||||
'initialize_monitor',
|
'initialize_monitor',
|
||||||
hooks,
|
hooks,
|
||||||
|
@ -87,7 +88,7 @@ def run_configuration(config_filename, config, arguments):
|
||||||
monitoring_log_level,
|
monitoring_log_level,
|
||||||
global_arguments.dry_run,
|
global_arguments.dry_run,
|
||||||
)
|
)
|
||||||
if using_primary_action:
|
|
||||||
dispatch.call_hooks(
|
dispatch.call_hooks(
|
||||||
'ping_monitor',
|
'ping_monitor',
|
||||||
hooks,
|
hooks,
|
||||||
|
@ -165,7 +166,7 @@ def run_configuration(config_filename, config, arguments):
|
||||||
error_repository = repository['path']
|
error_repository = repository['path']
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if using_primary_action:
|
if monitoring_hooks_are_activated:
|
||||||
# send logs irrespective of error
|
# send logs irrespective of error
|
||||||
dispatch.call_hooks(
|
dispatch.call_hooks(
|
||||||
'ping_monitor',
|
'ping_monitor',
|
||||||
|
@ -185,7 +186,7 @@ def run_configuration(config_filename, config, arguments):
|
||||||
|
|
||||||
if not encountered_error:
|
if not encountered_error:
|
||||||
try:
|
try:
|
||||||
if using_primary_action:
|
if monitoring_hooks_are_activated:
|
||||||
dispatch.call_hooks(
|
dispatch.call_hooks(
|
||||||
'ping_monitor',
|
'ping_monitor',
|
||||||
hooks,
|
hooks,
|
||||||
|
|
|
@ -141,6 +141,7 @@ def add_logging_level(level_name, level_number):
|
||||||
|
|
||||||
|
|
||||||
ANSWER = logging.WARN - 5
|
ANSWER = logging.WARN - 5
|
||||||
|
DISABLED = logging.CRITICAL + 10
|
||||||
|
|
||||||
|
|
||||||
def add_custom_log_levels(): # pragma: no cover
|
def add_custom_log_levels(): # pragma: no cover
|
||||||
|
@ -148,6 +149,7 @@ def add_custom_log_levels(): # pragma: no cover
|
||||||
Add a custom log level between WARN and INFO for user-requested answers.
|
Add a custom log level between WARN and INFO for user-requested answers.
|
||||||
'''
|
'''
|
||||||
add_logging_level('ANSWER', ANSWER)
|
add_logging_level('ANSWER', ANSWER)
|
||||||
|
add_logging_level('DISABLED', DISABLED)
|
||||||
|
|
||||||
|
|
||||||
def configure_logging(
|
def configure_logging(
|
||||||
|
@ -175,10 +177,12 @@ def configure_logging(
|
||||||
|
|
||||||
# Log certain log levels to console stderr and others to stdout. This supports use cases like
|
# Log certain log levels to console stderr and others to stdout. This supports use cases like
|
||||||
# grepping (non-error) output.
|
# grepping (non-error) output.
|
||||||
|
console_disabled = logging.NullHandler()
|
||||||
console_error_handler = logging.StreamHandler(sys.stderr)
|
console_error_handler = logging.StreamHandler(sys.stderr)
|
||||||
console_standard_handler = logging.StreamHandler(sys.stdout)
|
console_standard_handler = logging.StreamHandler(sys.stdout)
|
||||||
console_handler = Multi_stream_handler(
|
console_handler = Multi_stream_handler(
|
||||||
{
|
{
|
||||||
|
logging.DISABLED: console_disabled,
|
||||||
logging.CRITICAL: console_error_handler,
|
logging.CRITICAL: console_error_handler,
|
||||||
logging.ERROR: console_error_handler,
|
logging.ERROR: console_error_handler,
|
||||||
logging.WARN: console_error_handler,
|
logging.WARN: console_error_handler,
|
||||||
|
@ -191,7 +195,7 @@ def configure_logging(
|
||||||
console_handler.setLevel(console_log_level)
|
console_handler.setLevel(console_log_level)
|
||||||
|
|
||||||
syslog_path = None
|
syslog_path = None
|
||||||
if log_file is None:
|
if log_file is None and syslog_log_level != logging.DISABLED:
|
||||||
if os.path.exists('/dev/log'):
|
if os.path.exists('/dev/log'):
|
||||||
syslog_path = '/dev/log'
|
syslog_path = '/dev/log'
|
||||||
elif os.path.exists('/var/run/syslog'):
|
elif os.path.exists('/var/run/syslog'):
|
||||||
|
@ -206,7 +210,7 @@ def configure_logging(
|
||||||
)
|
)
|
||||||
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 and log_file_log_level != logging.DISABLED:
|
||||||
file_handler = logging.handlers.WatchedFileHandler(log_file)
|
file_handler = logging.handlers.WatchedFileHandler(log_file)
|
||||||
file_handler.setFormatter(
|
file_handler.setFormatter(
|
||||||
logging.Formatter(
|
logging.Formatter(
|
||||||
|
|
|
@ -2,6 +2,7 @@ import logging
|
||||||
|
|
||||||
import borgmatic.logger
|
import borgmatic.logger
|
||||||
|
|
||||||
|
VERBOSITY_DISABLED = -2
|
||||||
VERBOSITY_ERROR = -1
|
VERBOSITY_ERROR = -1
|
||||||
VERBOSITY_ANSWER = 0
|
VERBOSITY_ANSWER = 0
|
||||||
VERBOSITY_SOME = 1
|
VERBOSITY_SOME = 1
|
||||||
|
@ -15,6 +16,7 @@ def verbosity_to_log_level(verbosity):
|
||||||
borgmatic.logger.add_custom_log_levels()
|
borgmatic.logger.add_custom_log_levels()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
VERBOSITY_DISABLED: logging.DISABLED,
|
||||||
VERBOSITY_ERROR: logging.ERROR,
|
VERBOSITY_ERROR: logging.ERROR,
|
||||||
VERBOSITY_ANSWER: logging.ANSWER,
|
VERBOSITY_ANSWER: logging.ANSWER,
|
||||||
VERBOSITY_SOME: logging.INFO,
|
VERBOSITY_SOME: logging.INFO,
|
||||||
|
|
|
@ -61,4 +61,4 @@ LogRateLimitIntervalSec=0
|
||||||
# Delay start to prevent backups running during boot. Note that systemd-inhibit requires dbus and
|
# Delay start to prevent backups running during boot. Note that systemd-inhibit requires dbus and
|
||||||
# dbus-user-session to be installed.
|
# dbus-user-session to be installed.
|
||||||
ExecStartPre=sleep 1m
|
ExecStartPre=sleep 1m
|
||||||
ExecStart=systemd-inhibit --who="borgmatic" --what="sleep:shutdown" --why="Prevent interrupting scheduled backup" /root/.local/bin/borgmatic --verbosity -1 --syslog-verbosity 1
|
ExecStart=systemd-inhibit --who="borgmatic" --what="sleep:shutdown" --why="Prevent interrupting scheduled backup" /root/.local/bin/borgmatic --verbosity -2 --syslog-verbosity 1
|
||||||
|
|
|
@ -169,6 +169,19 @@ def test_run_configuration_bails_for_monitor_finish_soft_failure():
|
||||||
assert results == []
|
assert results == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_run_configuration_does_not_call_monitoring_hooks_if_monitoring_hooks_are_disabled():
|
||||||
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(module.DISABLED)
|
||||||
|
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
||||||
|
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').never()
|
||||||
|
flexmock(module).should_receive('run_actions').and_return([])
|
||||||
|
|
||||||
|
config = {'location': {'repositories': [{'path': 'foo'}]}}
|
||||||
|
arguments = {'global': flexmock(monitoring_verbosity=-2, dry_run=False), 'create': flexmock()}
|
||||||
|
results = list(module.run_configuration('test.yaml', config, arguments))
|
||||||
|
assert results == []
|
||||||
|
|
||||||
|
|
||||||
def test_run_configuration_logs_on_error_hook_error():
|
def test_run_configuration_logs_on_error_hook_error():
|
||||||
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
||||||
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
||||||
|
@ -229,8 +242,7 @@ def test_run_configuration_retries_hard_error():
|
||||||
).and_return([flexmock()])
|
).and_return([flexmock()])
|
||||||
error_logs = [flexmock()]
|
error_logs = [flexmock()]
|
||||||
flexmock(module).should_receive('log_error_records').with_args(
|
flexmock(module).should_receive('log_error_records').with_args(
|
||||||
'foo: Error running actions for repository',
|
'foo: Error running actions for repository', OSError,
|
||||||
OSError,
|
|
||||||
).and_return(error_logs)
|
).and_return(error_logs)
|
||||||
config = {'location': {'repositories': [{'path': 'foo'}]}, 'storage': {'retries': 1}}
|
config = {'location': {'repositories': [{'path': 'foo'}]}, 'storage': {'retries': 1}}
|
||||||
arguments = {'global': flexmock(monitoring_verbosity=1, dry_run=False), 'create': flexmock()}
|
arguments = {'global': flexmock(monitoring_verbosity=1, dry_run=False), 'create': flexmock()}
|
||||||
|
|
|
@ -285,6 +285,44 @@ 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_skips_syslog_if_syslog_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)
|
||||||
|
)
|
||||||
|
flexmock(module).should_receive('Console_color_formatter')
|
||||||
|
flexmock(module).should_receive('interactive_console').never()
|
||||||
|
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()
|
||||||
|
|
||||||
|
module.configure_logging(console_log_level=logging.INFO, syslog_log_level=logging.DISABLED)
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
)
|
||||||
|
|
||||||
|
# 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').never()
|
||||||
|
flexmock(module.logging.handlers).should_receive('SysLogHandler').never()
|
||||||
|
flexmock(module.logging.handlers).should_receive('WatchedFileHandler').never()
|
||||||
|
|
||||||
|
module.configure_logging(
|
||||||
|
console_log_level=logging.INFO, log_file_log_level=logging.DISABLED, log_file='/tmp/logfile'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_configure_logging_to_log_file_instead_of_syslog():
|
def test_configure_logging_to_log_file_instead_of_syslog():
|
||||||
flexmock(module).should_receive('add_custom_log_levels')
|
flexmock(module).should_receive('add_custom_log_levels')
|
||||||
flexmock(module.logging).ANSWER = module.ANSWER
|
flexmock(module.logging).ANSWER = module.ANSWER
|
||||||
|
@ -297,7 +335,7 @@ def test_configure_logging_to_log_file_instead_of_syslog():
|
||||||
flexmock(module.logging).should_receive('basicConfig').with_args(
|
flexmock(module.logging).should_receive('basicConfig').with_args(
|
||||||
level=logging.DEBUG, 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').never()
|
||||||
flexmock(module.logging.handlers).should_receive('SysLogHandler').never()
|
flexmock(module.logging.handlers).should_receive('SysLogHandler').never()
|
||||||
file_handler = logging.handlers.WatchedFileHandler('/tmp/logfile')
|
file_handler = logging.handlers.WatchedFileHandler('/tmp/logfile')
|
||||||
flexmock(module.logging.handlers).should_receive('WatchedFileHandler').with_args(
|
flexmock(module.logging.handlers).should_receive('WatchedFileHandler').with_args(
|
||||||
|
|
|
@ -17,11 +17,13 @@ def insert_logging_mock(log_level):
|
||||||
def test_verbosity_to_log_level_maps_known_verbosity_to_log_level():
|
def test_verbosity_to_log_level_maps_known_verbosity_to_log_level():
|
||||||
flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
|
flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
|
||||||
flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
|
flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
|
||||||
|
flexmock(module.logging).DISABLED = module.borgmatic.logger.DISABLED
|
||||||
|
|
||||||
assert module.verbosity_to_log_level(module.VERBOSITY_ERROR) == logging.ERROR
|
assert module.verbosity_to_log_level(module.VERBOSITY_ERROR) == logging.ERROR
|
||||||
assert module.verbosity_to_log_level(module.VERBOSITY_ANSWER) == module.borgmatic.logger.ANSWER
|
assert module.verbosity_to_log_level(module.VERBOSITY_ANSWER) == module.borgmatic.logger.ANSWER
|
||||||
assert module.verbosity_to_log_level(module.VERBOSITY_SOME) == logging.INFO
|
assert module.verbosity_to_log_level(module.VERBOSITY_SOME) == logging.INFO
|
||||||
assert module.verbosity_to_log_level(module.VERBOSITY_LOTS) == logging.DEBUG
|
assert module.verbosity_to_log_level(module.VERBOSITY_LOTS) == logging.DEBUG
|
||||||
|
assert module.verbosity_to_log_level(module.VERBOSITY_DISABLED) == logging.DISABLED
|
||||||
|
|
||||||
|
|
||||||
def test_verbosity_to_log_level_maps_unknown_verbosity_to_warning_level():
|
def test_verbosity_to_log_level_maps_unknown_verbosity_to_warning_level():
|
||||||
|
|
Loading…
Reference in a new issue