This allows the unit tests to run without the errors logging to the screen. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jordan Justen <jordan.l.justen@intel.com> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Yingke Liu <yingke.d.liu@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17692 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			277 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			277 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| ## @file
 | |
| # This file implements the log mechanism for Python tools.
 | |
| #
 | |
| # Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
 | |
| # This program and the accompanying materials
 | |
| # are licensed and made available under the terms and conditions of the BSD License
 | |
| # which accompanies this distribution.  The full text of the license may be found at
 | |
| # http://opensource.org/licenses/bsd-license.php
 | |
| #
 | |
| # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| #
 | |
| 
 | |
| ## Import modules
 | |
| import Common.LongFilePathOs as os, sys, logging
 | |
| import traceback
 | |
| from  BuildToolError import *
 | |
| 
 | |
| ## Log level constants
 | |
| DEBUG_0 = 1
 | |
| DEBUG_1 = 2
 | |
| DEBUG_2 = 3
 | |
| DEBUG_3 = 4
 | |
| DEBUG_4 = 5
 | |
| DEBUG_5 = 6
 | |
| DEBUG_6 = 7
 | |
| DEBUG_7 = 8
 | |
| DEBUG_8 = 9
 | |
| DEBUG_9 = 10
 | |
| VERBOSE = 15
 | |
| INFO    = 20
 | |
| WARN    = 30
 | |
| QUIET   = 40
 | |
| ERROR   = 50
 | |
| SILENT  = 99
 | |
| 
 | |
| IsRaiseError = True
 | |
| 
 | |
| # Tool name
 | |
| _ToolName = os.path.basename(sys.argv[0])
 | |
| 
 | |
| # For validation purpose
 | |
| _LogLevels = [DEBUG_0, DEBUG_1, DEBUG_2, DEBUG_3, DEBUG_4, DEBUG_5,
 | |
|               DEBUG_6, DEBUG_7, DEBUG_8, DEBUG_9, VERBOSE, WARN, INFO,
 | |
|               ERROR, QUIET, SILENT]
 | |
| 
 | |
| # For DEBUG level (All DEBUG_0~9 are applicable)
 | |
| _DebugLogger = logging.getLogger("tool_debug")
 | |
| _DebugFormatter = logging.Formatter("[%(asctime)s.%(msecs)d]: %(message)s", datefmt="%H:%M:%S")
 | |
| 
 | |
| # For VERBOSE, INFO, WARN level
 | |
| _InfoLogger = logging.getLogger("tool_info")
 | |
| _InfoFormatter = logging.Formatter("%(message)s")
 | |
| 
 | |
| # For ERROR level
 | |
| _ErrorLogger = logging.getLogger("tool_error")
 | |
| _ErrorFormatter = logging.Formatter("%(message)s")
 | |
| 
 | |
| # String templates for ERROR/WARN/DEBUG log message
 | |
| _ErrorMessageTemplate = '\n\n%(tool)s...\n%(file)s(%(line)s): error %(errorcode)04X: %(msg)s\n\t%(extra)s'
 | |
| _ErrorMessageTemplateWithoutFile = '\n\n%(tool)s...\n : error %(errorcode)04X: %(msg)s\n\t%(extra)s'
 | |
| _WarningMessageTemplate = '%(tool)s...\n%(file)s(%(line)s): warning: %(msg)s'
 | |
| _WarningMessageTemplateWithoutFile = '%(tool)s: : warning: %(msg)s'
 | |
| _DebugMessageTemplate = '%(file)s(%(line)s): debug: \n    %(msg)s'
 | |
| 
 | |
| #
 | |
| # Flag used to take WARN as ERROR.
 | |
| # By default, only ERROR message will break the tools execution.
 | |
| #
 | |
| _WarningAsError = False
 | |
| 
 | |
| ## Log debug message
 | |
| #
 | |
| #   @param  Level       DEBUG level (DEBUG0~9)
 | |
| #   @param  Message     Debug information
 | |
| #   @param  ExtraData   More information associated with "Message"
 | |
| #
 | |
| def debug(Level, Message, ExtraData=None):
 | |
|     if _DebugLogger.level > Level:
 | |
|         return
 | |
|     if Level > DEBUG_9:
 | |
|         return
 | |
| 
 | |
|     # Find out the caller method information
 | |
|     CallerStack = traceback.extract_stack()[-2]
 | |
|     TemplateDict = {
 | |
|         "file"      : CallerStack[0],
 | |
|         "line"      : CallerStack[1],
 | |
|         "msg"       : Message,
 | |
|     }
 | |
| 
 | |
|     if ExtraData != None:
 | |
|         LogText = _DebugMessageTemplate % TemplateDict + "\n    %s" % ExtraData
 | |
|     else:
 | |
|         LogText = _DebugMessageTemplate % TemplateDict
 | |
| 
 | |
|     _DebugLogger.log(Level, LogText)
 | |
| 
 | |
| ## Log verbose message
 | |
| #
 | |
| #   @param  Message     Verbose information
 | |
| #
 | |
| def verbose(Message):
 | |
|     return _InfoLogger.log(VERBOSE, Message)
 | |
| 
 | |
| ## Log warning message
 | |
| #
 | |
| #   Warning messages are those which might be wrong but won't fail the tool.
 | |
| #
 | |
| #   @param  ToolName    The name of the tool. If not given, the name of caller
 | |
| #                       method will be used.
 | |
| #   @param  Message     Warning information
 | |
| #   @param  File        The name of file which caused the warning.
 | |
| #   @param  Line        The line number in the "File" which caused the warning.
 | |
| #   @param  ExtraData   More information associated with "Message"
 | |
| #
 | |
| def warn(ToolName, Message, File=None, Line=None, ExtraData=None):
 | |
|     if _InfoLogger.level > WARN:
 | |
|         return
 | |
| 
 | |
|     # if no tool name given, use caller's source file name as tool name
 | |
|     if ToolName == None or ToolName == "":
 | |
|         ToolName = os.path.basename(traceback.extract_stack()[-2][0])
 | |
| 
 | |
|     if Line == None:
 | |
|         Line = "..."
 | |
|     else:
 | |
|         Line = "%d" % Line
 | |
| 
 | |
|     TemplateDict = {
 | |
|         "tool"      : ToolName,
 | |
|         "file"      : File,
 | |
|         "line"      : Line,
 | |
|         "msg"       : Message,
 | |
|     }
 | |
| 
 | |
|     if File != None:
 | |
|         LogText = _WarningMessageTemplate % TemplateDict
 | |
|     else:
 | |
|         LogText = _WarningMessageTemplateWithoutFile % TemplateDict
 | |
| 
 | |
|     if ExtraData != None:
 | |
|         LogText += "\n    %s" % ExtraData
 | |
| 
 | |
|     _InfoLogger.log(WARN, LogText)
 | |
| 
 | |
|     # Raise an execption if indicated
 | |
|     if _WarningAsError == True:
 | |
|         raise FatalError(WARNING_AS_ERROR)
 | |
| 
 | |
| ## Log INFO message
 | |
| info    = _InfoLogger.info
 | |
| 
 | |
| ## Log ERROR message
 | |
| #
 | |
| #   Once an error messages is logged, the tool's execution will be broken by raising
 | |
| # an execption. If you don't want to break the execution later, you can give
 | |
| # "RaiseError" with "False" value.
 | |
| #
 | |
| #   @param  ToolName    The name of the tool. If not given, the name of caller
 | |
| #                       method will be used.
 | |
| #   @param  ErrorCode   The error code
 | |
| #   @param  Message     Warning information
 | |
| #   @param  File        The name of file which caused the error.
 | |
| #   @param  Line        The line number in the "File" which caused the warning.
 | |
| #   @param  ExtraData   More information associated with "Message"
 | |
| #   @param  RaiseError  Raise an exception to break the tool's executuion if
 | |
| #                       it's True. This is the default behavior.
 | |
| #
 | |
| def error(ToolName, ErrorCode, Message=None, File=None, Line=None, ExtraData=None, RaiseError=IsRaiseError):
 | |
|     if Line == None:
 | |
|         Line = "..."
 | |
|     else:
 | |
|         Line = "%d" % Line
 | |
| 
 | |
|     if Message == None:
 | |
|         if ErrorCode in gErrorMessage:
 | |
|             Message = gErrorMessage[ErrorCode]
 | |
|         else:
 | |
|             Message = gErrorMessage[UNKNOWN_ERROR]
 | |
| 
 | |
|     if ExtraData == None:
 | |
|         ExtraData = ""
 | |
| 
 | |
|     TemplateDict = {
 | |
|         "tool"      : _ToolName,
 | |
|         "file"      : File,
 | |
|         "line"      : Line,
 | |
|         "errorcode" : ErrorCode,
 | |
|         "msg"       : Message,
 | |
|         "extra"     : ExtraData
 | |
|     }
 | |
| 
 | |
|     if File != None:
 | |
|         LogText =  _ErrorMessageTemplate % TemplateDict
 | |
|     else:
 | |
|         LogText = _ErrorMessageTemplateWithoutFile % TemplateDict
 | |
| 
 | |
|     _ErrorLogger.log(ERROR, LogText)
 | |
|     if RaiseError:
 | |
|         raise FatalError(ErrorCode)
 | |
| 
 | |
| # Log information which should be always put out
 | |
| quiet   = _ErrorLogger.error
 | |
| 
 | |
| ## Initialize log system
 | |
| def Initialize():
 | |
|     #
 | |
|     # Since we use different format to log different levels of message into different
 | |
|     # place (stdout or stderr), we have to use different "Logger" objects to do this.
 | |
|     #
 | |
|     # For DEBUG level (All DEBUG_0~9 are applicable)
 | |
|     _DebugLogger.setLevel(INFO)
 | |
|     _DebugChannel = logging.StreamHandler(sys.stdout)
 | |
|     _DebugChannel.setFormatter(_DebugFormatter)
 | |
|     _DebugLogger.addHandler(_DebugChannel)
 | |
| 
 | |
|     # For VERBOSE, INFO, WARN level
 | |
|     _InfoLogger.setLevel(INFO)
 | |
|     _InfoChannel = logging.StreamHandler(sys.stdout)
 | |
|     _InfoChannel.setFormatter(_InfoFormatter)
 | |
|     _InfoLogger.addHandler(_InfoChannel)
 | |
| 
 | |
|     # For ERROR level
 | |
|     _ErrorLogger.setLevel(INFO)
 | |
|     _ErrorCh = logging.StreamHandler(sys.stderr)
 | |
|     _ErrorCh.setFormatter(_ErrorFormatter)
 | |
|     _ErrorLogger.addHandler(_ErrorCh)
 | |
| 
 | |
| ## Set log level
 | |
| #
 | |
| #   @param  Level   One of log level in _LogLevel
 | |
| def SetLevel(Level):
 | |
|     if Level not in _LogLevels:
 | |
|         info("Not supported log level (%d). Use default level instead." % Level)
 | |
|         Level = INFO
 | |
|     _DebugLogger.setLevel(Level)
 | |
|     _InfoLogger.setLevel(Level)
 | |
|     _ErrorLogger.setLevel(Level)
 | |
| 
 | |
| def InitializeForUnitTest():
 | |
|     Initialize()
 | |
|     SetLevel(SILENT)
 | |
| 
 | |
| ## Get current log level
 | |
| def GetLevel():
 | |
|     return _InfoLogger.getEffectiveLevel()
 | |
| 
 | |
| ## Raise up warning as error
 | |
| def SetWarningAsError():
 | |
|     global _WarningAsError
 | |
|     _WarningAsError = True
 | |
| 
 | |
| ## Specify a file to store the log message as well as put on console
 | |
| #
 | |
| #   @param  LogFile     The file path used to store the log message
 | |
| #
 | |
| def SetLogFile(LogFile):
 | |
|     if os.path.exists(LogFile):
 | |
|         os.remove(LogFile)
 | |
| 
 | |
|     _Ch = logging.FileHandler(LogFile)
 | |
|     _Ch.setFormatter(_DebugFormatter)
 | |
|     _DebugLogger.addHandler(_Ch)
 | |
| 
 | |
|     _Ch= logging.FileHandler(LogFile)
 | |
|     _Ch.setFormatter(_InfoFormatter)
 | |
|     _InfoLogger.addHandler(_Ch)
 | |
| 
 | |
|     _Ch = logging.FileHandler(LogFile)
 | |
|     _Ch.setFormatter(_ErrorFormatter)
 | |
|     _ErrorLogger.addHandler(_Ch)
 | |
| 
 | |
| if __name__ == '__main__':
 | |
|     pass
 | |
| 
 |