2 # This file implements the log mechanism for Python tools.
4 # Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
6 # SPDX-License-Identifier: BSD-2-Clause-Patent
15 from sys
import stdout
16 from sys
import stderr
19 from logging
import getLogger
20 from logging
import Formatter
21 from logging
import StreamHandler
22 from logging
import FileHandler
23 from traceback
import extract_stack
25 from Logger
.ToolError
import FatalError
26 from Logger
.ToolError
import WARNING_AS_ERROR
27 from Logger
.ToolError
import gERROR_MESSAGE
28 from Logger
.ToolError
import UNKNOWN_ERROR
29 from Library
import GlobalData
58 _TOOL_NAME
= os
.path
.basename(argv
[0])
60 # For validation purpose
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
, \
66 # For DEBUG level (All DEBUG_0~9 are applicable)
68 _DEBUG_LOGGER
= getLogger("tool_debug")
69 _DEBUG_FORMATTER
= Formatter("[%(asctime)s.%(msecs)d]: %(message)s", \
72 # For VERBOSE, INFO, WARN level
74 _INFO_LOGGER
= getLogger("tool_info")
75 _INFO_FORMATTER
= Formatter("%(message)s")
79 _ERROR_LOGGER
= getLogger("tool_error")
80 _ERROR_FORMATTER
= Formatter("%(message)s")
83 # String templates for ERROR/WARN/DEBUG log message
85 _ERROR_MESSAGE_TEMPLATE
= \
86 ('\n\n%(tool)s...\n%(file)s(%(line)s): error %(errorcode)04X: %(msg)s\n\t%(extra)s')
88 __ERROR_MESSAGE_TEMPLATE_WITHOUT_FILE
= \
89 '\n\n%(tool)s...\n : error %(errorcode)04X: %(msg)s\n\t%(extra)s'
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'
99 #Info = _INFO_LOGGER.info
101 def Info(msg
, *args
, **kwargs
):
102 _INFO_LOGGER
.info(msg
, *args
, **kwargs
)
105 # Log information which should be always put out
107 def Quiet(msg
, *args
, **kwargs
):
108 _ERROR_LOGGER
.error(msg
, *args
, **kwargs
)
112 # @param Level DEBUG level (DEBUG0~9)
113 # @param Message Debug information
114 # @param ExtraData More information associated with "Message"
116 def Debug(Level
, Message
, ExtraData
=None):
117 if _DEBUG_LOGGER
.level
> Level
:
122 # Find out the caller method information
124 CallerStack
= extract_stack()[-2]
126 "file" : CallerStack
[0],
127 "line" : CallerStack
[1],
131 if ExtraData
is not None:
132 LogText
= _DEBUG_MESSAGE_TEMPLATE
% TemplateDict
+ "\n %s" % ExtraData
134 LogText
= _DEBUG_MESSAGE_TEMPLATE
% TemplateDict
136 _DEBUG_LOGGER
.log(Level
, LogText
)
138 ## Log verbose message
140 # @param Message Verbose information
142 def Verbose(Message
):
143 return _INFO_LOGGER
.log(VERBOSE
, Message
)
145 ## Log warning message
147 # Warning messages are those which might be wrong but won't fail the tool.
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"
156 def Warn(ToolName
, Message
, File
=None, Line
=None, ExtraData
=None):
157 if _INFO_LOGGER
.level
> WARN
:
160 # if no tool name given, use caller's source file name as tool name
162 if ToolName
is None or ToolName
== "":
163 ToolName
= os
.path
.basename(extract_stack()[-2][0])
178 LogText
= _WARNING_MESSAGE_TEMPLATE
% TemplateDict
180 LogText
= _WARNING_MESSAGE_TEMPLATE_WITHOUT_FILE
% TemplateDict
182 if ExtraData
is not None:
183 LogText
+= "\n %s" % ExtraData
185 _INFO_LOGGER
.log(WARN
, LogText
)
187 # Raise an exception if indicated
189 if GlobalData
.gWARNING_AS_ERROR
== True:
190 raise FatalError(WARNING_AS_ERROR
)
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.
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.
208 def Error(ToolName
, ErrorCode
, Message
=None, File
=None, Line
=None, \
209 ExtraData
=None, RaiseError
=IS_RAISE_ERROR
):
218 if ErrorCode
in gERROR_MESSAGE
:
219 Message
= gERROR_MESSAGE
[ErrorCode
]
221 Message
= gERROR_MESSAGE
[UNKNOWN_ERROR
]
223 if ExtraData
is None:
230 "errorcode" : ErrorCode
,
236 LogText
= _ERROR_MESSAGE_TEMPLATE
% TemplateDict
238 LogText
= __ERROR_MESSAGE_TEMPLATE_WITHOUT_FILE
% TemplateDict
240 if not SUPRESS_ERROR
:
241 _ERROR_LOGGER
.log(ERROR
, LogText
)
243 raise FatalError(ErrorCode
)
246 ## Initialize log system
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.
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
)
260 # For VERBOSE, INFO, WARN level
262 _INFO_LOGGER
.setLevel(INFO
)
263 _InfoChannel
= StreamHandler(stdout
)
264 _InfoChannel
.setFormatter(_INFO_FORMATTER
)
265 _INFO_LOGGER
.addHandler(_InfoChannel
)
269 _ERROR_LOGGER
.setLevel(INFO
)
270 _ErrorCh
= StreamHandler(stderr
)
271 _ErrorCh
.setFormatter(_ERROR_FORMATTER
)
272 _ERROR_LOGGER
.addHandler(_ErrorCh
)
277 # @param Level One of log level in _LogLevel
280 if Level
not in _LOG_LEVELS
:
281 Info("Not supported log level (%d). Use default level instead." % \
284 _DEBUG_LOGGER
.setLevel(Level
)
285 _INFO_LOGGER
.setLevel(Level
)
286 _ERROR_LOGGER
.setLevel(Level
)
288 ## Get current log level
291 return _INFO_LOGGER
.getEffectiveLevel()
293 ## Raise up warning as error
295 def SetWarningAsError():
296 GlobalData
.gWARNING_AS_ERROR
= True
298 ## Specify a file to store the log message as well as put on console
300 # @param LogFile The file path used to store the log message
302 def SetLogFile(LogFile
):
303 if os
.path
.exists(LogFile
):
306 _Ch
= FileHandler(LogFile
)
307 _Ch
.setFormatter(_DEBUG_FORMATTER
)
308 _DEBUG_LOGGER
.addHandler(_Ch
)
310 _Ch
= FileHandler(LogFile
)
311 _Ch
.setFormatter(_INFO_FORMATTER
)
312 _INFO_LOGGER
.addHandler(_Ch
)
314 _Ch
= FileHandler(LogFile
)
315 _Ch
.setFormatter(_ERROR_FORMATTER
)
316 _ERROR_LOGGER
.addHandler(_Ch
)