diff --git a/simple_backup/simple_backup.py b/simple_backup/simple_backup.py index 2859ae3..246a39c 100755 --- a/simple_backup/simple_backup.py +++ b/simple_backup/simple_backup.py @@ -789,20 +789,17 @@ class Backup: returncode = p.wait() if returncode == 0: - if self._verbose: - logger.info('rsync: %s', output) - else: - # May be fewer than two lines, e.g. with --rsync-options q - for r in output: - logger.info('rsync: %s', r) + # Without -v, only the summary, which may be fewer than two lines (e.g. with --rsync-options q) + for r in output: + logger.info('rsync: %s', r) else: self._returncode_log(returncode) if self._verbose: - if returncode in [23, 24]: - logger.warning(output) - else: - logger.error(output) + level = logging.WARNING if returncode in [23, 24] else logging.ERROR + + for r in output: + logger.log(level, 'rsync: %s', r) if self._removed_count > 0 and returncode not in [0, 24]: # With --remove-before-backup, old backups are already gone if the new one failed diff --git a/tests/test_local.py b/tests/test_local.py index 972f408..c7eda01 100644 --- a/tests/test_local.py +++ b/tests/test_local.py @@ -56,9 +56,9 @@ def out(tmp_path: Path) -> Path: def make_backup(out: Path, inputs: list[str], keep: int = -1, exclude: list[str] | None = None, - remove_before: bool = False, progress: bool = False) -> sb.Backup: + remove_before: bool = False, progress: bool = False, verbose: bool = False) -> sb.Backup: backup = sb.Backup(inputs, str(out), exclude or [], keep, OPTIONS, remove_before=remove_before, - progress=progress) + progress=progress, verbose=verbose) assert backup.check_params() == 0 @@ -356,6 +356,17 @@ class TestReturnCodes: assert run_backup(out, [str(src)]) == 0 assert [m[7:] for m in caplog.messages if m.startswith('rsync: ')] == logged + @pytest.mark.parametrize('returncode, level', [(0, 'INFO'), (23, 'WARNING'), (1, 'ERROR')]) + def test_verbose_one_line_per_message(self, src: Path, out: Path, fake_popen: type[FakePopen], + caplog: pytest.LogCaptureFixture, returncode: int, level: str) -> None: + fake_popen.returncode = returncode + + run_backup(out, [str(src)], verbose=True) + + rsync = [(r.levelname, r.getMessage()) for r in caplog.records if r.getMessage().startswith('rsync: ')] + lines = ['sending incremental file list', 'sent 1 bytes received 2 bytes', 'total size is 3'] + assert rsync == [(level, f'rsync: {line}') for line in lines] + def test_rsync_missing(self, src: Path, out: Path, tmp_path: Path, fake_popen: type[FakePopen], old_backups: list[str], monkeypatch: pytest.MonkeyPatch, caplog: pytest.LogCaptureFixture) -> None: