]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/Common/EdkLogger.py
f6a5e3b4daf9e544ed06082048c6a62f056d8b94
[mirror_edk2.git] / BaseTools / Source / Python / Common / EdkLogger.py
1 ## @file
2 # This file implements the log mechanism for Python tools.
3 #
4 # Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
5 # SPDX-License-Identifier: BSD-2-Clause-Patent
6 #
7
8 ## Import modules
9 from __future__ import absolute_import
10 import Common.LongFilePathOs as os, sys, logging
11 import traceback
12 from .BuildToolError import *
13 import logging.handlers
14
15 ## Log level constants
16 DEBUG_0 = 1
17 DEBUG_1 = 2
18 DEBUG_2 = 3
19 DEBUG_3 = 4
20 DEBUG_4 = 5
21 DEBUG_5 = 6
22 DEBUG_6 = 7
23 DEBUG_7 = 8
24 DEBUG_8 = 9
25 DEBUG_9 = 10
26 VERBOSE = 15
27 INFO = 20
28 WARN = 30
29 QUIET = 40
30 ERROR = 50
31 SILENT = 99
32
33 IsRaiseError = True
34
35 # Tool name
36 _ToolName = os.path.basename(sys.argv[0])
37
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,
41 ERROR, QUIET, SILENT]
42
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")
46
47 # For VERBOSE, INFO, WARN level
48 _InfoLogger = logging.getLogger("tool_info")
49 _InfoFormatter = logging.Formatter("%(message)s")
50
51 # For ERROR level
52 _ErrorLogger = logging.getLogger("tool_error")
53 _ErrorFormatter = logging.Formatter("%(message)s")
54
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'
61
62 #
63 # Flag used to take WARN as ERROR.
64 # By default, only ERROR message will break the tools execution.
65 #
66 _WarningAsError = False
67
68 ## Log debug message
69 #
70 # @param Level DEBUG level (DEBUG0~9)
71 # @param Message Debug information
72 # @param ExtraData More information associated with "Message"
73 #
74 def debug(Level, Message, ExtraData=None):
75 if _DebugLogger.level > Level:
76 return
77 if Level > DEBUG_9:
78 return
79
80 # Find out the caller method information
81 CallerStack = traceback.extract_stack()[-2]
82 TemplateDict = {
83 "file" : CallerStack[0],
84 "line" : CallerStack[1],
85 "msg" : Message,
86 }
87
88 if ExtraData is not None:
89 LogText = _DebugMessageTemplate % TemplateDict + "\n %s" % ExtraData
90 else:
91 LogText = _DebugMessageTemplate % TemplateDict
92
93 _DebugLogger.log(Level, LogText)
94
95 ## Log verbose message
96 #
97 # @param Message Verbose information
98 #
99 def verbose(Message):
100 return _InfoLogger.log(VERBOSE, Message)
101
102 ## Log warning message
103 #
104 # Warning messages are those which might be wrong but won't fail the tool.
105 #
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"
112 #
113 def warn(ToolName, Message, File=None, Line=None, ExtraData=None):
114 if _InfoLogger.level > WARN:
115 return
116
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])
120
121 if Line is None:
122 Line = "..."
123 else:
124 Line = "%d" % Line
125
126 TemplateDict = {
127 "tool" : ToolName,
128 "file" : File,
129 "line" : Line,
130 "msg" : Message,
131 }
132
133 if File is not None:
134 LogText = _WarningMessageTemplate % TemplateDict
135 else:
136 LogText = _WarningMessageTemplateWithoutFile % TemplateDict
137
138 if ExtraData is not None:
139 LogText += "\n %s" % ExtraData
140
141 _InfoLogger.log(WARN, LogText)
142
143 # Raise an exception if indicated
144 if _WarningAsError == True:
145 raise FatalError(WARNING_AS_ERROR)
146
147 ## Log INFO message
148 info = _InfoLogger.info
149
150 ## Log ERROR message
151 #
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.
155 #
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.
165 #
166 def error(ToolName, ErrorCode, Message=None, File=None, Line=None, ExtraData=None, RaiseError=IsRaiseError):
167 if Line is None:
168 Line = "..."
169 else:
170 Line = "%d" % Line
171
172 if Message is None:
173 if ErrorCode in gErrorMessage:
174 Message = gErrorMessage[ErrorCode]
175 else:
176 Message = gErrorMessage[UNKNOWN_ERROR]
177
178 if ExtraData is None:
179 ExtraData = ""
180
181 TemplateDict = {
182 "tool" : _ToolName,
183 "file" : File,
184 "line" : Line,
185 "errorcode" : ErrorCode,
186 "msg" : Message,
187 "extra" : ExtraData
188 }
189
190 if File is not None:
191 LogText = _ErrorMessageTemplate % TemplateDict
192 else:
193 LogText = _ErrorMessageTemplateWithoutFile % TemplateDict
194
195 _ErrorLogger.log(ERROR, LogText)
196
197 if RaiseError and IsRaiseError:
198 raise FatalError(ErrorCode)
199
200 # Log information which should be always put out
201 quiet = _ErrorLogger.error
202
203 ## Initialize log system
204 def LogClientInitialize(log_q):
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.handlers.QueueHandler(log_q)
212 _DebugChannel.setFormatter(_DebugFormatter)
213 _DebugLogger.addHandler(_DebugChannel)
214
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)
220
221 # For ERROR level
222 _ErrorLogger.setLevel(INFO)
223 _ErrorCh = logging.handlers.QueueHandler(log_q)
224 _ErrorCh.setFormatter(_ErrorFormatter)
225 _ErrorLogger.addHandler(_ErrorCh)
226
227 ## Set log level
228 #
229 # @param Level One of log level in _LogLevel
230 def 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 ## Initialize log system
239 def Initialize():
240 #
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.
243 #
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)
249
250 # For VERBOSE, INFO, WARN level
251 _InfoLogger.setLevel(INFO)
252 _InfoChannel = logging.StreamHandler(sys.stdout)
253 _InfoChannel.setFormatter(_InfoFormatter)
254 _InfoLogger.addHandler(_InfoChannel)
255
256 # For ERROR level
257 _ErrorLogger.setLevel(INFO)
258 _ErrorCh = logging.StreamHandler(sys.stderr)
259 _ErrorCh.setFormatter(_ErrorFormatter)
260 _ErrorLogger.addHandler(_ErrorCh)
261
262 def InitializeForUnitTest():
263 Initialize()
264 SetLevel(SILENT)
265
266 ## Get current log level
267 def GetLevel():
268 return _InfoLogger.getEffectiveLevel()
269
270 ## Raise up warning as error
271 def SetWarningAsError():
272 global _WarningAsError
273 _WarningAsError = True
274
275 ## Specify a file to store the log message as well as put on console
276 #
277 # @param LogFile The file path used to store the log message
278 #
279 def SetLogFile(LogFile):
280 if os.path.exists(LogFile):
281 os.remove(LogFile)
282
283 _Ch = logging.FileHandler(LogFile)
284 _Ch.setFormatter(_DebugFormatter)
285 _DebugLogger.addHandler(_Ch)
286
287 _Ch= logging.FileHandler(LogFile)
288 _Ch.setFormatter(_InfoFormatter)
289 _InfoLogger.addHandler(_Ch)
290
291 _Ch = logging.FileHandler(LogFile)
292 _Ch.setFormatter(_ErrorFormatter)
293 _ErrorLogger.addHandler(_Ch)
294
295 if __name__ == '__main__':
296 pass
297