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