EdkLogger.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. ## @file
  2. # This file implements the log mechanism for Python tools.
  3. #
  4. # Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
  5. # This program and the accompanying materials
  6. # are licensed and made available under the terms and conditions of the BSD License
  7. # which accompanies this distribution. The full text of the license may be found at
  8. # http://opensource.org/licenses/bsd-license.php
  9. #
  10. # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
  12. #
  13. ## Import modules
  14. from __future__ import absolute_import
  15. import Common.LongFilePathOs as os, sys, logging
  16. import traceback
  17. from .BuildToolError import *
  18. ## Log level constants
  19. DEBUG_0 = 1
  20. DEBUG_1 = 2
  21. DEBUG_2 = 3
  22. DEBUG_3 = 4
  23. DEBUG_4 = 5
  24. DEBUG_5 = 6
  25. DEBUG_6 = 7
  26. DEBUG_7 = 8
  27. DEBUG_8 = 9
  28. DEBUG_9 = 10
  29. VERBOSE = 15
  30. INFO = 20
  31. WARN = 30
  32. QUIET = 40
  33. ERROR = 50
  34. SILENT = 99
  35. IsRaiseError = True
  36. # Tool name
  37. _ToolName = os.path.basename(sys.argv[0])
  38. # For validation purpose
  39. _LogLevels = [DEBUG_0, DEBUG_1, DEBUG_2, DEBUG_3, DEBUG_4, DEBUG_5,
  40. DEBUG_6, DEBUG_7, DEBUG_8, DEBUG_9, VERBOSE, WARN, INFO,
  41. ERROR, QUIET, SILENT]
  42. # For DEBUG level (All DEBUG_0~9 are applicable)
  43. _DebugLogger = logging.getLogger("tool_debug")
  44. _DebugFormatter = logging.Formatter("[%(asctime)s.%(msecs)d]: %(message)s", datefmt="%H:%M:%S")
  45. # For VERBOSE, INFO, WARN level
  46. _InfoLogger = logging.getLogger("tool_info")
  47. _InfoFormatter = logging.Formatter("%(message)s")
  48. # For ERROR level
  49. _ErrorLogger = logging.getLogger("tool_error")
  50. _ErrorFormatter = logging.Formatter("%(message)s")
  51. # String templates for ERROR/WARN/DEBUG log message
  52. _ErrorMessageTemplate = '\n\n%(tool)s...\n%(file)s(%(line)s): error %(errorcode)04X: %(msg)s\n\t%(extra)s'
  53. _ErrorMessageTemplateWithoutFile = '\n\n%(tool)s...\n : error %(errorcode)04X: %(msg)s\n\t%(extra)s'
  54. _WarningMessageTemplate = '%(tool)s...\n%(file)s(%(line)s): warning: %(msg)s'
  55. _WarningMessageTemplateWithoutFile = '%(tool)s: : warning: %(msg)s'
  56. _DebugMessageTemplate = '%(file)s(%(line)s): debug: \n %(msg)s'
  57. #
  58. # Flag used to take WARN as ERROR.
  59. # By default, only ERROR message will break the tools execution.
  60. #
  61. _WarningAsError = False
  62. ## Log debug message
  63. #
  64. # @param Level DEBUG level (DEBUG0~9)
  65. # @param Message Debug information
  66. # @param ExtraData More information associated with "Message"
  67. #
  68. def debug(Level, Message, ExtraData=None):
  69. if _DebugLogger.level > Level:
  70. return
  71. if Level > DEBUG_9:
  72. return
  73. # Find out the caller method information
  74. CallerStack = traceback.extract_stack()[-2]
  75. TemplateDict = {
  76. "file" : CallerStack[0],
  77. "line" : CallerStack[1],
  78. "msg" : Message,
  79. }
  80. if ExtraData is not None:
  81. LogText = _DebugMessageTemplate % TemplateDict + "\n %s" % ExtraData
  82. else:
  83. LogText = _DebugMessageTemplate % TemplateDict
  84. _DebugLogger.log(Level, LogText)
  85. ## Log verbose message
  86. #
  87. # @param Message Verbose information
  88. #
  89. def verbose(Message):
  90. return _InfoLogger.log(VERBOSE, Message)
  91. ## Log warning message
  92. #
  93. # Warning messages are those which might be wrong but won't fail the tool.
  94. #
  95. # @param ToolName The name of the tool. If not given, the name of caller
  96. # method will be used.
  97. # @param Message Warning information
  98. # @param File The name of file which caused the warning.
  99. # @param Line The line number in the "File" which caused the warning.
  100. # @param ExtraData More information associated with "Message"
  101. #
  102. def warn(ToolName, Message, File=None, Line=None, ExtraData=None):
  103. if _InfoLogger.level > WARN:
  104. return
  105. # if no tool name given, use caller's source file name as tool name
  106. if ToolName is None or ToolName == "":
  107. ToolName = os.path.basename(traceback.extract_stack()[-2][0])
  108. if Line is None:
  109. Line = "..."
  110. else:
  111. Line = "%d" % Line
  112. TemplateDict = {
  113. "tool" : ToolName,
  114. "file" : File,
  115. "line" : Line,
  116. "msg" : Message,
  117. }
  118. if File is not None:
  119. LogText = _WarningMessageTemplate % TemplateDict
  120. else:
  121. LogText = _WarningMessageTemplateWithoutFile % TemplateDict
  122. if ExtraData is not None:
  123. LogText += "\n %s" % ExtraData
  124. _InfoLogger.log(WARN, LogText)
  125. # Raise an exception if indicated
  126. if _WarningAsError == True:
  127. raise FatalError(WARNING_AS_ERROR)
  128. ## Log INFO message
  129. info = _InfoLogger.info
  130. ## Log ERROR message
  131. #
  132. # Once an error messages is logged, the tool's execution will be broken by raising
  133. # an exception. If you don't want to break the execution later, you can give
  134. # "RaiseError" with "False" value.
  135. #
  136. # @param ToolName The name of the tool. If not given, the name of caller
  137. # method will be used.
  138. # @param ErrorCode The error code
  139. # @param Message Warning information
  140. # @param File The name of file which caused the error.
  141. # @param Line The line number in the "File" which caused the warning.
  142. # @param ExtraData More information associated with "Message"
  143. # @param RaiseError Raise an exception to break the tool's execution if
  144. # it's True. This is the default behavior.
  145. #
  146. def error(ToolName, ErrorCode, Message=None, File=None, Line=None, ExtraData=None, RaiseError=IsRaiseError):
  147. if Line is None:
  148. Line = "..."
  149. else:
  150. Line = "%d" % Line
  151. if Message is None:
  152. if ErrorCode in gErrorMessage:
  153. Message = gErrorMessage[ErrorCode]
  154. else:
  155. Message = gErrorMessage[UNKNOWN_ERROR]
  156. if ExtraData is None:
  157. ExtraData = ""
  158. TemplateDict = {
  159. "tool" : _ToolName,
  160. "file" : File,
  161. "line" : Line,
  162. "errorcode" : ErrorCode,
  163. "msg" : Message,
  164. "extra" : ExtraData
  165. }
  166. if File is not None:
  167. LogText = _ErrorMessageTemplate % TemplateDict
  168. else:
  169. LogText = _ErrorMessageTemplateWithoutFile % TemplateDict
  170. _ErrorLogger.log(ERROR, LogText)
  171. if RaiseError and IsRaiseError:
  172. raise FatalError(ErrorCode)
  173. # Log information which should be always put out
  174. quiet = _ErrorLogger.error
  175. ## Initialize log system
  176. def Initialize():
  177. #
  178. # Since we use different format to log different levels of message into different
  179. # place (stdout or stderr), we have to use different "Logger" objects to do this.
  180. #
  181. # For DEBUG level (All DEBUG_0~9 are applicable)
  182. _DebugLogger.setLevel(INFO)
  183. _DebugChannel = logging.StreamHandler(sys.stdout)
  184. _DebugChannel.setFormatter(_DebugFormatter)
  185. _DebugLogger.addHandler(_DebugChannel)
  186. # For VERBOSE, INFO, WARN level
  187. _InfoLogger.setLevel(INFO)
  188. _InfoChannel = logging.StreamHandler(sys.stdout)
  189. _InfoChannel.setFormatter(_InfoFormatter)
  190. _InfoLogger.addHandler(_InfoChannel)
  191. # For ERROR level
  192. _ErrorLogger.setLevel(INFO)
  193. _ErrorCh = logging.StreamHandler(sys.stderr)
  194. _ErrorCh.setFormatter(_ErrorFormatter)
  195. _ErrorLogger.addHandler(_ErrorCh)
  196. ## Set log level
  197. #
  198. # @param Level One of log level in _LogLevel
  199. def SetLevel(Level):
  200. if Level not in _LogLevels:
  201. info("Not supported log level (%d). Use default level instead." % Level)
  202. Level = INFO
  203. _DebugLogger.setLevel(Level)
  204. _InfoLogger.setLevel(Level)
  205. _ErrorLogger.setLevel(Level)
  206. def InitializeForUnitTest():
  207. Initialize()
  208. SetLevel(SILENT)
  209. ## Get current log level
  210. def GetLevel():
  211. return _InfoLogger.getEffectiveLevel()
  212. ## Raise up warning as error
  213. def SetWarningAsError():
  214. global _WarningAsError
  215. _WarningAsError = True
  216. ## Specify a file to store the log message as well as put on console
  217. #
  218. # @param LogFile The file path used to store the log message
  219. #
  220. def SetLogFile(LogFile):
  221. if os.path.exists(LogFile):
  222. os.remove(LogFile)
  223. _Ch = logging.FileHandler(LogFile)
  224. _Ch.setFormatter(_DebugFormatter)
  225. _DebugLogger.addHandler(_Ch)
  226. _Ch= logging.FileHandler(LogFile)
  227. _Ch.setFormatter(_InfoFormatter)
  228. _InfoLogger.addHandler(_Ch)
  229. _Ch = logging.FileHandler(LogFile)
  230. _Ch.setFormatter(_ErrorFormatter)
  231. _ErrorLogger.addHandler(_Ch)
  232. if __name__ == '__main__':
  233. pass