1## @file 2# This file implements the log mechanism for Python tools. 3# 4# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> 5# 6# SPDX-License-Identifier: BSD-2-Clause-Patent 7# 8 9''' 10Logger 11''' 12 13## Import modules 14from sys import argv 15from sys import stdout 16from sys import stderr 17import os.path 18from os import remove 19from logging import getLogger 20from logging import Formatter 21from logging import StreamHandler 22from logging import FileHandler 23from traceback import extract_stack 24 25from Logger.ToolError import FatalError 26from Logger.ToolError import WARNING_AS_ERROR 27from Logger.ToolError import gERROR_MESSAGE 28from Logger.ToolError import UNKNOWN_ERROR 29from Library import GlobalData 30 31# 32# Log level constants 33# 34DEBUG_0 = 1 35DEBUG_1 = 2 36DEBUG_2 = 3 37DEBUG_3 = 4 38DEBUG_4 = 5 39DEBUG_5 = 6 40DEBUG_6 = 7 41DEBUG_7 = 8 42DEBUG_8 = 9 43DEBUG_9 = 10 44VERBOSE = 15 45INFO = 20 46WARN = 30 47QUIET = 40 48QUIET_1 = 41 49ERROR = 50 50SILENT = 60 51 52IS_RAISE_ERROR = True 53SUPRESS_ERROR = False 54 55# 56# Tool name 57# 58_TOOL_NAME = os.path.basename(argv[0]) 59# 60# For validation purpose 61# 62_LOG_LEVELS = [DEBUG_0, DEBUG_1, DEBUG_2, DEBUG_3, DEBUG_4, DEBUG_5, DEBUG_6, \ 63 DEBUG_7, DEBUG_8, DEBUG_9, VERBOSE, WARN, INFO, ERROR, QUIET, \ 64 QUIET_1, SILENT] 65# 66# For DEBUG level (All DEBUG_0~9 are applicable) 67# 68_DEBUG_LOGGER = getLogger("tool_debug") 69_DEBUG_FORMATTER = Formatter("[%(asctime)s.%(msecs)d]: %(message)s", \ 70 datefmt="%H:%M:%S") 71# 72# For VERBOSE, INFO, WARN level 73# 74_INFO_LOGGER = getLogger("tool_info") 75_INFO_FORMATTER = Formatter("%(message)s") 76# 77# For ERROR level 78# 79_ERROR_LOGGER = getLogger("tool_error") 80_ERROR_FORMATTER = Formatter("%(message)s") 81 82# 83# String templates for ERROR/WARN/DEBUG log message 84# 85_ERROR_MESSAGE_TEMPLATE = \ 86('\n\n%(tool)s...\n%(file)s(%(line)s): error %(errorcode)04X: %(msg)s\n\t%(extra)s') 87 88__ERROR_MESSAGE_TEMPLATE_WITHOUT_FILE = \ 89'\n\n%(tool)s...\n : error %(errorcode)04X: %(msg)s\n\t%(extra)s' 90 91_WARNING_MESSAGE_TEMPLATE = '%(tool)s...\n%(file)s(%(line)s): warning: %(msg)s' 92_WARNING_MESSAGE_TEMPLATE_WITHOUT_FILE = '%(tool)s: : warning: %(msg)s' 93_DEBUG_MESSAGE_TEMPLATE = '%(file)s(%(line)s): debug: \n %(msg)s' 94 95 96# 97# Log INFO message 98# 99#Info = _INFO_LOGGER.info 100 101def Info(msg, *args, **kwargs): 102 _INFO_LOGGER.info(msg, *args, **kwargs) 103 104# 105# Log information which should be always put out 106# 107def Quiet(msg, *args, **kwargs): 108 _ERROR_LOGGER.error(msg, *args, **kwargs) 109 110## Log debug message 111# 112# @param Level DEBUG level (DEBUG0~9) 113# @param Message Debug information 114# @param ExtraData More information associated with "Message" 115# 116def Debug(Level, Message, ExtraData=None): 117 if _DEBUG_LOGGER.level > Level: 118 return 119 if Level > DEBUG_9: 120 return 121 # 122 # Find out the caller method information 123 # 124 CallerStack = extract_stack()[-2] 125 TemplateDict = { 126 "file" : CallerStack[0], 127 "line" : CallerStack[1], 128 "msg" : Message, 129 } 130 131 if ExtraData is not None: 132 LogText = _DEBUG_MESSAGE_TEMPLATE % TemplateDict + "\n %s" % ExtraData 133 else: 134 LogText = _DEBUG_MESSAGE_TEMPLATE % TemplateDict 135 136 _DEBUG_LOGGER.log(Level, LogText) 137 138## Log verbose message 139# 140# @param Message Verbose information 141# 142def Verbose(Message): 143 return _INFO_LOGGER.log(VERBOSE, Message) 144 145## Log warning message 146# 147# Warning messages are those which might be wrong but won't fail the tool. 148# 149# @param ToolName The name of the tool. If not given, the name of caller 150# method will be used. 151# @param Message Warning information 152# @param File The name of file which caused the warning. 153# @param Line The line number in the "File" which caused the warning. 154# @param ExtraData More information associated with "Message" 155# 156def Warn(ToolName, Message, File=None, Line=None, ExtraData=None): 157 if _INFO_LOGGER.level > WARN: 158 return 159 # 160 # if no tool name given, use caller's source file name as tool name 161 # 162 if ToolName is None or ToolName == "": 163 ToolName = os.path.basename(extract_stack()[-2][0]) 164 165 if Line is None: 166 Line = "..." 167 else: 168 Line = "%d" % Line 169 170 TemplateDict = { 171 "tool" : ToolName, 172 "file" : File, 173 "line" : Line, 174 "msg" : Message, 175 } 176 177 if File is not None: 178 LogText = _WARNING_MESSAGE_TEMPLATE % TemplateDict 179 else: 180 LogText = _WARNING_MESSAGE_TEMPLATE_WITHOUT_FILE % TemplateDict 181 182 if ExtraData is not None: 183 LogText += "\n %s" % ExtraData 184 185 _INFO_LOGGER.log(WARN, LogText) 186 # 187 # Raise an exception if indicated 188 # 189 if GlobalData.gWARNING_AS_ERROR == True: 190 raise FatalError(WARNING_AS_ERROR) 191 192## Log ERROR message 193# 194# Once an error messages is logged, the tool's execution will be broken by 195# raising an exception. If you don't want to break the execution later, you 196# can give "RaiseError" with "False" value. 197# 198# @param ToolName The name of the tool. If not given, the name of caller 199# method will be used. 200# @param ErrorCode The error code 201# @param Message Warning information 202# @param File The name of file which caused the error. 203# @param Line The line number in the "File" which caused the warning. 204# @param ExtraData More information associated with "Message" 205# @param RaiseError Raise an exception to break the tool's execution if 206# it's True. This is the default behavior. 207# 208def Error(ToolName, ErrorCode, Message=None, File=None, Line=None, \ 209 ExtraData=None, RaiseError=IS_RAISE_ERROR): 210 if ToolName: 211 pass 212 if Line is None: 213 Line = "..." 214 else: 215 Line = "%d" % Line 216 217 if Message is None: 218 if ErrorCode in gERROR_MESSAGE: 219 Message = gERROR_MESSAGE[ErrorCode] 220 else: 221 Message = gERROR_MESSAGE[UNKNOWN_ERROR] 222 223 if ExtraData is None: 224 ExtraData = "" 225 226 TemplateDict = { 227 "tool" : _TOOL_NAME, 228 "file" : File, 229 "line" : Line, 230 "errorcode" : ErrorCode, 231 "msg" : Message, 232 "extra" : ExtraData 233 } 234 235 if File is not None: 236 LogText = _ERROR_MESSAGE_TEMPLATE % TemplateDict 237 else: 238 LogText = __ERROR_MESSAGE_TEMPLATE_WITHOUT_FILE % TemplateDict 239 240 if not SUPRESS_ERROR: 241 _ERROR_LOGGER.log(ERROR, LogText) 242 if RaiseError: 243 raise FatalError(ErrorCode) 244 245 246## Initialize log system 247# 248def Initialize(): 249 # 250 # Since we use different format to log different levels of message into 251 # different place (stdout or stderr), we have to use different "Logger" 252 # objects to do this. 253 # 254 # For DEBUG level (All DEBUG_0~9 are applicable) 255 _DEBUG_LOGGER.setLevel(INFO) 256 _DebugChannel = StreamHandler(stdout) 257 _DebugChannel.setFormatter(_DEBUG_FORMATTER) 258 _DEBUG_LOGGER.addHandler(_DebugChannel) 259 # 260 # For VERBOSE, INFO, WARN level 261 # 262 _INFO_LOGGER.setLevel(INFO) 263 _InfoChannel = StreamHandler(stdout) 264 _InfoChannel.setFormatter(_INFO_FORMATTER) 265 _INFO_LOGGER.addHandler(_InfoChannel) 266 # 267 # For ERROR level 268 # 269 _ERROR_LOGGER.setLevel(INFO) 270 _ErrorCh = StreamHandler(stderr) 271 _ErrorCh.setFormatter(_ERROR_FORMATTER) 272 _ERROR_LOGGER.addHandler(_ErrorCh) 273 274 275## Set log level 276# 277# @param Level One of log level in _LogLevel 278# 279def SetLevel(Level): 280 if Level not in _LOG_LEVELS: 281 Info("Not supported log level (%d). Use default level instead." % \ 282 Level) 283 Level = INFO 284 _DEBUG_LOGGER.setLevel(Level) 285 _INFO_LOGGER.setLevel(Level) 286 _ERROR_LOGGER.setLevel(Level) 287 288## Get current log level 289# 290def GetLevel(): 291 return _INFO_LOGGER.getEffectiveLevel() 292 293## Raise up warning as error 294# 295def SetWarningAsError(): 296 GlobalData.gWARNING_AS_ERROR = True 297 298## Specify a file to store the log message as well as put on console 299# 300# @param LogFile The file path used to store the log message 301# 302def SetLogFile(LogFile): 303 if os.path.exists(LogFile): 304 remove(LogFile) 305 306 _Ch = FileHandler(LogFile) 307 _Ch.setFormatter(_DEBUG_FORMATTER) 308 _DEBUG_LOGGER.addHandler(_Ch) 309 310 _Ch = FileHandler(LogFile) 311 _Ch.setFormatter(_INFO_FORMATTER) 312 _INFO_LOGGER.addHandler(_Ch) 313 314 _Ch = FileHandler(LogFile) 315 _Ch.setFormatter(_ERROR_FORMATTER) 316 _ERROR_LOGGER.addHandler(_Ch) 317 318 319 320