_log.py 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. import logging
  2. import collections
  3. from .case import _BaseTestCaseContext
  4. _LoggingWatcher = collections.namedtuple("_LoggingWatcher",
  5. ["records", "output"])
  6. class _CapturingHandler(logging.Handler):
  7. """
  8. A logging handler capturing all (raw and formatted) logging output.
  9. """
  10. def __init__(self):
  11. logging.Handler.__init__(self)
  12. self.watcher = _LoggingWatcher([], [])
  13. def flush(self):
  14. pass
  15. def emit(self, record):
  16. self.watcher.records.append(record)
  17. msg = self.format(record)
  18. self.watcher.output.append(msg)
  19. class _AssertLogsContext(_BaseTestCaseContext):
  20. """A context manager used to implement TestCase.assertLogs()."""
  21. LOGGING_FORMAT = "%(levelname)s:%(name)s:%(message)s"
  22. def __init__(self, test_case, logger_name, level):
  23. _BaseTestCaseContext.__init__(self, test_case)
  24. self.logger_name = logger_name
  25. if level:
  26. self.level = logging._nameToLevel.get(level, level)
  27. else:
  28. self.level = logging.INFO
  29. self.msg = None
  30. def __enter__(self):
  31. if isinstance(self.logger_name, logging.Logger):
  32. logger = self.logger = self.logger_name
  33. else:
  34. logger = self.logger = logging.getLogger(self.logger_name)
  35. formatter = logging.Formatter(self.LOGGING_FORMAT)
  36. handler = _CapturingHandler()
  37. handler.setFormatter(formatter)
  38. self.watcher = handler.watcher
  39. self.old_handlers = logger.handlers[:]
  40. self.old_level = logger.level
  41. self.old_propagate = logger.propagate
  42. logger.handlers = [handler]
  43. logger.setLevel(self.level)
  44. logger.propagate = False
  45. return handler.watcher
  46. def __exit__(self, exc_type, exc_value, tb):
  47. self.logger.handlers = self.old_handlers
  48. self.logger.propagate = self.old_propagate
  49. self.logger.setLevel(self.old_level)
  50. if exc_type is not None:
  51. # let unexpected exceptions pass through
  52. return False
  53. if len(self.watcher.records) == 0:
  54. self._raiseFailure(
  55. "no logs of level {} or higher triggered on {}"
  56. .format(logging.getLevelName(self.level), self.logger.name))