summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/build/android/pylib/utils/logging_utils.py
blob: 846d336c2c8da3f068b302d1a56a86600ffef574 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import contextlib
import logging
import os

from pylib.constants import host_paths

_COLORAMA_PATH = os.path.join(
    host_paths.DIR_SOURCE_ROOT, 'third_party', 'colorama', 'src')

with host_paths.SysPath(_COLORAMA_PATH, position=0):
  import colorama

BACK = colorama.Back
FORE = colorama.Fore
STYLE = colorama.Style


class _ColorFormatter(logging.Formatter):
  # pylint does not see members added dynamically in the constructor.
  # pylint: disable=no-member
  color_map = {
    logging.DEBUG: (FORE.CYAN),
    logging.WARNING: (FORE.YELLOW),
    logging.ERROR: (FORE.RED),
    logging.CRITICAL: (BACK.RED),
  }

  def __init__(self, wrapped_formatter=None):
    """Wraps a |logging.Formatter| and adds color."""
    super(_ColorFormatter, self).__init__(self)
    self._wrapped_formatter = wrapped_formatter or logging.Formatter()

  #override
  def format(self, record):
    message = self._wrapped_formatter.format(record)
    return self.Colorize(message, record.levelno)

  def Colorize(self, message, log_level):
    try:
      return (''.join(self.color_map[log_level]) + message +
              colorama.Style.RESET_ALL)
    except KeyError:
      return message


class ColorStreamHandler(logging.StreamHandler):
  """Handler that can be used to colorize logging output.

  Example using a specific logger:

    logger = logging.getLogger('my_logger')
    logger.addHandler(ColorStreamHandler())
    logger.info('message')

  Example using the root logger:

    ColorStreamHandler.MakeDefault()
    logging.info('message')

  """
  def __init__(self, force_color=False):
    super(ColorStreamHandler, self).__init__()
    self.force_color = force_color
    self.setFormatter(logging.Formatter())

  @property
  def is_tty(self):
    isatty = getattr(self.stream, 'isatty', None)
    return isatty and isatty()

  #override
  def setFormatter(self, formatter):
    if self.force_color or self.is_tty:
      formatter = _ColorFormatter(formatter)
    super(ColorStreamHandler, self).setFormatter(formatter)

  @staticmethod
  def MakeDefault(force_color=False):
    """
     Replaces the default logging handlers with a coloring handler. To use
     a colorizing handler at the same time as others, either register them
     after this call, or add the ColorStreamHandler on the logger using
     Logger.addHandler()

     Args:
       force_color: Set to True to bypass the tty check and always colorize.
     """
    # If the existing handlers aren't removed, messages are duplicated
    logging.getLogger().handlers = []
    logging.getLogger().addHandler(ColorStreamHandler(force_color))


@contextlib.contextmanager
def OverrideColor(level, color):
  """Temporarily override the logging color for a specified level.

  Args:
    level: logging level whose color gets overridden.
    color: tuple of formats to apply to log lines.
  """
  prev_colors = {}
  for handler in logging.getLogger().handlers:
    if isinstance(handler.formatter, _ColorFormatter):
      prev_colors[handler.formatter] = handler.formatter.color_map[level]
      handler.formatter.color_map[level] = color
  try:
    yield
  finally:
    for formatter, prev_color in prev_colors.items():
      formatter.color_map[level] = prev_color


@contextlib.contextmanager
def SuppressLogging(level=logging.ERROR):
  """Momentarilly suppress logging events from all loggers.

  TODO(jbudorick): This is not thread safe. Log events from other threads might
  also inadvertently disappear.

  Example:

    with logging_utils.SuppressLogging():
      # all but CRITICAL logging messages are suppressed
      logging.info('just doing some thing') # not shown
      logging.critical('something really bad happened') # still shown

  Args:
    level: logging events with this or lower levels are suppressed.
  """
  logging.disable(level)
  yield
  logging.disable(logging.NOTSET)