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 15import Common.LongFilePathOs as os, sys, logging 16import traceback 17from BuildToolError import * 18 19## Log level constants 20DEBUG_0 = 1 21DEBUG_1 = 2 22DEBUG_2 = 3 23DEBUG_3 = 4 24DEBUG_4 = 5 25DEBUG_5 = 6 26DEBUG_6 = 7 27DEBUG_7 = 8 28DEBUG_8 = 9 29DEBUG_9 = 10 30VERBOSE = 15 31INFO = 20 32WARN = 30 33QUIET = 40 34ERROR = 50 35SILENT = 99 36 37IsRaiseError = 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# 78def 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# 103def 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# 117def 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 152info = _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# 170def 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 204quiet = _ErrorLogger.error 205 206## Initialize log system 207def 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 233def 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 241def InitializeForUnitTest(): 242 Initialize() 243 SetLevel(SILENT) 244 245## Get current log level 246def GetLevel(): 247 return _InfoLogger.getEffectiveLevel() 248 249## Raise up warning as error 250def 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# 258def 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 274if __name__ == '__main__': 275 pass 276 277