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