| ## @file | |
| # This file implements the log mechanism for Python tools. | |
| # | |
| # Copyright (c) 2011, 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. | |
| # | |
| ''' | |
| Logger | |
| ''' | |
| ## Import modules | |
| from sys import argv | |
| from sys import stdout | |
| from sys import stderr | |
| import os.path | |
| from os import remove | |
| from logging import getLogger | |
| from logging import Formatter | |
| from logging import StreamHandler | |
| from logging import FileHandler | |
| from traceback import extract_stack | |
| from Logger.ToolError import FatalError | |
| from Logger.ToolError import WARNING_AS_ERROR | |
| from Logger.ToolError import gERROR_MESSAGE | |
| from Logger.ToolError import UNKNOWN_ERROR | |
| from Library import GlobalData | |
| # | |
| # 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 | |
| QUIET_1 = 41 | |
| ERROR = 50 | |
| SILENT = 60 | |
| IS_RAISE_ERROR = True | |
| SUPRESS_ERROR = False | |
| # | |
| # Tool name | |
| # | |
| _TOOL_NAME = os.path.basename(argv[0]) | |
| # | |
| # For validation purpose | |
| # | |
| _LOG_LEVELS = [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, \ | |
| QUIET_1, SILENT] | |
| # | |
| # For DEBUG level (All DEBUG_0~9 are applicable) | |
| # | |
| _DEBUG_LOGGER = getLogger("tool_debug") | |
| _DEBUG_FORMATTER = Formatter("[%(asctime)s.%(msecs)d]: %(message)s", \ | |
| datefmt="%H:%M:%S") | |
| # | |
| # For VERBOSE, INFO, WARN level | |
| # | |
| _INFO_LOGGER = getLogger("tool_info") | |
| _INFO_FORMATTER = Formatter("%(message)s") | |
| # | |
| # For ERROR level | |
| # | |
| _ERROR_LOGGER = getLogger("tool_error") | |
| _ERROR_FORMATTER = Formatter("%(message)s") | |
| # | |
| # String templates for ERROR/WARN/DEBUG log message | |
| # | |
| _ERROR_MESSAGE_TEMPLATE = \ | |
| ('\n\n%(tool)s...\n%(file)s(%(line)s): error %(errorcode)04X: %(msg)s\n\t%(extra)s') | |
| __ERROR_MESSAGE_TEMPLATE_WITHOUT_FILE = \ | |
| '\n\n%(tool)s...\n : error %(errorcode)04X: %(msg)s\n\t%(extra)s' | |
| _WARNING_MESSAGE_TEMPLATE = '%(tool)s...\n%(file)s(%(line)s): warning: %(msg)s' | |
| _WARNING_MESSAGE_TEMPLATE_WITHOUT_FILE = '%(tool)s: : warning: %(msg)s' | |
| _DEBUG_MESSAGE_TEMPLATE = '%(file)s(%(line)s): debug: \n %(msg)s' | |
| # | |
| # Log INFO message | |
| # | |
| #Info = _INFO_LOGGER.info | |
| def Info(msg, *args, **kwargs): | |
| _INFO_LOGGER.info(msg, *args, **kwargs) | |
| # | |
| # Log information which should be always put out | |
| # | |
| def Quiet(msg, *args, **kwargs): | |
| _ERROR_LOGGER.error(msg, *args, **kwargs) | |
| ## 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 _DEBUG_LOGGER.level > Level: | |
| return | |
| if Level > DEBUG_9: | |
| return | |
| # | |
| # Find out the caller method information | |
| # | |
| CallerStack = extract_stack()[-2] | |
| TemplateDict = { | |
| "file" : CallerStack[0], | |
| "line" : CallerStack[1], | |
| "msg" : Message, | |
| } | |
| if ExtraData != None: | |
| LogText = _DEBUG_MESSAGE_TEMPLATE % TemplateDict + "\n %s" % ExtraData | |
| else: | |
| LogText = _DEBUG_MESSAGE_TEMPLATE % TemplateDict | |
| _DEBUG_LOGGER.log(Level, LogText) | |
| ## Log verbose message | |
| # | |
| # @param Message Verbose information | |
| # | |
| def Verbose(Message): | |
| return _INFO_LOGGER.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 _INFO_LOGGER.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(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 = _WARNING_MESSAGE_TEMPLATE % TemplateDict | |
| else: | |
| LogText = _WARNING_MESSAGE_TEMPLATE_WITHOUT_FILE % TemplateDict | |
| if ExtraData != None: | |
| LogText += "\n %s" % ExtraData | |
| _INFO_LOGGER.log(WARN, LogText) | |
| # | |
| # Raise an execption if indicated | |
| # | |
| if GlobalData.gWARNING_AS_ERROR == True: | |
| raise FatalError(WARNING_AS_ERROR) | |
| ## 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=IS_RAISE_ERROR): | |
| if ToolName: | |
| pass | |
| if Line == None: | |
| Line = "..." | |
| else: | |
| Line = "%d" % Line | |
| if Message == None: | |
| if ErrorCode in gERROR_MESSAGE: | |
| Message = gERROR_MESSAGE[ErrorCode] | |
| else: | |
| Message = gERROR_MESSAGE[UNKNOWN_ERROR] | |
| if ExtraData == None: | |
| ExtraData = "" | |
| TemplateDict = { | |
| "tool" : _TOOL_NAME, | |
| "file" : File, | |
| "line" : Line, | |
| "errorcode" : ErrorCode, | |
| "msg" : Message, | |
| "extra" : ExtraData | |
| } | |
| if File != None: | |
| LogText = _ERROR_MESSAGE_TEMPLATE % TemplateDict | |
| else: | |
| LogText = __ERROR_MESSAGE_TEMPLATE_WITHOUT_FILE % TemplateDict | |
| if not SUPRESS_ERROR: | |
| _ERROR_LOGGER.log(ERROR, LogText) | |
| if RaiseError: | |
| raise FatalError(ErrorCode) | |
| ## 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) | |
| _DEBUG_LOGGER.setLevel(INFO) | |
| _DebugChannel = StreamHandler(stdout) | |
| _DebugChannel.setFormatter(_DEBUG_FORMATTER) | |
| _DEBUG_LOGGER.addHandler(_DebugChannel) | |
| # | |
| # For VERBOSE, INFO, WARN level | |
| # | |
| _INFO_LOGGER.setLevel(INFO) | |
| _InfoChannel = StreamHandler(stdout) | |
| _InfoChannel.setFormatter(_INFO_FORMATTER) | |
| _INFO_LOGGER.addHandler(_InfoChannel) | |
| # | |
| # For ERROR level | |
| # | |
| _ERROR_LOGGER.setLevel(INFO) | |
| _ErrorCh = StreamHandler(stderr) | |
| _ErrorCh.setFormatter(_ERROR_FORMATTER) | |
| _ERROR_LOGGER.addHandler(_ErrorCh) | |
| ## Set log level | |
| # | |
| # @param Level One of log level in _LogLevel | |
| # | |
| def SetLevel(Level): | |
| if Level not in _LOG_LEVELS: | |
| Info("Not supported log level (%d). Use default level instead." % \ | |
| Level) | |
| Level = INFO | |
| _DEBUG_LOGGER.setLevel(Level) | |
| _INFO_LOGGER.setLevel(Level) | |
| _ERROR_LOGGER.setLevel(Level) | |
| ## Get current log level | |
| # | |
| def GetLevel(): | |
| return _INFO_LOGGER.getEffectiveLevel() | |
| ## Raise up warning as error | |
| # | |
| def SetWarningAsError(): | |
| GlobalData.gWARNING_AS_ERROR = 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): | |
| remove(LogFile) | |
| _Ch = FileHandler(LogFile) | |
| _Ch.setFormatter(_DEBUG_FORMATTER) | |
| _DEBUG_LOGGER.addHandler(_Ch) | |
| _Ch = FileHandler(LogFile) | |
| _Ch.setFormatter(_INFO_FORMATTER) | |
| _INFO_LOGGER.addHandler(_Ch) | |
| _Ch = FileHandler(LogFile) | |
| _Ch.setFormatter(_ERROR_FORMATTER) | |
| _ERROR_LOGGER.addHandler(_Ch) | |