| ## @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) |
| |
| |
| |