mirror of
https://github.com/borgmatic-collective/borgmatic.git
synced 2026-08-06 16:23:00 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74ac148747 | ||
|
|
be7887c071 | ||
|
|
da459d95b8 | ||
|
|
b3aa6af859 | ||
|
|
b816af1b13 | ||
|
|
276aeb9875 | ||
|
|
de94001508 | ||
|
|
7cfab3620b | ||
|
|
6c136ebbf1 | ||
|
|
eaa5eb4174 | ||
|
|
acc2a39454 | ||
|
|
a10c7a8496 |
@@ -0,0 +1,31 @@
|
|||||||
|
#### What I'm trying to do and why
|
||||||
|
|
||||||
|
#### Steps to reproduce (if a bug)
|
||||||
|
|
||||||
|
Include (sanitized) borgmatic configuration files if applicable.
|
||||||
|
|
||||||
|
#### Actual behavior (if a bug)
|
||||||
|
|
||||||
|
Include (sanitized) `--verbosity 2` output if applicable.
|
||||||
|
|
||||||
|
#### Expected behavior (if a bug)
|
||||||
|
|
||||||
|
#### Other notes / implementation ideas
|
||||||
|
|
||||||
|
#### Environment
|
||||||
|
|
||||||
|
**borgmatic version:** [version here]
|
||||||
|
|
||||||
|
Use `sudo borgmatic --version` or `sudo pip show borgmatic | grep ^Version`
|
||||||
|
|
||||||
|
**borgmatic installation method:** [e.g., Debian package, Docker container, etc.]
|
||||||
|
|
||||||
|
**Borg version:** [version here]
|
||||||
|
|
||||||
|
Use `sudo borg --version`
|
||||||
|
|
||||||
|
**Python version:** [version here]
|
||||||
|
|
||||||
|
Use `python --version`
|
||||||
|
|
||||||
|
**operating system and version:** [OS here]
|
||||||
@@ -1,3 +1,11 @@
|
|||||||
|
1.3.8
|
||||||
|
* #191: Disable console color via "color" option in borgmatic configuration output section.
|
||||||
|
|
||||||
|
1.3.7
|
||||||
|
* #196: Fix for unclear error message for invalid YAML merge include.
|
||||||
|
* #197: Don't color syslog output.
|
||||||
|
* Change default syslog verbosity to show errors only.
|
||||||
|
|
||||||
1.3.6
|
1.3.6
|
||||||
* #53: Log to syslog in addition to existing console logging. Add --syslog-verbosity flag to
|
* #53: Log to syslog in addition to existing console logging. Add --syslog-verbosity flag to
|
||||||
customize the log level. See the documentation for more information:
|
customize the log level. See the documentation for more information:
|
||||||
|
|||||||
@@ -2,13 +2,12 @@ import logging
|
|||||||
|
|
||||||
from borgmatic.borg import extract
|
from borgmatic.borg import extract
|
||||||
from borgmatic.execute import execute_command
|
from borgmatic.execute import execute_command
|
||||||
from borgmatic.logger import get_logger
|
|
||||||
|
|
||||||
DEFAULT_CHECKS = ('repository', 'archives')
|
DEFAULT_CHECKS = ('repository', 'archives')
|
||||||
DEFAULT_PREFIX = '{hostname}-'
|
DEFAULT_PREFIX = '{hostname}-'
|
||||||
|
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def _parse_checks(consistency_config):
|
def _parse_checks(consistency_config):
|
||||||
|
|||||||
@@ -5,9 +5,8 @@ import os
|
|||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
from borgmatic.execute import execute_command
|
from borgmatic.execute import execute_command
|
||||||
from borgmatic.logger import get_logger
|
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def _expand_directory(directory):
|
def _expand_directory(directory):
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from borgmatic.execute import execute_command
|
from borgmatic.execute import execute_command
|
||||||
from borgmatic.logger import get_logger
|
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def extract_last_archive_dry_run(repository, lock_wait=None, local_path='borg', remote_path=None):
|
def extract_last_archive_dry_run(repository, lock_wait=None, local_path='borg', remote_path=None):
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from borgmatic.execute import execute_command
|
from borgmatic.execute import execute_command
|
||||||
from borgmatic.logger import get_logger
|
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def display_archives_info(
|
def display_archives_info(
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import logging
|
|||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from borgmatic.execute import execute_command
|
from borgmatic.execute import execute_command
|
||||||
from borgmatic.logger import get_logger
|
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
INFO_REPOSITORY_NOT_FOUND_EXIT_CODE = 2
|
INFO_REPOSITORY_NOT_FOUND_EXIT_CODE = 2
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from borgmatic.execute import execute_command
|
from borgmatic.execute import execute_command
|
||||||
from borgmatic.logger import get_logger
|
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def list_archives(
|
def list_archives(
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from borgmatic.execute import execute_command
|
from borgmatic.execute import execute_command
|
||||||
from borgmatic.logger import get_logger
|
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def _make_prune_flags(retention_config):
|
def _make_prune_flags(retention_config):
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ from borgmatic.borg import init as borg_init
|
|||||||
from borgmatic.borg import list as borg_list
|
from borgmatic.borg import list as borg_list
|
||||||
from borgmatic.borg import prune as borg_prune
|
from borgmatic.borg import prune as borg_prune
|
||||||
from borgmatic.config import checks, collect, convert, validate
|
from borgmatic.config import checks, collect, convert, validate
|
||||||
from borgmatic.logger import configure_logging, get_logger, should_do_markup
|
from borgmatic.logger import configure_logging, should_do_markup
|
||||||
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
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
LEGACY_CONFIG_PATH = '/etc/borgmatic/config'
|
LEGACY_CONFIG_PATH = '/etc/borgmatic/config'
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ def parse_arguments(*arguments):
|
|||||||
'--syslog-verbosity',
|
'--syslog-verbosity',
|
||||||
type=int,
|
type=int,
|
||||||
choices=range(0, 3),
|
choices=range(0, 3),
|
||||||
default=1,
|
default=0,
|
||||||
help='Display verbose progress to syslog (from none to lots: 0, 1, or 2)',
|
help='Display verbose progress to syslog (from none to lots: 0, 1, or 2)',
|
||||||
)
|
)
|
||||||
common_group.add_argument(
|
common_group.add_argument(
|
||||||
@@ -404,37 +404,50 @@ def run_actions(
|
|||||||
yield json.loads(json_output)
|
yield json.loads(json_output)
|
||||||
|
|
||||||
|
|
||||||
def collect_configuration_run_summary_logs(config_filenames, args):
|
def load_configurations(config_filenames):
|
||||||
'''
|
'''
|
||||||
Given a sequence of configuration filenames and parsed command-line arguments as an
|
Given a sequence of configuration filenames, load and validate each configuration file. Return
|
||||||
argparse.ArgumentParser instance, run each configuration file and yield a series of
|
the results as a tuple of: dict of configuration filename to corresponding parsed configuration,
|
||||||
logging.LogRecord instances containing summary information about each run.
|
and sequence of logging.LogRecord instances containing any parse errors.
|
||||||
|
|
||||||
As a side effect of running through these configuration files, output their JSON results, if
|
|
||||||
any, to stdout.
|
|
||||||
'''
|
'''
|
||||||
# Dict mapping from config filename to corresponding parsed config dict.
|
# Dict mapping from config filename to corresponding parsed config dict.
|
||||||
configs = collections.OrderedDict()
|
configs = collections.OrderedDict()
|
||||||
|
logs = []
|
||||||
|
|
||||||
# Parse and load each configuration file.
|
# Parse and load each configuration file.
|
||||||
for config_filename in config_filenames:
|
for config_filename in config_filenames:
|
||||||
try:
|
try:
|
||||||
logger.info('{}: Parsing configuration file'.format(config_filename))
|
|
||||||
configs[config_filename] = validate.parse_configuration(
|
configs[config_filename] = validate.parse_configuration(
|
||||||
config_filename, validate.schema_filename()
|
config_filename, validate.schema_filename()
|
||||||
)
|
)
|
||||||
except (ValueError, OSError, validate.Validation_error) as error:
|
except (ValueError, OSError, validate.Validation_error) as error:
|
||||||
yield logging.makeLogRecord(
|
logs.extend(
|
||||||
dict(
|
[
|
||||||
levelno=logging.CRITICAL,
|
logging.makeLogRecord(
|
||||||
levelname='CRITICAL',
|
dict(
|
||||||
msg='{}: Error parsing configuration file'.format(config_filename),
|
levelno=logging.CRITICAL,
|
||||||
)
|
levelname='CRITICAL',
|
||||||
)
|
msg='{}: Error parsing configuration file'.format(config_filename),
|
||||||
yield logging.makeLogRecord(
|
)
|
||||||
dict(levelno=logging.CRITICAL, levelname='CRITICAL', msg=error)
|
),
|
||||||
|
logging.makeLogRecord(
|
||||||
|
dict(levelno=logging.CRITICAL, levelname='CRITICAL', msg=error)
|
||||||
|
),
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return (configs, logs)
|
||||||
|
|
||||||
|
|
||||||
|
def collect_configuration_run_summary_logs(configs, args):
|
||||||
|
'''
|
||||||
|
Given a dict of configuration filename to corresponding parsed configuration, and parsed
|
||||||
|
command-line arguments as an argparse.ArgumentParser instance, run each configuration file and
|
||||||
|
yield a series of logging.LogRecord instances containing summary information about each run.
|
||||||
|
|
||||||
|
As a side effect of running through these configuration files, output their JSON results, if
|
||||||
|
any, to stdout.
|
||||||
|
'''
|
||||||
# Run cross-file validation checks.
|
# Run cross-file validation checks.
|
||||||
if args.extract or (args.list and args.archive):
|
if args.extract or (args.list and args.archive):
|
||||||
try:
|
try:
|
||||||
@@ -472,7 +485,7 @@ def collect_configuration_run_summary_logs(config_filenames, args):
|
|||||||
if json_results:
|
if json_results:
|
||||||
sys.stdout.write(json.dumps(json_results))
|
sys.stdout.write(json.dumps(json_results))
|
||||||
|
|
||||||
if not config_filenames:
|
if not configs:
|
||||||
yield logging.makeLogRecord(
|
yield logging.makeLogRecord(
|
||||||
dict(
|
dict(
|
||||||
levelno=logging.CRITICAL,
|
levelno=logging.CRITICAL,
|
||||||
@@ -507,25 +520,30 @@ def main(): # pragma: no cover
|
|||||||
logger.critical('Error parsing arguments: {}'.format(' '.join(sys.argv)))
|
logger.critical('Error parsing arguments: {}'.format(' '.join(sys.argv)))
|
||||||
exit_with_help_link()
|
exit_with_help_link()
|
||||||
|
|
||||||
colorama.init(autoreset=True, strip=not should_do_markup(args.no_color))
|
|
||||||
|
|
||||||
configure_logging(
|
|
||||||
verbosity_to_log_level(args.verbosity), verbosity_to_log_level(args.syslog_verbosity)
|
|
||||||
)
|
|
||||||
|
|
||||||
if args.version:
|
if args.version:
|
||||||
print(pkg_resources.require('borgmatic')[0].version)
|
print(pkg_resources.require('borgmatic')[0].version)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
config_filenames = tuple(collect.collect_config_filenames(args.config_paths))
|
config_filenames = tuple(collect.collect_config_filenames(args.config_paths))
|
||||||
|
configs, parse_logs = load_configurations(config_filenames)
|
||||||
|
|
||||||
|
colorama.init(autoreset=True, strip=not should_do_markup(args.no_color, configs))
|
||||||
|
configure_logging(
|
||||||
|
verbosity_to_log_level(args.verbosity), verbosity_to_log_level(args.syslog_verbosity)
|
||||||
|
)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
summary_logs = tuple(collect_configuration_run_summary_logs(config_filenames, args))
|
summary_logs = list(collect_configuration_run_summary_logs(configs, args))
|
||||||
|
|
||||||
logger.info('')
|
logger.info('')
|
||||||
logger.info('summary:')
|
logger.info('summary:')
|
||||||
[logger.handle(log) for log in summary_logs if log.levelno >= logger.getEffectiveLevel()]
|
[
|
||||||
|
logger.handle(log)
|
||||||
|
for log in parse_logs + summary_logs
|
||||||
|
if log.levelno >= logger.getEffectiveLevel()
|
||||||
|
]
|
||||||
|
|
||||||
if any(log.levelno == logging.CRITICAL for log in summary_logs):
|
if any(log.levelno == logging.CRITICAL for log in summary_logs):
|
||||||
exit_with_help_link()
|
exit_with_help_link()
|
||||||
|
|||||||
@@ -3,9 +3,8 @@ import sys
|
|||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
|
|
||||||
from borgmatic.config import collect, validate
|
from borgmatic.config import collect, validate
|
||||||
from borgmatic.logger import get_logger
|
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def parse_arguments(*arguments):
|
def parse_arguments(*arguments):
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import ruamel.yaml
|
import ruamel.yaml
|
||||||
|
|
||||||
from borgmatic.logger import get_logger
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def load_configuration(filename):
|
def load_configuration(filename):
|
||||||
@@ -54,9 +53,7 @@ class Include_constructor(ruamel.yaml.SafeConstructor):
|
|||||||
|
|
||||||
for index, (key_node, value_node) in enumerate(node.value):
|
for index, (key_node, value_node) in enumerate(node.value):
|
||||||
if key_node.tag == u'tag:yaml.org,2002:merge' and value_node.tag == '!include':
|
if key_node.tag == u'tag:yaml.org,2002:merge' and value_node.tag == '!include':
|
||||||
included_value = representer.represent_mapping(
|
included_value = representer.represent_data(self.construct_object(value_node))
|
||||||
tag='tag:yaml.org,2002:map', mapping=self.construct_object(value_node)
|
|
||||||
)
|
|
||||||
node.value[index] = (key_node, included_value)
|
node.value[index] = (key_node, included_value)
|
||||||
|
|
||||||
super(Include_constructor, self).flatten_mapping(node)
|
super(Include_constructor, self).flatten_mapping(node)
|
||||||
|
|||||||
@@ -301,6 +301,16 @@ map:
|
|||||||
this prefix. Borg placeholders can be used. See the output of
|
this prefix. Borg placeholders can be used. See the output of
|
||||||
"borg help placeholders" for details. Defaults to "{hostname}-".
|
"borg help placeholders" for details. Defaults to "{hostname}-".
|
||||||
example: sourcehostname
|
example: sourcehostname
|
||||||
|
output:
|
||||||
|
desc: |
|
||||||
|
Options for customizing borgmatic's own output and logging.
|
||||||
|
map:
|
||||||
|
color:
|
||||||
|
type: bool
|
||||||
|
desc: |
|
||||||
|
Apply color to console output. Can be overridden with --no-color command-line
|
||||||
|
flag. Defaults to true.
|
||||||
|
example: false
|
||||||
hooks:
|
hooks:
|
||||||
desc: |
|
desc: |
|
||||||
Shell commands or scripts to execute before and after a backup or if an error has occurred.
|
Shell commands or scripts to execute before and after a backup or if an error has occurred.
|
||||||
|
|||||||
@@ -6,9 +6,6 @@ import pykwalify.errors
|
|||||||
import ruamel.yaml
|
import ruamel.yaml
|
||||||
|
|
||||||
from borgmatic.config import load
|
from borgmatic.config import load
|
||||||
from borgmatic.logger import get_logger
|
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def schema_filename():
|
def schema_filename():
|
||||||
@@ -66,13 +63,6 @@ def apply_logical_validation(config_filename, parsed_configuration):
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
consistency_prefix = parsed_configuration.get('consistency', {}).get('prefix')
|
|
||||||
if archive_name_format and not consistency_prefix:
|
|
||||||
logger.warning(
|
|
||||||
'Since version 1.1.16, if you provide `archive_name_format`, you should also'
|
|
||||||
' specify `consistency.prefix`.'
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_configuration(config_filename, schema_filename):
|
def parse_configuration(config_filename, schema_filename):
|
||||||
'''
|
'''
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import logging
|
import logging
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from borgmatic.logger import get_logger
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def execute_and_log_output(full_command, output_log_level, shell):
|
def execute_and_log_output(full_command, output_log_level, shell):
|
||||||
|
|||||||
+1
-2
@@ -2,9 +2,8 @@ import logging
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from borgmatic import execute
|
from borgmatic import execute
|
||||||
from borgmatic.logger import get_logger
|
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def execute_hook(commands, umask, config_filename, description, dry_run):
|
def execute_hook(commands, umask, config_filename, description, dry_run):
|
||||||
|
|||||||
+10
-48
@@ -21,13 +21,17 @@ def to_bool(arg):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def should_do_markup(no_color):
|
def should_do_markup(no_color, configs):
|
||||||
'''
|
'''
|
||||||
Determine if we should enable colorama marking up.
|
Given the value of the command-line no-color argument, and a dict of configuration filename to
|
||||||
|
corresponding parsed configuration, determine if we should enable colorama marking up.
|
||||||
'''
|
'''
|
||||||
if no_color:
|
if no_color:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
if any(config.get('output', {}).get('color') is False for config in configs.values()):
|
||||||
|
return False
|
||||||
|
|
||||||
py_colors = os.environ.get('PY_COLORS', None)
|
py_colors = os.environ.get('PY_COLORS', None)
|
||||||
|
|
||||||
if py_colors is not None:
|
if py_colors is not None:
|
||||||
@@ -45,52 +49,10 @@ LOG_LEVEL_TO_COLOR = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Borgmatic_logger(logging.Logger):
|
class Console_color_formatter(logging.Formatter):
|
||||||
def critical(self, msg, *args, **kwargs):
|
def format(self, record):
|
||||||
color = LOG_LEVEL_TO_COLOR.get(logging.CRITICAL)
|
|
||||||
|
|
||||||
return super(Borgmatic_logger, self).critical(color_text(color, msg), *args, **kwargs)
|
|
||||||
|
|
||||||
def error(self, msg, *args, **kwargs):
|
|
||||||
color = LOG_LEVEL_TO_COLOR.get(logging.ERROR)
|
|
||||||
|
|
||||||
return super(Borgmatic_logger, self).error(color_text(color, msg), *args, **kwargs)
|
|
||||||
|
|
||||||
def warn(self, msg, *args, **kwargs):
|
|
||||||
color = LOG_LEVEL_TO_COLOR.get(logging.WARN)
|
|
||||||
|
|
||||||
return super(Borgmatic_logger, self).warn(color_text(color, msg), *args, **kwargs)
|
|
||||||
|
|
||||||
def info(self, msg, *args, **kwargs):
|
|
||||||
color = LOG_LEVEL_TO_COLOR.get(logging.INFO)
|
|
||||||
|
|
||||||
return super(Borgmatic_logger, self).info(color_text(color, msg), *args, **kwargs)
|
|
||||||
|
|
||||||
def debug(self, msg, *args, **kwargs):
|
|
||||||
color = LOG_LEVEL_TO_COLOR.get(logging.DEBUG)
|
|
||||||
|
|
||||||
return super(Borgmatic_logger, self).debug(color_text(color, msg), *args, **kwargs)
|
|
||||||
|
|
||||||
def handle(self, record):
|
|
||||||
color = LOG_LEVEL_TO_COLOR.get(record.levelno)
|
color = LOG_LEVEL_TO_COLOR.get(record.levelno)
|
||||||
colored_record = logging.makeLogRecord(
|
return color_text(color, record.msg)
|
||||||
dict(
|
|
||||||
levelno=record.levelno,
|
|
||||||
levelname=record.levelname,
|
|
||||||
msg=color_text(color, record.msg),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
return super(Borgmatic_logger, self).handle(colored_record)
|
|
||||||
|
|
||||||
|
|
||||||
def get_logger(name=None):
|
|
||||||
'''
|
|
||||||
Build a logger with the given name.
|
|
||||||
'''
|
|
||||||
logging.setLoggerClass(Borgmatic_logger)
|
|
||||||
logger = logging.getLogger(name)
|
|
||||||
return logger
|
|
||||||
|
|
||||||
|
|
||||||
def color_text(color, message):
|
def color_text(color, message):
|
||||||
@@ -111,7 +73,7 @@ def configure_logging(console_log_level, syslog_log_level=None):
|
|||||||
syslog_log_level = console_log_level
|
syslog_log_level = console_log_level
|
||||||
|
|
||||||
console_handler = logging.StreamHandler()
|
console_handler = logging.StreamHandler()
|
||||||
console_handler.setFormatter(logging.Formatter('%(message)s'))
|
console_handler.setFormatter(Console_color_formatter())
|
||||||
console_handler.setLevel(console_log_level)
|
console_handler.setLevel(console_log_level)
|
||||||
|
|
||||||
syslog_path = None
|
syslog_path = None
|
||||||
|
|||||||
@@ -42,11 +42,11 @@ using systemd, try running `journalctl -xe`. Otherwise, try viewing
|
|||||||
|
|
||||||
You can customize the log level used for syslog logging with the
|
You can customize the log level used for syslog logging with the
|
||||||
`--syslog-verbosity` flag, and this is independent from the console logging
|
`--syslog-verbosity` flag, and this is independent from the console logging
|
||||||
`--verbosity` flag described above. For instance, to disable syslog logging
|
`--verbosity` flag described above. For instance, to get additional
|
||||||
except for errors:
|
information about the progress of the backup as it proceeds:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
borgmatic --syslog-verbosity 0
|
borgmatic --syslog-verbosity 1
|
||||||
```
|
```
|
||||||
|
|
||||||
Or to increase syslog logging to include debug spew:
|
Or to increase syslog logging to include debug spew:
|
||||||
|
|||||||
@@ -105,6 +105,10 @@ include, the local file's option takes precedent. And note that this is a
|
|||||||
shallow merge rather than a deep merge, so the merging does not descend into
|
shallow merge rather than a deep merge, so the merging does not descend into
|
||||||
nested values.
|
nested values.
|
||||||
|
|
||||||
|
Note that this `<<` include merging syntax is only for merging in mappings
|
||||||
|
(keys/values). If you'd like to include other types like scalars or lists
|
||||||
|
directly, please see the section above about standard includes.
|
||||||
|
|
||||||
|
|
||||||
## Related documentation
|
## Related documentation
|
||||||
|
|
||||||
|
|||||||
@@ -199,12 +199,13 @@ sudo systemctl start borgmatic.timer
|
|||||||
Feel free to modify the timer file based on how frequently you'd like
|
Feel free to modify the timer file based on how frequently you'd like
|
||||||
borgmatic to run.
|
borgmatic to run.
|
||||||
|
|
||||||
## Colored Output
|
## Colored output
|
||||||
|
|
||||||
Borgmatic uses [colorama](https://pypi.org/project/colorama/) to produce
|
Borgmatic produces colored terminal output by default. It is disabled when a
|
||||||
colored terminal output by default. It is disabled when a non-interactive
|
non-interactive terminal is detected (like a cron job). Otherwise, you can
|
||||||
terminal is detected (like a cron job). Otherwise, it can be disabled by
|
disable it by passing the `--no-color` flag, setting the environment variable
|
||||||
passing `--no-color` or by setting the environment variable `PY_COLORS=False`.
|
`PY_COLORS=False`, or setting the `color` option to `false` in the `output`
|
||||||
|
section of configuration.
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from setuptools import find_packages, setup
|
from setuptools import find_packages, setup
|
||||||
|
|
||||||
VERSION = '1.3.6'
|
VERSION = '1.3.8'
|
||||||
|
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ def test_parse_arguments_with_no_arguments_uses_defaults():
|
|||||||
assert parser.config_paths == config_paths
|
assert parser.config_paths == config_paths
|
||||||
assert parser.excludes_filename is None
|
assert parser.excludes_filename is None
|
||||||
assert parser.verbosity == 0
|
assert parser.verbosity == 0
|
||||||
assert parser.syslog_verbosity == 1
|
assert parser.syslog_verbosity == 0
|
||||||
assert parser.json is False
|
assert parser.json is False
|
||||||
|
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ def test_parse_arguments_with_multiple_config_paths_parses_as_list():
|
|||||||
|
|
||||||
assert parser.config_paths == ['myconfig', 'otherconfig']
|
assert parser.config_paths == ['myconfig', 'otherconfig']
|
||||||
assert parser.verbosity == 0
|
assert parser.verbosity == 0
|
||||||
assert parser.syslog_verbosity == 1
|
assert parser.syslog_verbosity == 0
|
||||||
|
|
||||||
|
|
||||||
def test_parse_arguments_with_verbosity_overrides_default():
|
def test_parse_arguments_with_verbosity_overrides_default():
|
||||||
@@ -38,7 +38,7 @@ def test_parse_arguments_with_verbosity_overrides_default():
|
|||||||
assert parser.config_paths == config_paths
|
assert parser.config_paths == config_paths
|
||||||
assert parser.excludes_filename is None
|
assert parser.excludes_filename is None
|
||||||
assert parser.verbosity == 1
|
assert parser.verbosity == 1
|
||||||
assert parser.syslog_verbosity == 1
|
assert parser.syslog_verbosity == 0
|
||||||
|
|
||||||
|
|
||||||
def test_parse_arguments_with_syslog_verbosity_overrides_default():
|
def test_parse_arguments_with_syslog_verbosity_overrides_default():
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import ruamel.yaml
|
||||||
from flexmock import flexmock
|
from flexmock import flexmock
|
||||||
|
|
||||||
from borgmatic.config import load as module
|
from borgmatic.config import load as module
|
||||||
@@ -38,3 +40,23 @@ def test_load_configuration_merges_include():
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert module.load_configuration('config.yaml') == {'foo': 'override', 'baz': 'quux'}
|
assert module.load_configuration('config.yaml') == {'foo': 'override', 'baz': 'quux'}
|
||||||
|
|
||||||
|
|
||||||
|
def test_load_configuration_does_not_merge_include_list():
|
||||||
|
builtins = flexmock(sys.modules['builtins'])
|
||||||
|
builtins.should_receive('open').with_args('include.yaml').and_return(
|
||||||
|
'''
|
||||||
|
- one
|
||||||
|
- two
|
||||||
|
'''
|
||||||
|
)
|
||||||
|
builtins.should_receive('open').with_args('config.yaml').and_return(
|
||||||
|
'''
|
||||||
|
foo: bar
|
||||||
|
repositories:
|
||||||
|
<<: !include include.yaml
|
||||||
|
'''
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(ruamel.yaml.error.YAMLError):
|
||||||
|
assert module.load_configuration('config.yaml')
|
||||||
|
|||||||
@@ -3,99 +3,106 @@ from flexmock import flexmock
|
|||||||
from borgmatic.commands import borgmatic as module
|
from borgmatic.commands import borgmatic as module
|
||||||
|
|
||||||
|
|
||||||
|
def test_load_configurations_collects_parsed_configurations():
|
||||||
|
configuration = flexmock()
|
||||||
|
other_configuration = flexmock()
|
||||||
|
flexmock(module.validate).should_receive('parse_configuration').and_return(
|
||||||
|
configuration
|
||||||
|
).and_return(other_configuration)
|
||||||
|
|
||||||
|
configs, logs = tuple(module.load_configurations(('test.yaml', 'other.yaml')))
|
||||||
|
|
||||||
|
assert configs == {'test.yaml': configuration, 'other.yaml': other_configuration}
|
||||||
|
assert logs == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_load_configurations_logs_critical_for_parse_error():
|
||||||
|
flexmock(module.validate).should_receive('parse_configuration').and_raise(ValueError)
|
||||||
|
|
||||||
|
configs, logs = tuple(module.load_configurations(('test.yaml',)))
|
||||||
|
|
||||||
|
assert configs == {}
|
||||||
|
assert any(log for log in logs if log.levelno == module.logging.CRITICAL)
|
||||||
|
|
||||||
|
|
||||||
def test_collect_configuration_run_summary_logs_info_for_success():
|
def test_collect_configuration_run_summary_logs_info_for_success():
|
||||||
flexmock(module.validate).should_receive('parse_configuration').and_return({'test.yaml': {}})
|
|
||||||
flexmock(module).should_receive('run_configuration').and_return([])
|
flexmock(module).should_receive('run_configuration').and_return([])
|
||||||
args = flexmock(extract=False, list=False)
|
args = flexmock(extract=False, list=False)
|
||||||
|
|
||||||
logs = tuple(module.collect_configuration_run_summary_logs(('test.yaml',), args=args))
|
logs = tuple(module.collect_configuration_run_summary_logs({'test.yaml': {}}, args=args))
|
||||||
|
|
||||||
assert all(log for log in logs if log.levelno == module.logging.INFO)
|
assert all(log for log in logs if log.levelno == module.logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
def test_collect_configuration_run_summary_logs_info_for_success_with_extract():
|
def test_collect_configuration_run_summary_logs_info_for_success_with_extract():
|
||||||
flexmock(module.validate).should_receive('parse_configuration').and_return({'test.yaml': {}})
|
|
||||||
flexmock(module.validate).should_receive('guard_configuration_contains_repository')
|
flexmock(module.validate).should_receive('guard_configuration_contains_repository')
|
||||||
flexmock(module).should_receive('run_configuration').and_return([])
|
flexmock(module).should_receive('run_configuration').and_return([])
|
||||||
args = flexmock(extract=True, list=False, repository='repo')
|
args = flexmock(extract=True, list=False, repository='repo')
|
||||||
|
|
||||||
logs = tuple(module.collect_configuration_run_summary_logs(('test.yaml',), args=args))
|
logs = tuple(module.collect_configuration_run_summary_logs({'test.yaml': {}}, args=args))
|
||||||
|
|
||||||
assert all(log for log in logs if log.levelno == module.logging.INFO)
|
assert all(log for log in logs if log.levelno == module.logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
def test_collect_configuration_run_summary_logs_critical_for_extract_with_repository_error():
|
def test_collect_configuration_run_summary_logs_critical_for_extract_with_repository_error():
|
||||||
flexmock(module.validate).should_receive('parse_configuration').and_return({'test.yaml': {}})
|
|
||||||
flexmock(module.validate).should_receive('guard_configuration_contains_repository').and_raise(
|
flexmock(module.validate).should_receive('guard_configuration_contains_repository').and_raise(
|
||||||
ValueError
|
ValueError
|
||||||
)
|
)
|
||||||
args = flexmock(extract=True, list=False, repository='repo')
|
args = flexmock(extract=True, list=False, repository='repo')
|
||||||
|
|
||||||
logs = tuple(module.collect_configuration_run_summary_logs(('test.yaml',), args=args))
|
logs = tuple(module.collect_configuration_run_summary_logs({'test.yaml': {}}, args=args))
|
||||||
|
|
||||||
assert any(log for log in logs if log.levelno == module.logging.CRITICAL)
|
assert any(log for log in logs if log.levelno == module.logging.CRITICAL)
|
||||||
|
|
||||||
|
|
||||||
def test_collect_configuration_run_summary_logs_critical_for_list_with_archive_and_repository_error():
|
def test_collect_configuration_run_summary_logs_critical_for_list_with_archive_and_repository_error():
|
||||||
flexmock(module.validate).should_receive('parse_configuration').and_return({'test.yaml': {}})
|
|
||||||
flexmock(module.validate).should_receive('guard_configuration_contains_repository').and_raise(
|
flexmock(module.validate).should_receive('guard_configuration_contains_repository').and_raise(
|
||||||
ValueError
|
ValueError
|
||||||
)
|
)
|
||||||
args = flexmock(extract=False, list=True, repository='repo', archive='test')
|
args = flexmock(extract=False, list=True, repository='repo', archive='test')
|
||||||
|
|
||||||
logs = tuple(module.collect_configuration_run_summary_logs(('test.yaml',), args=args))
|
logs = tuple(module.collect_configuration_run_summary_logs({'test.yaml': {}}, args=args))
|
||||||
|
|
||||||
assert any(log for log in logs if log.levelno == module.logging.CRITICAL)
|
assert any(log for log in logs if log.levelno == module.logging.CRITICAL)
|
||||||
|
|
||||||
|
|
||||||
def test_collect_configuration_run_summary_logs_info_for_success_with_list():
|
def test_collect_configuration_run_summary_logs_info_for_success_with_list():
|
||||||
flexmock(module.validate).should_receive('parse_configuration').and_return({'test.yaml': {}})
|
|
||||||
flexmock(module).should_receive('run_configuration').and_return([])
|
flexmock(module).should_receive('run_configuration').and_return([])
|
||||||
args = flexmock(extract=False, list=True, repository='repo', archive=None)
|
args = flexmock(extract=False, list=True, repository='repo', archive=None)
|
||||||
|
|
||||||
logs = tuple(module.collect_configuration_run_summary_logs(('test.yaml',), args=args))
|
logs = tuple(module.collect_configuration_run_summary_logs({'test.yaml': {}}, args=args))
|
||||||
|
|
||||||
assert all(log for log in logs if log.levelno == module.logging.INFO)
|
assert all(log for log in logs if log.levelno == module.logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
def test_collect_configuration_run_summary_logs_critical_for_parse_error():
|
|
||||||
flexmock(module.validate).should_receive('parse_configuration').and_raise(ValueError)
|
|
||||||
args = flexmock(extract=False, list=False)
|
|
||||||
|
|
||||||
logs = tuple(module.collect_configuration_run_summary_logs(('test.yaml',), args=args))
|
|
||||||
|
|
||||||
assert any(log for log in logs if log.levelno == module.logging.CRITICAL)
|
|
||||||
|
|
||||||
|
|
||||||
def test_collect_configuration_run_summary_logs_critical_for_run_error():
|
def test_collect_configuration_run_summary_logs_critical_for_run_error():
|
||||||
flexmock(module.validate).should_receive('parse_configuration').and_return({'test.yaml': {}})
|
|
||||||
flexmock(module.validate).should_receive('guard_configuration_contains_repository')
|
flexmock(module.validate).should_receive('guard_configuration_contains_repository')
|
||||||
flexmock(module).should_receive('run_configuration').and_raise(ValueError)
|
flexmock(module).should_receive('run_configuration').and_raise(ValueError)
|
||||||
args = flexmock(extract=False, list=False)
|
args = flexmock(extract=False, list=False)
|
||||||
|
|
||||||
logs = tuple(module.collect_configuration_run_summary_logs(('test.yaml',), args=args))
|
logs = tuple(module.collect_configuration_run_summary_logs({'test.yaml': {}}, args=args))
|
||||||
|
|
||||||
assert any(log for log in logs if log.levelno == module.logging.CRITICAL)
|
|
||||||
|
|
||||||
|
|
||||||
def test_collect_configuration_run_summary_logs_critical_for_missing_configs():
|
|
||||||
flexmock(module.validate).should_receive('parse_configuration').and_return({'test.yaml': {}})
|
|
||||||
flexmock(module).should_receive('run_configuration').and_return([])
|
|
||||||
args = flexmock(config_paths=(), extract=False, list=False)
|
|
||||||
|
|
||||||
logs = tuple(module.collect_configuration_run_summary_logs(config_filenames=(), args=args))
|
|
||||||
|
|
||||||
assert any(log for log in logs if log.levelno == module.logging.CRITICAL)
|
assert any(log for log in logs if log.levelno == module.logging.CRITICAL)
|
||||||
|
|
||||||
|
|
||||||
def test_collect_configuration_run_summary_logs_outputs_merged_json_results():
|
def test_collect_configuration_run_summary_logs_outputs_merged_json_results():
|
||||||
flexmock(module.validate).should_receive('parse_configuration').and_return(
|
|
||||||
{'test.yaml': {}, 'test2.yaml': {}}
|
|
||||||
)
|
|
||||||
flexmock(module).should_receive('run_configuration').and_return(['foo', 'bar']).and_return(
|
flexmock(module).should_receive('run_configuration').and_return(['foo', 'bar']).and_return(
|
||||||
['baz']
|
['baz']
|
||||||
)
|
)
|
||||||
flexmock(module.sys.stdout).should_receive('write').with_args('["foo", "bar", "baz"]').once()
|
flexmock(module.sys.stdout).should_receive('write').with_args('["foo", "bar", "baz"]').once()
|
||||||
args = flexmock(extract=False, list=False)
|
args = flexmock(extract=False, list=False)
|
||||||
|
|
||||||
tuple(module.collect_configuration_run_summary_logs(('test.yaml', 'test2.yaml'), args=args))
|
tuple(
|
||||||
|
module.collect_configuration_run_summary_logs(
|
||||||
|
{'test.yaml': {}, 'test2.yaml': {}}, args=args
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_collect_configuration_run_summary_logs_critical_for_missing_configs():
|
||||||
|
flexmock(module).should_receive('run_configuration').and_return([])
|
||||||
|
args = flexmock(extract=False, list=False, config_paths=[])
|
||||||
|
|
||||||
|
logs = tuple(module.collect_configuration_run_summary_logs({}, args=args))
|
||||||
|
|
||||||
|
assert any(log for log in logs if log.levelno == module.logging.CRITICAL)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from flexmock import flexmock
|
|
||||||
|
|
||||||
from borgmatic.config import validate as module
|
from borgmatic.config import validate as module
|
||||||
|
|
||||||
@@ -37,20 +36,6 @@ def test_apply_logical_validation_raises_if_archive_name_format_present_without_
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_apply_logical_validation_warns_if_archive_name_format_present_without_consistency_prefix():
|
|
||||||
logger = flexmock(module.logger)
|
|
||||||
logger.should_receive('warning').once()
|
|
||||||
|
|
||||||
module.apply_logical_validation(
|
|
||||||
'config.yaml',
|
|
||||||
{
|
|
||||||
'storage': {'archive_name_format': '{hostname}-{now}'},
|
|
||||||
'retention': {'prefix': '{hostname}-'},
|
|
||||||
'consistency': {},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_apply_locical_validation_raises_if_unknown_repository_in_check_repositories():
|
def test_apply_locical_validation_raises_if_unknown_repository_in_check_repositories():
|
||||||
with pytest.raises(module.Validation_error):
|
with pytest.raises(module.Validation_error):
|
||||||
module.apply_logical_validation(
|
module.apply_logical_validation(
|
||||||
@@ -74,10 +59,7 @@ def test_apply_locical_validation_does_not_raise_if_known_repository_in_check_re
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_apply_logical_validation_does_not_raise_or_warn_if_archive_name_format_and_prefix_present():
|
def test_apply_logical_validation_does_not_raise_if_archive_name_format_and_prefix_present():
|
||||||
logger = flexmock(module.logger)
|
|
||||||
logger.should_receive('warning').never()
|
|
||||||
|
|
||||||
module.apply_logical_validation(
|
module.apply_logical_validation(
|
||||||
'config.yaml',
|
'config.yaml',
|
||||||
{
|
{
|
||||||
|
|||||||
+52
-18
@@ -21,51 +21,81 @@ def test_to_bool_passes_none_through():
|
|||||||
|
|
||||||
|
|
||||||
def test_should_do_markup_respects_no_color_value():
|
def test_should_do_markup_respects_no_color_value():
|
||||||
assert module.should_do_markup(no_color=True) is False
|
assert module.should_do_markup(no_color=True, configs={}) is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_do_markup_respects_config_value():
|
||||||
|
assert (
|
||||||
|
module.should_do_markup(no_color=False, configs={'foo.yaml': {'output': {'color': False}}})
|
||||||
|
is False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_do_markup_prefers_any_false_config_value():
|
||||||
|
assert (
|
||||||
|
module.should_do_markup(
|
||||||
|
no_color=False,
|
||||||
|
configs={
|
||||||
|
'foo.yaml': {'output': {'color': True}},
|
||||||
|
'bar.yaml': {'output': {'color': False}},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
is False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_should_do_markup_respects_PY_COLORS_environment_variable():
|
def test_should_do_markup_respects_PY_COLORS_environment_variable():
|
||||||
flexmock(module.os.environ).should_receive('get').and_return('True')
|
flexmock(module.os.environ).should_receive('get').and_return('True')
|
||||||
flexmock(module).should_receive('to_bool').and_return(True)
|
flexmock(module).should_receive('to_bool').and_return(True)
|
||||||
|
|
||||||
assert module.should_do_markup(no_color=False) is True
|
assert module.should_do_markup(no_color=False, configs={}) is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_do_markup_prefers_no_color_value_to_config_value():
|
||||||
|
assert (
|
||||||
|
module.should_do_markup(no_color=True, configs={'foo.yaml': {'output': {'color': True}}})
|
||||||
|
is False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_do_markup_prefers_config_value_to_PY_COLORS():
|
||||||
|
flexmock(module.os.environ).should_receive('get').and_return('True')
|
||||||
|
flexmock(module).should_receive('to_bool').and_return(True)
|
||||||
|
|
||||||
|
assert (
|
||||||
|
module.should_do_markup(no_color=False, configs={'foo.yaml': {'output': {'color': False}}})
|
||||||
|
is False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_should_do_markup_prefers_no_color_value_to_PY_COLORS():
|
def test_should_do_markup_prefers_no_color_value_to_PY_COLORS():
|
||||||
flexmock(module.os.environ).should_receive('get').and_return('True')
|
flexmock(module.os.environ).should_receive('get').and_return('True')
|
||||||
flexmock(module).should_receive('to_bool').and_return(True)
|
flexmock(module).should_receive('to_bool').and_return(True)
|
||||||
|
|
||||||
assert module.should_do_markup(no_color=True) is False
|
assert module.should_do_markup(no_color=True, configs={}) is False
|
||||||
|
|
||||||
|
|
||||||
def test_should_do_markup_respects_stdout_tty_value():
|
def test_should_do_markup_respects_stdout_tty_value():
|
||||||
flexmock(module.os.environ).should_receive('get').and_return(None)
|
flexmock(module.os.environ).should_receive('get').and_return(None)
|
||||||
|
|
||||||
assert module.should_do_markup(no_color=False) is False
|
assert module.should_do_markup(no_color=False, configs={}) is False
|
||||||
|
|
||||||
|
|
||||||
def test_should_do_markup_prefers_PY_COLORS_to_stdout_tty_value():
|
def test_should_do_markup_prefers_PY_COLORS_to_stdout_tty_value():
|
||||||
flexmock(module.os.environ).should_receive('get').and_return('True')
|
flexmock(module.os.environ).should_receive('get').and_return('True')
|
||||||
flexmock(module).should_receive('to_bool').and_return(True)
|
flexmock(module).should_receive('to_bool').and_return(True)
|
||||||
|
|
||||||
assert module.should_do_markup(no_color=False) is True
|
assert module.should_do_markup(no_color=False, configs={}) is True
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('method_name', ('critical', 'error', 'warn', 'info', 'debug'))
|
def test_console_color_formatter_format_includes_log_message():
|
||||||
def test_borgmatic_logger_log_method_does_not_raise(method_name):
|
plain_message = 'uh oh'
|
||||||
flexmock(module).should_receive('color_text')
|
record = flexmock(levelno=logging.CRITICAL, msg=plain_message)
|
||||||
flexmock(module.logging.Logger).should_receive(method_name)
|
|
||||||
|
|
||||||
getattr(module.Borgmatic_logger('test'), method_name)(msg='hi')
|
colored_message = module.Console_color_formatter().format(record)
|
||||||
|
|
||||||
|
assert colored_message != plain_message
|
||||||
def test_borgmatic_logger_handle_does_not_raise():
|
assert plain_message in colored_message
|
||||||
flexmock(module).should_receive('color_text')
|
|
||||||
flexmock(module.logging.Logger).should_receive('handle')
|
|
||||||
|
|
||||||
module.Borgmatic_logger('test').handle(
|
|
||||||
module.logging.makeLogRecord(dict(levelno=module.logging.CRITICAL, msg='hi'))
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_color_text_does_not_raise():
|
def test_color_text_does_not_raise():
|
||||||
@@ -77,6 +107,7 @@ def test_color_text_without_color_does_not_raise():
|
|||||||
|
|
||||||
|
|
||||||
def test_configure_logging_probes_for_log_socket_on_linux():
|
def test_configure_logging_probes_for_log_socket_on_linux():
|
||||||
|
flexmock(module).should_receive('Console_color_formatter')
|
||||||
flexmock(module.logging).should_receive('basicConfig').with_args(
|
flexmock(module.logging).should_receive('basicConfig').with_args(
|
||||||
level=logging.INFO, handlers=tuple
|
level=logging.INFO, handlers=tuple
|
||||||
)
|
)
|
||||||
@@ -91,6 +122,7 @@ def test_configure_logging_probes_for_log_socket_on_linux():
|
|||||||
|
|
||||||
|
|
||||||
def test_configure_logging_probes_for_log_socket_on_macos():
|
def test_configure_logging_probes_for_log_socket_on_macos():
|
||||||
|
flexmock(module).should_receive('Console_color_formatter')
|
||||||
flexmock(module.logging).should_receive('basicConfig').with_args(
|
flexmock(module.logging).should_receive('basicConfig').with_args(
|
||||||
level=logging.INFO, handlers=tuple
|
level=logging.INFO, handlers=tuple
|
||||||
)
|
)
|
||||||
@@ -105,6 +137,7 @@ def test_configure_logging_probes_for_log_socket_on_macos():
|
|||||||
|
|
||||||
|
|
||||||
def test_configure_logging_sets_global_logger_to_most_verbose_log_level():
|
def test_configure_logging_sets_global_logger_to_most_verbose_log_level():
|
||||||
|
flexmock(module).should_receive('Console_color_formatter')
|
||||||
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
|
||||||
).once()
|
).once()
|
||||||
@@ -114,6 +147,7 @@ def test_configure_logging_sets_global_logger_to_most_verbose_log_level():
|
|||||||
|
|
||||||
|
|
||||||
def test_configure_logging_skips_syslog_if_not_found():
|
def test_configure_logging_skips_syslog_if_not_found():
|
||||||
|
flexmock(module).should_receive('Console_color_formatter')
|
||||||
flexmock(module.logging).should_receive('basicConfig').with_args(
|
flexmock(module.logging).should_receive('basicConfig').with_args(
|
||||||
level=logging.INFO, handlers=tuple
|
level=logging.INFO, handlers=tuple
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user