2 # This file implements the log mechanism for Python tools.
4 # Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
5 # SPDX-License-Identifier: BSD-2-Clause-Patent
9 from __future__
import absolute_import
10 import Common
.LongFilePathOs
as os
, sys
, logging
12 from .BuildToolError
import *
13 import logging
.handlers
15 ## Log level constants
36 _ToolName
= os
.path
.basename(sys
.argv
[0])
38 # For validation purpose
39 _LogLevels
= [DEBUG_0
, DEBUG_1
, DEBUG_2
, DEBUG_3
, DEBUG_4
, DEBUG_5
,
40 DEBUG_6
, DEBUG_7
, DEBUG_8
, DEBUG_9
, VERBOSE
, WARN
, INFO
,
43 # For DEBUG level (All DEBUG_0~9 are applicable)
44 _DebugLogger
= logging
.getLogger("tool_debug")
45 _DebugFormatter
= logging
.Formatter("[%(asctime)s.%(msecs)d]: %(message)s", datefmt
="%H:%M:%S")
47 # For VERBOSE, INFO, WARN level
48 _InfoLogger
= logging
.getLogger("tool_info")
49 _InfoFormatter
= logging
.Formatter("%(message)s")
52 _ErrorLogger
= logging
.getLogger("tool_error")
53 _ErrorFormatter
= logging
.Formatter("%(message)s")
55 # String templates for ERROR/WARN/DEBUG log message
56 _ErrorMessageTemplate
= '\n\n%(tool)s...\n%(file)s(%(line)s): error %(errorcode)04X: %(msg)s\n\t%(extra)s'
57 _ErrorMessageTemplateWithoutFile
= '\n\n%(tool)s...\n : error %(errorcode)04X: %(msg)s\n\t%(extra)s'
58 _WarningMessageTemplate
= '%(tool)s...\n%(file)s(%(line)s): warning: %(msg)s'
59 _WarningMessageTemplateWithoutFile
= '%(tool)s: : warning: %(msg)s'
60 _DebugMessageTemplate
= '%(file)s(%(line)s): debug: \n %(msg)s'
63 # Flag used to take WARN as ERROR.
64 # By default, only ERROR message will break the tools execution.
66 _WarningAsError
= False
70 # @param Level DEBUG level (DEBUG0~9)
71 # @param Message Debug information
72 # @param ExtraData More information associated with "Message"
74 def debug(Level
, Message
, ExtraData
=None):
75 if _DebugLogger
.level
> Level
:
80 # Find out the caller method information
81 CallerStack
= traceback
.extract_stack()[-2]
83 "file" : CallerStack
[0],
84 "line" : CallerStack
[1],
88 if ExtraData
is not None:
89 LogText
= _DebugMessageTemplate
% TemplateDict
+ "\n %s" % ExtraData
91 LogText
= _DebugMessageTemplate
% TemplateDict
93 _DebugLogger
.log(Level
, LogText
)
95 ## Log verbose message
97 # @param Message Verbose information
100 return _InfoLogger
.log(VERBOSE
, Message
)
102 ## Log warning message
104 # Warning messages are those which might be wrong but won't fail the tool.
106 # @param ToolName The name of the tool. If not given, the name of caller
107 # method will be used.
108 # @param Message Warning information
109 # @param File The name of file which caused the warning.
110 # @param Line The line number in the "File" which caused the warning.
111 # @param ExtraData More information associated with "Message"
113 def warn(ToolName
, Message
, File
=None, Line
=None, ExtraData
=None):
114 if _InfoLogger
.level
> WARN
:
117 # if no tool name given, use caller's source file name as tool name
118 if ToolName
is None or ToolName
== "":
119 ToolName
= os
.path
.basename(traceback
.extract_stack()[-2][0])
134 LogText
= _WarningMessageTemplate
% TemplateDict
136 LogText
= _WarningMessageTemplateWithoutFile
% TemplateDict
138 if ExtraData
is not None:
139 LogText
+= "\n %s" % ExtraData
141 _InfoLogger
.log(WARN
, LogText
)
143 # Raise an exception if indicated
144 if _WarningAsError
== True:
145 raise FatalError(WARNING_AS_ERROR
)
148 info
= _InfoLogger
.info
152 # Once an error messages is logged, the tool's execution will be broken by raising
153 # an exception. If you don't want to break the execution later, you can give
154 # "RaiseError" with "False" value.
156 # @param ToolName The name of the tool. If not given, the name of caller
157 # method will be used.
158 # @param ErrorCode The error code
159 # @param Message Warning information
160 # @param File The name of file which caused the error.
161 # @param Line The line number in the "File" which caused the warning.
162 # @param ExtraData More information associated with "Message"
163 # @param RaiseError Raise an exception to break the tool's execution if
164 # it's True. This is the default behavior.
166 def error(ToolName
, ErrorCode
, Message
=None, File
=None, Line
=None, ExtraData
=None, RaiseError
=IsRaiseError
):
173 if ErrorCode
in gErrorMessage
:
174 Message
= gErrorMessage
[ErrorCode
]
176 Message
= gErrorMessage
[UNKNOWN_ERROR
]
178 if ExtraData
is None:
185 "errorcode" : ErrorCode
,
191 LogText
= _ErrorMessageTemplate
% TemplateDict
193 LogText
= _ErrorMessageTemplateWithoutFile
% TemplateDict
195 _ErrorLogger
.log(ERROR
, LogText
)
197 if RaiseError
and IsRaiseError
:
198 raise FatalError(ErrorCode
)
200 # Log information which should be always put out
201 quiet
= _ErrorLogger
.error
203 ## Initialize log system
204 def LogClientInitialize(log_q
):
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.
209 # For DEBUG level (All DEBUG_0~9 are applicable)
210 _DebugLogger
.setLevel(INFO
)
211 _DebugChannel
= logging
.handlers
.QueueHandler(log_q
)
212 _DebugChannel
.setFormatter(_DebugFormatter
)
213 _DebugLogger
.addHandler(_DebugChannel
)
215 # For VERBOSE, INFO, WARN level
216 _InfoLogger
.setLevel(INFO
)
217 _InfoChannel
= logging
.handlers
.QueueHandler(log_q
)
218 _InfoChannel
.setFormatter(_InfoFormatter
)
219 _InfoLogger
.addHandler(_InfoChannel
)
222 _ErrorLogger
.setLevel(INFO
)
223 _ErrorCh
= logging
.handlers
.QueueHandler(log_q
)
224 _ErrorCh
.setFormatter(_ErrorFormatter
)
225 _ErrorLogger
.addHandler(_ErrorCh
)
229 # @param Level One of log level in _LogLevel
231 if Level
not in _LogLevels
:
232 info("Not supported log level (%d). Use default level instead." % Level
)
234 _DebugLogger
.setLevel(Level
)
235 _InfoLogger
.setLevel(Level
)
236 _ErrorLogger
.setLevel(Level
)
238 ## Initialize log system
241 # Since we use different format to log different levels of message into different
242 # place (stdout or stderr), we have to use different "Logger" objects to do this.
244 # For DEBUG level (All DEBUG_0~9 are applicable)
245 _DebugLogger
.setLevel(INFO
)
246 _DebugChannel
= logging
.StreamHandler(sys
.stdout
)
247 _DebugChannel
.setFormatter(_DebugFormatter
)
248 _DebugLogger
.addHandler(_DebugChannel
)
250 # For VERBOSE, INFO, WARN level
251 _InfoLogger
.setLevel(INFO
)
252 _InfoChannel
= logging
.StreamHandler(sys
.stdout
)
253 _InfoChannel
.setFormatter(_InfoFormatter
)
254 _InfoLogger
.addHandler(_InfoChannel
)
257 _ErrorLogger
.setLevel(INFO
)
258 _ErrorCh
= logging
.StreamHandler(sys
.stderr
)
259 _ErrorCh
.setFormatter(_ErrorFormatter
)
260 _ErrorLogger
.addHandler(_ErrorCh
)
262 def InitializeForUnitTest():
266 ## Get current log level
268 return _InfoLogger
.getEffectiveLevel()
270 ## Raise up warning as error
271 def SetWarningAsError():
272 global _WarningAsError
273 _WarningAsError
= True
275 ## Specify a file to store the log message as well as put on console
277 # @param LogFile The file path used to store the log message
279 def SetLogFile(LogFile
):
280 if os
.path
.exists(LogFile
):
283 _Ch
= logging
.FileHandler(LogFile
)
284 _Ch
.setFormatter(_DebugFormatter
)
285 _DebugLogger
.addHandler(_Ch
)
287 _Ch
= logging
.FileHandler(LogFile
)
288 _Ch
.setFormatter(_InfoFormatter
)
289 _InfoLogger
.addHandler(_Ch
)
291 _Ch
= logging
.FileHandler(LogFile
)
292 _Ch
.setFormatter(_ErrorFormatter
)
293 _ErrorLogger
.addHandler(_Ch
)
295 if __name__
== '__main__':