1## @file 2# This file implements the log mechanism for Python tools. 3# 4# Copyright (c) 2007 - 2014, 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 35 36IsRaiseError = True 37 38# Tool name 39_ToolName = os.path.basename(sys.argv[0]) 40 41# For validation purpose 42_LogLevels = [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] 43 44# For DEBUG level (All DEBUG_0~9 are applicable) 45_DebugLogger = logging.getLogger("tool_debug") 46_DebugFormatter = logging.Formatter("[%(asctime)s.%(msecs)d]: %(message)s", datefmt="%H:%M:%S") 47 48# For VERBOSE, INFO, WARN level 49_InfoLogger = logging.getLogger("tool_info") 50_InfoFormatter = logging.Formatter("%(message)s") 51 52# For ERROR level 53_ErrorLogger = logging.getLogger("tool_error") 54_ErrorFormatter = logging.Formatter("%(message)s") 55 56# String templates for ERROR/WARN/DEBUG log message 57_ErrorMessageTemplate = '\n\n%(tool)s...\n%(file)s(%(line)s): error %(errorcode)04X: %(msg)s\n\t%(extra)s' 58_ErrorMessageTemplateWithoutFile = '\n\n%(tool)s...\n : error %(errorcode)04X: %(msg)s\n\t%(extra)s' 59_WarningMessageTemplate = '%(tool)s...\n%(file)s(%(line)s): warning: %(msg)s' 60_WarningMessageTemplateWithoutFile = '%(tool)s: : warning: %(msg)s' 61_DebugMessageTemplate = '%(file)s(%(line)s): debug: \n %(msg)s' 62 63# 64# Flag used to take WARN as ERROR. 65# By default, only ERROR message will break the tools execution. 66# 67_WarningAsError = False 68 69## Log debug message 70# 71# @param Level DEBUG level (DEBUG0~9) 72# @param Message Debug information 73# @param ExtraData More information associated with "Message" 74# 75def debug(Level, Message, ExtraData=None): 76 if _DebugLogger.level > Level: 77 return 78 if Level > DEBUG_9: 79 return 80 81 # Find out the caller method information 82 CallerStack = traceback.extract_stack()[-2] 83 TemplateDict = { 84 "file" : CallerStack[0], 85 "line" : CallerStack[1], 86 "msg" : Message, 87 } 88 89 if ExtraData != None: 90 LogText = _DebugMessageTemplate % TemplateDict + "\n %s" % ExtraData 91 else: 92 LogText = _DebugMessageTemplate % TemplateDict 93 94 _DebugLogger.log(Level, LogText) 95 96## Log verbose message 97# 98# @param Message Verbose information 99# 100def verbose(Message): 101 return _InfoLogger.log(VERBOSE, Message) 102 103## Log warning message 104# 105# Warning messages are those which might be wrong but won't fail the tool. 106# 107# @param ToolName The name of the tool. If not given, the name of caller 108# method will be used. 109# @param Message Warning information 110# @param File The name of file which caused the warning. 111# @param Line The line number in the "File" which caused the warning. 112# @param ExtraData More information associated with "Message" 113# 114def warn(ToolName, Message, File=None, Line=None, ExtraData=None): 115 if _InfoLogger.level > WARN: 116 return 117 118 # if no tool name given, use caller's source file name as tool name 119 if ToolName == None or ToolName == "": 120 ToolName = os.path.basename(traceback.extract_stack()[-2][0]) 121 122 if Line == None: 123 Line = "..." 124 else: 125 Line = "%d" % Line 126 127 TemplateDict = { 128 "tool" : ToolName, 129 "file" : File, 130 "line" : Line, 131 "msg" : Message, 132 } 133 134 if File != None: 135 LogText = _WarningMessageTemplate % TemplateDict 136 else: 137 LogText = _WarningMessageTemplateWithoutFile % TemplateDict 138 139 if ExtraData != None: 140 LogText += "\n %s" % ExtraData 141 142 _InfoLogger.log(WARN, LogText) 143 144 # Raise an execption if indicated 145 if _WarningAsError == True: 146 raise FatalError(WARNING_AS_ERROR) 147 148## Log INFO message 149info = _InfoLogger.info 150 151## Log ERROR message 152# 153# Once an error messages is logged, the tool's execution will be broken by raising 154# an execption. If you don't want to break the execution later, you can give 155# "RaiseError" with "False" value. 156# 157# @param ToolName The name of the tool. If not given, the name of caller 158# method will be used. 159# @param ErrorCode The error code 160# @param Message Warning information 161# @param File The name of file which caused the error. 162# @param Line The line number in the "File" which caused the warning. 163# @param ExtraData More information associated with "Message" 164# @param RaiseError Raise an exception to break the tool's executuion if 165# it's True. This is the default behavior. 166# 167def error(ToolName, ErrorCode, Message=None, File=None, Line=None, ExtraData=None, RaiseError=IsRaiseError): 168 if Line == None: 169 Line = "..." 170 else: 171 Line = "%d" % Line 172 173 if Message == None: 174 if ErrorCode in gErrorMessage: 175 Message = gErrorMessage[ErrorCode] 176 else: 177 Message = gErrorMessage[UNKNOWN_ERROR] 178 179 if ExtraData == None: 180 ExtraData = "" 181 182 TemplateDict = { 183 "tool" : _ToolName, 184 "file" : File, 185 "line" : Line, 186 "errorcode" : ErrorCode, 187 "msg" : Message, 188 "extra" : ExtraData 189 } 190 191 if File != None: 192 LogText = _ErrorMessageTemplate % TemplateDict 193 else: 194 LogText = _ErrorMessageTemplateWithoutFile % TemplateDict 195 196 _ErrorLogger.log(ERROR, LogText) 197 if RaiseError: 198 raise FatalError(ErrorCode) 199 200# Log information which should be always put out 201quiet = _ErrorLogger.error 202 203## Initialize log system 204def Initialize(): 205 # 206 # Since we use different format to log different levels of message into different 207 # place (stdout or stderr), we have to use different "Logger" objects to do this. 208 # 209 # For DEBUG level (All DEBUG_0~9 are applicable) 210 _DebugLogger.setLevel(INFO) 211 _DebugChannel = logging.StreamHandler(sys.stdout) 212 _DebugChannel.setFormatter(_DebugFormatter) 213 _DebugLogger.addHandler(_DebugChannel) 214 215 # For VERBOSE, INFO, WARN level 216 _InfoLogger.setLevel(INFO) 217 _InfoChannel = logging.StreamHandler(sys.stdout) 218 _InfoChannel.setFormatter(_InfoFormatter) 219 _InfoLogger.addHandler(_InfoChannel) 220 221 # For ERROR level 222 _ErrorLogger.setLevel(INFO) 223 _ErrorCh = logging.StreamHandler(sys.stderr) 224 _ErrorCh.setFormatter(_ErrorFormatter) 225 _ErrorLogger.addHandler(_ErrorCh) 226 227## Set log level 228# 229# @param Level One of log level in _LogLevel 230def SetLevel(Level): 231 if Level not in _LogLevels: 232 info("Not supported log level (%d). Use default level instead." % Level) 233 Level = INFO 234 _DebugLogger.setLevel(Level) 235 _InfoLogger.setLevel(Level) 236 _ErrorLogger.setLevel(Level) 237 238## Get current log level 239def GetLevel(): 240 return _InfoLogger.getEffectiveLevel() 241 242## Raise up warning as error 243def SetWarningAsError(): 244 global _WarningAsError 245 _WarningAsError = True 246 247## Specify a file to store the log message as well as put on console 248# 249# @param LogFile The file path used to store the log message 250# 251def SetLogFile(LogFile): 252 if os.path.exists(LogFile): 253 os.remove(LogFile) 254 255 _Ch = logging.FileHandler(LogFile) 256 _Ch.setFormatter(_DebugFormatter) 257 _DebugLogger.addHandler(_Ch) 258 259 _Ch= logging.FileHandler(LogFile) 260 _Ch.setFormatter(_InfoFormatter) 261 _InfoLogger.addHandler(_Ch) 262 263 _Ch = logging.FileHandler(LogFile) 264 _Ch.setFormatter(_ErrorFormatter) 265 _ErrorLogger.addHandler(_Ch) 266 267if __name__ == '__main__': 268 pass 269 270