mirror of https://github.com/acidanthera/audk.git
326 lines
8.9 KiB
Python
326 lines
8.9 KiB
Python
## @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)
|
|
|
|
|
|
|