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