Home | History | Annotate | Download | only in Common
      1 ## @file

      2 # This file implements the log mechanism for Python tools.

      3 #

      4 # Copyright (c) 2007 - 2015, 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 
     14 ## Import modules

     15 import Common.LongFilePathOs as os, sys, logging
     16 import traceback
     17 from  BuildToolError import *
     18 
     19 ## Log level constants

     20 DEBUG_0 = 1
     21 DEBUG_1 = 2
     22 DEBUG_2 = 3
     23 DEBUG_3 = 4
     24 DEBUG_4 = 5
     25 DEBUG_5 = 6
     26 DEBUG_6 = 7
     27 DEBUG_7 = 8
     28 DEBUG_8 = 9
     29 DEBUG_9 = 10
     30 VERBOSE = 15
     31 INFO    = 20
     32 WARN    = 30
     33 QUIET   = 40
     34 ERROR   = 50
     35 SILENT  = 99
     36 
     37 IsRaiseError = True
     38 
     39 # Tool name

     40 _ToolName = os.path.basename(sys.argv[0])
     41 
     42 # For validation purpose

     43 _LogLevels = [DEBUG_0, DEBUG_1, DEBUG_2, DEBUG_3, DEBUG_4, DEBUG_5,
     44               DEBUG_6, DEBUG_7, DEBUG_8, DEBUG_9, VERBOSE, WARN, INFO,
     45               ERROR, QUIET, SILENT]
     46 
     47 # For DEBUG level (All DEBUG_0~9 are applicable)

     48 _DebugLogger = logging.getLogger("tool_debug")
     49 _DebugFormatter = logging.Formatter("[%(asctime)s.%(msecs)d]: %(message)s", datefmt="%H:%M:%S")
     50 
     51 # For VERBOSE, INFO, WARN level

     52 _InfoLogger = logging.getLogger("tool_info")
     53 _InfoFormatter = logging.Formatter("%(message)s")
     54 
     55 # For ERROR level

     56 _ErrorLogger = logging.getLogger("tool_error")
     57 _ErrorFormatter = logging.Formatter("%(message)s")
     58 
     59 # String templates for ERROR/WARN/DEBUG log message

     60 _ErrorMessageTemplate = '\n\n%(tool)s...\n%(file)s(%(line)s): error %(errorcode)04X: %(msg)s\n\t%(extra)s'
     61 _ErrorMessageTemplateWithoutFile = '\n\n%(tool)s...\n : error %(errorcode)04X: %(msg)s\n\t%(extra)s'
     62 _WarningMessageTemplate = '%(tool)s...\n%(file)s(%(line)s): warning: %(msg)s'
     63 _WarningMessageTemplateWithoutFile = '%(tool)s: : warning: %(msg)s'
     64 _DebugMessageTemplate = '%(file)s(%(line)s): debug: \n    %(msg)s'
     65 
     66 #

     67 # Flag used to take WARN as ERROR.

     68 # By default, only ERROR message will break the tools execution.

     69 #

     70 _WarningAsError = False
     71 
     72 ## Log debug message

     73 #

     74 #   @param  Level       DEBUG level (DEBUG0~9)

     75 #   @param  Message     Debug information

     76 #   @param  ExtraData   More information associated with "Message"

     77 #

     78 def debug(Level, Message, ExtraData=None):
     79     if _DebugLogger.level > Level:
     80         return
     81     if Level > DEBUG_9:
     82         return
     83 
     84     # Find out the caller method information

     85     CallerStack = traceback.extract_stack()[-2]
     86     TemplateDict = {
     87         "file"      : CallerStack[0],
     88         "line"      : CallerStack[1],
     89         "msg"       : Message,
     90     }
     91 
     92     if ExtraData != None:
     93         LogText = _DebugMessageTemplate % TemplateDict + "\n    %s" % ExtraData
     94     else:
     95         LogText = _DebugMessageTemplate % TemplateDict
     96 
     97     _DebugLogger.log(Level, LogText)
     98 
     99 ## Log verbose message

    100 #

    101 #   @param  Message     Verbose information

    102 #

    103 def verbose(Message):
    104     return _InfoLogger.log(VERBOSE, Message)
    105 
    106 ## Log warning message

    107 #

    108 #   Warning messages are those which might be wrong but won't fail the tool.

    109 #

    110 #   @param  ToolName    The name of the tool. If not given, the name of caller

    111 #                       method will be used.

    112 #   @param  Message     Warning information

    113 #   @param  File        The name of file which caused the warning.

    114 #   @param  Line        The line number in the "File" which caused the warning.

    115 #   @param  ExtraData   More information associated with "Message"

    116 #

    117 def warn(ToolName, Message, File=None, Line=None, ExtraData=None):
    118     if _InfoLogger.level > WARN:
    119         return
    120 
    121     # if no tool name given, use caller's source file name as tool name

    122     if ToolName == None or ToolName == "":
    123         ToolName = os.path.basename(traceback.extract_stack()[-2][0])
    124 
    125     if Line == None:
    126         Line = "..."
    127     else:
    128         Line = "%d" % Line
    129 
    130     TemplateDict = {
    131         "tool"      : ToolName,
    132         "file"      : File,
    133         "line"      : Line,
    134         "msg"       : Message,
    135     }
    136 
    137     if File != None:
    138         LogText = _WarningMessageTemplate % TemplateDict
    139     else:
    140         LogText = _WarningMessageTemplateWithoutFile % TemplateDict
    141 
    142     if ExtraData != None:
    143         LogText += "\n    %s" % ExtraData
    144 
    145     _InfoLogger.log(WARN, LogText)
    146 
    147     # Raise an execption if indicated

    148     if _WarningAsError == True:
    149         raise FatalError(WARNING_AS_ERROR)
    150 
    151 ## Log INFO message

    152 info    = _InfoLogger.info
    153 
    154 ## Log ERROR message

    155 #

    156 #   Once an error messages is logged, the tool's execution will be broken by raising

    157 # an execption. If you don't want to break the execution later, you can give

    158 # "RaiseError" with "False" value.

    159 #

    160 #   @param  ToolName    The name of the tool. If not given, the name of caller

    161 #                       method will be used.

    162 #   @param  ErrorCode   The error code

    163 #   @param  Message     Warning information

    164 #   @param  File        The name of file which caused the error.

    165 #   @param  Line        The line number in the "File" which caused the warning.

    166 #   @param  ExtraData   More information associated with "Message"

    167 #   @param  RaiseError  Raise an exception to break the tool's executuion if

    168 #                       it's True. This is the default behavior.

    169 #

    170 def error(ToolName, ErrorCode, Message=None, File=None, Line=None, ExtraData=None, RaiseError=IsRaiseError):
    171     if Line == None:
    172         Line = "..."
    173     else:
    174         Line = "%d" % Line
    175 
    176     if Message == None:
    177         if ErrorCode in gErrorMessage:
    178             Message = gErrorMessage[ErrorCode]
    179         else:
    180             Message = gErrorMessage[UNKNOWN_ERROR]
    181 
    182     if ExtraData == None:
    183         ExtraData = ""
    184 
    185     TemplateDict = {
    186         "tool"      : _ToolName,
    187         "file"      : File,
    188         "line"      : Line,
    189         "errorcode" : ErrorCode,
    190         "msg"       : Message,
    191         "extra"     : ExtraData
    192     }
    193 
    194     if File != None:
    195         LogText =  _ErrorMessageTemplate % TemplateDict
    196     else:
    197         LogText = _ErrorMessageTemplateWithoutFile % TemplateDict
    198 
    199     _ErrorLogger.log(ERROR, LogText)
    200     if RaiseError:
    201         raise FatalError(ErrorCode)
    202 
    203 # Log information which should be always put out

    204 quiet   = _ErrorLogger.error
    205 
    206 ## Initialize log system

    207 def Initialize():
    208     #

    209     # Since we use different format to log different levels of message into different

    210     # place (stdout or stderr), we have to use different "Logger" objects to do this.

    211     #

    212     # For DEBUG level (All DEBUG_0~9 are applicable)

    213     _DebugLogger.setLevel(INFO)
    214     _DebugChannel = logging.StreamHandler(sys.stdout)
    215     _DebugChannel.setFormatter(_DebugFormatter)
    216     _DebugLogger.addHandler(_DebugChannel)
    217 
    218     # For VERBOSE, INFO, WARN level

    219     _InfoLogger.setLevel(INFO)
    220     _InfoChannel = logging.StreamHandler(sys.stdout)
    221     _InfoChannel.setFormatter(_InfoFormatter)
    222     _InfoLogger.addHandler(_InfoChannel)
    223 
    224     # For ERROR level

    225     _ErrorLogger.setLevel(INFO)
    226     _ErrorCh = logging.StreamHandler(sys.stderr)
    227     _ErrorCh.setFormatter(_ErrorFormatter)
    228     _ErrorLogger.addHandler(_ErrorCh)
    229 
    230 ## Set log level

    231 #

    232 #   @param  Level   One of log level in _LogLevel

    233 def SetLevel(Level):
    234     if Level not in _LogLevels:
    235         info("Not supported log level (%d). Use default level instead." % Level)
    236         Level = INFO
    237     _DebugLogger.setLevel(Level)
    238     _InfoLogger.setLevel(Level)
    239     _ErrorLogger.setLevel(Level)
    240 
    241 def InitializeForUnitTest():
    242     Initialize()
    243     SetLevel(SILENT)
    244 
    245 ## Get current log level

    246 def GetLevel():
    247     return _InfoLogger.getEffectiveLevel()
    248 
    249 ## Raise up warning as error

    250 def SetWarningAsError():
    251     global _WarningAsError
    252     _WarningAsError = True
    253 
    254 ## Specify a file to store the log message as well as put on console

    255 #

    256 #   @param  LogFile     The file path used to store the log message

    257 #

    258 def SetLogFile(LogFile):
    259     if os.path.exists(LogFile):
    260         os.remove(LogFile)
    261 
    262     _Ch = logging.FileHandler(LogFile)
    263     _Ch.setFormatter(_DebugFormatter)
    264     _DebugLogger.addHandler(_Ch)
    265 
    266     _Ch= logging.FileHandler(LogFile)
    267     _Ch.setFormatter(_InfoFormatter)
    268     _InfoLogger.addHandler(_Ch)
    269 
    270     _Ch = logging.FileHandler(LogFile)
    271     _Ch.setFormatter(_ErrorFormatter)
    272     _ErrorLogger.addHandler(_Ch)
    273 
    274 if __name__ == '__main__':
    275     pass
    276 
    277