logging.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. from __future__ import absolute_import
  2. import contextlib
  3. import logging
  4. import logging.handlers
  5. import os
  6. try:
  7. import threading
  8. except ImportError:
  9. import dummy_threading as threading
  10. from pip.compat import WINDOWS
  11. try:
  12. from pip._vendor import colorama
  13. # Lots of different errors can come from this, including SystemError and
  14. # ImportError.
  15. except Exception:
  16. colorama = None
  17. _log_state = threading.local()
  18. _log_state.indentation = 0
  19. @contextlib.contextmanager
  20. def indent_log(num=2):
  21. """
  22. A context manager which will cause the log output to be indented for any
  23. log messages emited inside it.
  24. """
  25. _log_state.indentation += num
  26. yield
  27. _log_state.indentation -= num
  28. def get_indentation():
  29. return _log_state.indentation
  30. class IndentingFormatter(logging.Formatter):
  31. def format(self, record):
  32. """
  33. Calls the standard formatter, but will indent all of the log messages
  34. by our current indentation level.
  35. """
  36. formatted = logging.Formatter.format(self, record)
  37. formatted = "".join([
  38. (" " * get_indentation()) + line
  39. for line in formatted.splitlines(True)
  40. ])
  41. return formatted
  42. def _color_wrap(*colors):
  43. def wrapped(inp):
  44. return "".join(list(colors) + [inp, colorama.Style.RESET_ALL])
  45. return wrapped
  46. class ColorizedStreamHandler(logging.StreamHandler):
  47. # Don't build up a list of colors if we don't have colorama
  48. if colorama:
  49. COLORS = [
  50. # This needs to be in order from highest logging level to lowest.
  51. (logging.ERROR, _color_wrap(colorama.Fore.RED)),
  52. (logging.WARNING, _color_wrap(colorama.Fore.YELLOW)),
  53. ]
  54. else:
  55. COLORS = []
  56. def __init__(self, stream=None):
  57. logging.StreamHandler.__init__(self, stream)
  58. if WINDOWS and colorama:
  59. self.stream = colorama.AnsiToWin32(self.stream)
  60. def should_color(self):
  61. # Don't colorize things if we do not have colorama
  62. if not colorama:
  63. return False
  64. real_stream = (
  65. self.stream if not isinstance(self.stream, colorama.AnsiToWin32)
  66. else self.stream.wrapped
  67. )
  68. # If the stream is a tty we should color it
  69. if hasattr(real_stream, "isatty") and real_stream.isatty():
  70. return True
  71. # If we have an ASNI term we should color it
  72. if os.environ.get("TERM") == "ANSI":
  73. return True
  74. # If anything else we should not color it
  75. return False
  76. def format(self, record):
  77. msg = logging.StreamHandler.format(self, record)
  78. if self.should_color():
  79. for level, color in self.COLORS:
  80. if record.levelno >= level:
  81. msg = color(msg)
  82. break
  83. return msg
  84. class BetterRotatingFileHandler(logging.handlers.RotatingFileHandler):
  85. def _open(self):
  86. # Ensure the directory exists
  87. if not os.path.exists(os.path.dirname(self.baseFilename)):
  88. os.makedirs(os.path.dirname(self.baseFilename))
  89. return logging.handlers.RotatingFileHandler._open(self)
  90. class MaxLevelFilter(logging.Filter):
  91. def __init__(self, level):
  92. self.level = level
  93. def filter(self, record):
  94. return record.levelno < self.level