diff options
| -rw-r--r-- | repo_logging.py | 58 | ||||
| -rw-r--r-- | tests/test_repo_logging.py | 36 |
2 files changed, 33 insertions, 61 deletions
diff --git a/repo_logging.py b/repo_logging.py index e94af7df..7d050555 100644 --- a/repo_logging.py +++ b/repo_logging.py | |||
| @@ -15,7 +15,7 @@ | |||
| 15 | """Logic for printing user-friendly logs in repo.""" | 15 | """Logic for printing user-friendly logs in repo.""" |
| 16 | 16 | ||
| 17 | import logging | 17 | import logging |
| 18 | from typing import Any, List | 18 | from typing import List |
| 19 | 19 | ||
| 20 | from color import Coloring | 20 | from color import Coloring |
| 21 | 21 | ||
| @@ -23,23 +23,42 @@ from color import Coloring | |||
| 23 | SEPARATOR = "=" * 80 | 23 | SEPARATOR = "=" * 80 |
| 24 | 24 | ||
| 25 | 25 | ||
| 26 | class LogColoring(Coloring): | 26 | class _ConfigMock: |
| 27 | """Default coloring config to use when Logging.config is not set.""" | ||
| 28 | |||
| 29 | def __init__(self): | ||
| 30 | self.default_values = {"color.ui": "auto"} | ||
| 31 | |||
| 32 | def GetString(self, x): | ||
| 33 | return self.default_values.get(x, None) | ||
| 34 | |||
| 35 | |||
| 36 | class _LogColoring(Coloring): | ||
| 27 | """Coloring outstream for logging.""" | 37 | """Coloring outstream for logging.""" |
| 28 | 38 | ||
| 29 | def __init__(self, config): | 39 | def __init__(self, config): |
| 30 | super().__init__(config, "logs") | 40 | super().__init__(config, "logs") |
| 31 | self.error = self.colorer("error", fg="red") | 41 | self.error = self.colorer("error", fg="red") |
| 32 | self.warning = self.colorer("warn", fg="yellow") | 42 | self.warning = self.colorer("warn", fg="yellow") |
| 43 | self.levelMap = { | ||
| 44 | "WARNING": self.warning, | ||
| 45 | "ERROR": self.error, | ||
| 46 | } | ||
| 33 | 47 | ||
| 34 | 48 | ||
| 35 | class ConfigMock: | 49 | class _LogColoringFormatter(logging.Formatter): |
| 36 | """Default coloring config to use when Logging.config is not set.""" | 50 | """Coloring formatter for logging.""" |
| 37 | 51 | ||
| 38 | def __init__(self): | 52 | def __init__(self, config=None, *args, **kwargs): |
| 39 | self.default_values = {"color.ui": "auto"} | 53 | self.config = config if config else _ConfigMock() |
| 54 | self.colorer = _LogColoring(self.config) | ||
| 55 | super().__init__(*args, **kwargs) | ||
| 40 | 56 | ||
| 41 | def GetString(self, x): | 57 | def format(self, record): |
| 42 | return self.default_values.get(x, None) | 58 | """Formats |record| with color.""" |
| 59 | msg = super().format(record) | ||
| 60 | colorer = self.colorer.levelMap.get(record.levelname) | ||
| 61 | return msg if not colorer else colorer(msg) | ||
| 43 | 62 | ||
| 44 | 63 | ||
| 45 | class RepoLogger(logging.Logger): | 64 | class RepoLogger(logging.Logger): |
| @@ -47,23 +66,12 @@ class RepoLogger(logging.Logger): | |||
| 47 | 66 | ||
| 48 | def __init__(self, name: str, config=None, **kwargs): | 67 | def __init__(self, name: str, config=None, **kwargs): |
| 49 | super().__init__(name, **kwargs) | 68 | super().__init__(name, **kwargs) |
| 50 | self.config = config if config else ConfigMock() | 69 | handler = logging.StreamHandler() |
| 51 | self.colorer = LogColoring(self.config) | 70 | handler.setFormatter(_LogColoringFormatter(config)) |
| 52 | 71 | self.addHandler(handler) | |
| 53 | def error(self, msg: Any, *args, **kwargs): | ||
| 54 | """Print and aggregate error-level logs.""" | ||
| 55 | colored_error = self.colorer.error(str(msg), *args) | ||
| 56 | super().error(colored_error, **kwargs) | ||
| 57 | |||
| 58 | def warning(self, msg: Any, *args, **kwargs): | ||
| 59 | """Print warning-level logs with coloring.""" | ||
| 60 | colored_warning = self.colorer.warning(str(msg), *args) | ||
| 61 | super().warning(colored_warning, **kwargs) | ||
| 62 | 72 | ||
| 63 | def log_aggregated_errors(self, errors: List[Exception]): | 73 | def log_aggregated_errors(self, errors: List[Exception]): |
| 64 | """Print all aggregated logs.""" | 74 | """Print all aggregated logs.""" |
| 65 | super().error(self.colorer.error(SEPARATOR)) | 75 | super().error(SEPARATOR) |
| 66 | super().error( | 76 | super().error("Repo command failed due to following errors:") |
| 67 | self.colorer.error("Repo command failed due to following errors:") | 77 | super().error("\n".join(str(e) for e in errors)) |
| 68 | ) | ||
| 69 | super().error("\n".join(map(str, errors))) | ||
diff --git a/tests/test_repo_logging.py b/tests/test_repo_logging.py index b51e6270..52f251a7 100644 --- a/tests/test_repo_logging.py +++ b/tests/test_repo_logging.py | |||
| @@ -20,42 +20,6 @@ from repo_logging import RepoLogger | |||
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | class TestRepoLogger(unittest.TestCase): | 22 | class TestRepoLogger(unittest.TestCase): |
| 23 | def test_error_logs_error(self): | ||
| 24 | """Test if error fn outputs logs.""" | ||
| 25 | logger = RepoLogger(__name__) | ||
| 26 | result = None | ||
| 27 | |||
| 28 | def mock_handler(log): | ||
| 29 | nonlocal result | ||
| 30 | result = log.getMessage() | ||
| 31 | |||
| 32 | mock_out = mock.MagicMock() | ||
| 33 | mock_out.level = 0 | ||
| 34 | mock_out.handle = mock_handler | ||
| 35 | logger.addHandler(mock_out) | ||
| 36 | |||
| 37 | logger.error("We're no strangers to love") | ||
| 38 | |||
| 39 | self.assertEqual(result, "We're no strangers to love") | ||
| 40 | |||
| 41 | def test_warning_logs_error(self): | ||
| 42 | """Test if warning fn outputs logs.""" | ||
| 43 | logger = RepoLogger(__name__) | ||
| 44 | result = None | ||
| 45 | |||
| 46 | def mock_handler(log): | ||
| 47 | nonlocal result | ||
| 48 | result = log.getMessage() | ||
| 49 | |||
| 50 | mock_out = mock.MagicMock() | ||
| 51 | mock_out.level = 0 | ||
| 52 | mock_out.handle = mock_handler | ||
| 53 | logger.addHandler(mock_out) | ||
| 54 | |||
| 55 | logger.warning("You know the rules and so do I (do I)") | ||
| 56 | |||
| 57 | self.assertEqual(result, "You know the rules and so do I (do I)") | ||
| 58 | |||
| 59 | def test_log_aggregated_errors_logs_aggregated_errors(self): | 23 | def test_log_aggregated_errors_logs_aggregated_errors(self): |
| 60 | """Test if log_aggregated_errors outputs aggregated errors.""" | 24 | """Test if log_aggregated_errors outputs aggregated errors.""" |
| 61 | logger = RepoLogger(__name__) | 25 | logger = RepoLogger(__name__) |
