msg.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. # ex:ts=4:sw=4:sts=4:et
  2. # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
  3. """
  4. BitBake 'msg' implementation
  5. Message handling infrastructure for bitbake
  6. """
  7. # Copyright (C) 2006 Richard Purdie
  8. #
  9. # This program is free software; you can redistribute it and/or modify
  10. # it under the terms of the GNU General Public License version 2 as
  11. # published by the Free Software Foundation.
  12. #
  13. # This program is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License along
  19. # with this program; if not, write to the Free Software Foundation, Inc.,
  20. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  21. import sys
  22. import copy
  23. import logging
  24. import collections
  25. from itertools import groupby
  26. import warnings
  27. import bb
  28. import bb.event
  29. class BBLogFormatter(logging.Formatter):
  30. """Formatter which ensures that our 'plain' messages (logging.INFO + 1) are used as is"""
  31. DEBUG3 = logging.DEBUG - 2
  32. DEBUG2 = logging.DEBUG - 1
  33. DEBUG = logging.DEBUG
  34. VERBOSE = logging.INFO - 1
  35. NOTE = logging.INFO
  36. PLAIN = logging.INFO + 1
  37. ERROR = logging.ERROR
  38. WARNING = logging.WARNING
  39. CRITICAL = logging.CRITICAL
  40. levelnames = {
  41. DEBUG3 : 'DEBUG',
  42. DEBUG2 : 'DEBUG',
  43. DEBUG : 'DEBUG',
  44. VERBOSE: 'NOTE',
  45. NOTE : 'NOTE',
  46. PLAIN : '',
  47. WARNING : 'WARNING',
  48. ERROR : 'ERROR',
  49. CRITICAL: 'ERROR',
  50. }
  51. color_enabled = False
  52. BASECOLOR, BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(29,38)
  53. COLORS = {
  54. DEBUG3 : CYAN,
  55. DEBUG2 : CYAN,
  56. DEBUG : CYAN,
  57. VERBOSE : BASECOLOR,
  58. NOTE : BASECOLOR,
  59. PLAIN : BASECOLOR,
  60. WARNING : YELLOW,
  61. ERROR : RED,
  62. CRITICAL: RED,
  63. }
  64. BLD = '\033[1;%dm'
  65. STD = '\033[%dm'
  66. RST = '\033[0m'
  67. def getLevelName(self, levelno):
  68. try:
  69. return self.levelnames[levelno]
  70. except KeyError:
  71. self.levelnames[levelno] = value = 'Level %d' % levelno
  72. return value
  73. def format(self, record):
  74. record.levelname = self.getLevelName(record.levelno)
  75. if record.levelno == self.PLAIN:
  76. msg = record.getMessage()
  77. else:
  78. if self.color_enabled:
  79. record = self.colorize(record)
  80. msg = logging.Formatter.format(self, record)
  81. if hasattr(record, 'bb_exc_info'):
  82. etype, value, tb = record.bb_exc_info
  83. formatted = bb.exceptions.format_exception(etype, value, tb, limit=5)
  84. msg += '\n' + ''.join(formatted)
  85. return msg
  86. def colorize(self, record):
  87. color = self.COLORS[record.levelno]
  88. if self.color_enabled and color is not None:
  89. record = copy.copy(record)
  90. record.levelname = "".join([self.BLD % color, record.levelname, self.RST])
  91. record.msg = "".join([self.STD % color, record.msg, self.RST])
  92. return record
  93. def enable_color(self):
  94. self.color_enabled = True
  95. class BBLogFilter(object):
  96. def __init__(self, handler, level, debug_domains):
  97. self.stdlevel = level
  98. self.debug_domains = debug_domains
  99. loglevel = level
  100. for domain in debug_domains:
  101. if debug_domains[domain] < loglevel:
  102. loglevel = debug_domains[domain]
  103. handler.setLevel(loglevel)
  104. handler.addFilter(self)
  105. def filter(self, record):
  106. if record.levelno >= self.stdlevel:
  107. return True
  108. if record.name in self.debug_domains and record.levelno >= self.debug_domains[record.name]:
  109. return True
  110. return False
  111. class BBLogFilterStdErr(BBLogFilter):
  112. def filter(self, record):
  113. if not BBLogFilter.filter(self, record):
  114. return False
  115. if record.levelno >= logging.ERROR:
  116. return True
  117. return False
  118. class BBLogFilterStdOut(BBLogFilter):
  119. def filter(self, record):
  120. if not BBLogFilter.filter(self, record):
  121. return False
  122. if record.levelno < logging.ERROR:
  123. return True
  124. return False
  125. # Message control functions
  126. #
  127. loggerDefaultDebugLevel = 0
  128. loggerDefaultVerbose = False
  129. loggerVerboseLogs = False
  130. loggerDefaultDomains = []
  131. def init_msgconfig(verbose, debug, debug_domains=None):
  132. """
  133. Set default verbosity and debug levels config the logger
  134. """
  135. bb.msg.loggerDefaultDebugLevel = debug
  136. bb.msg.loggerDefaultVerbose = verbose
  137. if verbose:
  138. bb.msg.loggerVerboseLogs = True
  139. if debug_domains:
  140. bb.msg.loggerDefaultDomains = debug_domains
  141. else:
  142. bb.msg.loggerDefaultDomains = []
  143. def constructLogOptions():
  144. debug = loggerDefaultDebugLevel
  145. verbose = loggerDefaultVerbose
  146. domains = loggerDefaultDomains
  147. if debug:
  148. level = BBLogFormatter.DEBUG - debug + 1
  149. elif verbose:
  150. level = BBLogFormatter.VERBOSE
  151. else:
  152. level = BBLogFormatter.NOTE
  153. debug_domains = {}
  154. for (domainarg, iterator) in groupby(domains):
  155. dlevel = len(tuple(iterator))
  156. debug_domains["BitBake.%s" % domainarg] = logging.DEBUG - dlevel + 1
  157. return level, debug_domains
  158. def addDefaultlogFilter(handler, cls = BBLogFilter):
  159. level, debug_domains = constructLogOptions()
  160. cls(handler, level, debug_domains)
  161. #
  162. # Message handling functions
  163. #
  164. def fatal(msgdomain, msg):
  165. if msgdomain:
  166. logger = logging.getLogger("BitBake.%s" % msgdomain)
  167. else:
  168. logger = logging.getLogger("BitBake")
  169. logger.critical(msg)
  170. sys.exit(1)