]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/UPT/Logger/Log.py
BaseTools: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / BaseTools / Source / Python / UPT / Logger / Log.py
CommitLineData
f51461c8
LG
1## @file\r
2# This file implements the log mechanism for Python tools.\r
3#\r
f7496d71 4# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
f51461c8 5#\r
2e351cbe 6# SPDX-License-Identifier: BSD-2-Clause-Patent\r
f51461c8
LG
7#\r
8\r
9'''\r
10Logger\r
11'''\r
12\r
13## Import modules\r
14from sys import argv\r
15from sys import stdout\r
16from sys import stderr\r
17import os.path\r
18from os import remove\r
19from logging import getLogger\r
20from logging import Formatter\r
21from logging import StreamHandler\r
22from logging import FileHandler\r
23from traceback import extract_stack\r
24\r
25from Logger.ToolError import FatalError\r
26from Logger.ToolError import WARNING_AS_ERROR\r
27from Logger.ToolError import gERROR_MESSAGE\r
28from Logger.ToolError import UNKNOWN_ERROR\r
29from Library import GlobalData\r
30\r
31#\r
32# Log level constants\r
33#\r
34DEBUG_0 = 1\r
35DEBUG_1 = 2\r
36DEBUG_2 = 3\r
37DEBUG_3 = 4\r
38DEBUG_4 = 5\r
39DEBUG_5 = 6\r
40DEBUG_6 = 7\r
41DEBUG_7 = 8\r
42DEBUG_8 = 9\r
43DEBUG_9 = 10\r
44VERBOSE = 15\r
45INFO = 20\r
46WARN = 30\r
47QUIET = 40\r
48QUIET_1 = 41\r
49ERROR = 50\r
50SILENT = 60\r
51\r
52IS_RAISE_ERROR = True\r
53SUPRESS_ERROR = False\r
54\r
55#\r
56# Tool name\r
57#\r
58_TOOL_NAME = os.path.basename(argv[0])\r
59#\r
60# For validation purpose\r
61#\r
62_LOG_LEVELS = [DEBUG_0, DEBUG_1, DEBUG_2, DEBUG_3, DEBUG_4, DEBUG_5, DEBUG_6, \\r
63 DEBUG_7, DEBUG_8, DEBUG_9, VERBOSE, WARN, INFO, ERROR, QUIET, \\r
64 QUIET_1, SILENT]\r
65#\r
66# For DEBUG level (All DEBUG_0~9 are applicable)\r
67#\r
68_DEBUG_LOGGER = getLogger("tool_debug")\r
69_DEBUG_FORMATTER = Formatter("[%(asctime)s.%(msecs)d]: %(message)s", \\r
70 datefmt="%H:%M:%S")\r
71#\r
72# For VERBOSE, INFO, WARN level\r
73#\r
74_INFO_LOGGER = getLogger("tool_info")\r
75_INFO_FORMATTER = Formatter("%(message)s")\r
76#\r
77# For ERROR level\r
78#\r
79_ERROR_LOGGER = getLogger("tool_error")\r
80_ERROR_FORMATTER = Formatter("%(message)s")\r
81\r
82#\r
83# String templates for ERROR/WARN/DEBUG log message\r
84#\r
85_ERROR_MESSAGE_TEMPLATE = \\r
86('\n\n%(tool)s...\n%(file)s(%(line)s): error %(errorcode)04X: %(msg)s\n\t%(extra)s')\r
87\r
88__ERROR_MESSAGE_TEMPLATE_WITHOUT_FILE = \\r
89'\n\n%(tool)s...\n : error %(errorcode)04X: %(msg)s\n\t%(extra)s'\r
90\r
91_WARNING_MESSAGE_TEMPLATE = '%(tool)s...\n%(file)s(%(line)s): warning: %(msg)s'\r
92_WARNING_MESSAGE_TEMPLATE_WITHOUT_FILE = '%(tool)s: : warning: %(msg)s'\r
93_DEBUG_MESSAGE_TEMPLATE = '%(file)s(%(line)s): debug: \n %(msg)s'\r
94\r
95\r
96#\r
97# Log INFO message\r
98#\r
99#Info = _INFO_LOGGER.info\r
100\r
101def Info(msg, *args, **kwargs):\r
102 _INFO_LOGGER.info(msg, *args, **kwargs)\r
103\r
104#\r
105# Log information which should be always put out\r
106#\r
107def Quiet(msg, *args, **kwargs):\r
108 _ERROR_LOGGER.error(msg, *args, **kwargs)\r
109\r
110## Log debug message\r
111#\r
112# @param Level DEBUG level (DEBUG0~9)\r
113# @param Message Debug information\r
114# @param ExtraData More information associated with "Message"\r
115#\r
116def Debug(Level, Message, ExtraData=None):\r
117 if _DEBUG_LOGGER.level > Level:\r
118 return\r
119 if Level > DEBUG_9:\r
120 return\r
121 #\r
122 # Find out the caller method information\r
123 #\r
124 CallerStack = extract_stack()[-2]\r
125 TemplateDict = {\r
126 "file" : CallerStack[0],\r
127 "line" : CallerStack[1],\r
128 "msg" : Message,\r
129 }\r
130\r
4231a819 131 if ExtraData is not None:\r
f51461c8
LG
132 LogText = _DEBUG_MESSAGE_TEMPLATE % TemplateDict + "\n %s" % ExtraData\r
133 else:\r
134 LogText = _DEBUG_MESSAGE_TEMPLATE % TemplateDict\r
135\r
136 _DEBUG_LOGGER.log(Level, LogText)\r
137\r
138## Log verbose message\r
139#\r
140# @param Message Verbose information\r
141#\r
142def Verbose(Message):\r
143 return _INFO_LOGGER.log(VERBOSE, Message)\r
144\r
145## Log warning message\r
146#\r
147# Warning messages are those which might be wrong but won't fail the tool.\r
148#\r
149# @param ToolName The name of the tool. If not given, the name of caller\r
150# method will be used.\r
151# @param Message Warning information\r
152# @param File The name of file which caused the warning.\r
153# @param Line The line number in the "File" which caused the warning.\r
154# @param ExtraData More information associated with "Message"\r
155#\r
156def Warn(ToolName, Message, File=None, Line=None, ExtraData=None):\r
157 if _INFO_LOGGER.level > WARN:\r
158 return\r
159 #\r
160 # if no tool name given, use caller's source file name as tool name\r
161 #\r
4231a819 162 if ToolName is None or ToolName == "":\r
f51461c8
LG
163 ToolName = os.path.basename(extract_stack()[-2][0])\r
164\r
4231a819 165 if Line is None:\r
f51461c8
LG
166 Line = "..."\r
167 else:\r
168 Line = "%d" % Line\r
169\r
170 TemplateDict = {\r
171 "tool" : ToolName,\r
172 "file" : File,\r
173 "line" : Line,\r
174 "msg" : Message,\r
175 }\r
176\r
4231a819 177 if File is not None:\r
f51461c8
LG
178 LogText = _WARNING_MESSAGE_TEMPLATE % TemplateDict\r
179 else:\r
180 LogText = _WARNING_MESSAGE_TEMPLATE_WITHOUT_FILE % TemplateDict\r
181\r
4231a819 182 if ExtraData is not None:\r
f51461c8
LG
183 LogText += "\n %s" % ExtraData\r
184\r
185 _INFO_LOGGER.log(WARN, LogText)\r
186 #\r
fb0b35e0 187 # Raise an exception if indicated\r
f51461c8
LG
188 #\r
189 if GlobalData.gWARNING_AS_ERROR == True:\r
190 raise FatalError(WARNING_AS_ERROR)\r
191\r
192## Log ERROR message\r
193#\r
f7496d71 194# Once an error messages is logged, the tool's execution will be broken by\r
fb0b35e0 195# raising an exception. If you don't want to break the execution later, you\r
f51461c8
LG
196# can give "RaiseError" with "False" value.\r
197#\r
198# @param ToolName The name of the tool. If not given, the name of caller\r
199# method will be used.\r
200# @param ErrorCode The error code\r
201# @param Message Warning information\r
202# @param File The name of file which caused the error.\r
203# @param Line The line number in the "File" which caused the warning.\r
204# @param ExtraData More information associated with "Message"\r
fb0b35e0 205# @param RaiseError Raise an exception to break the tool's execution if\r
f51461c8
LG
206# it's True. This is the default behavior.\r
207#\r
208def Error(ToolName, ErrorCode, Message=None, File=None, Line=None, \\r
209 ExtraData=None, RaiseError=IS_RAISE_ERROR):\r
210 if ToolName:\r
211 pass\r
4231a819 212 if Line is None:\r
f51461c8
LG
213 Line = "..."\r
214 else:\r
215 Line = "%d" % Line\r
216\r
4231a819 217 if Message is None:\r
f51461c8
LG
218 if ErrorCode in gERROR_MESSAGE:\r
219 Message = gERROR_MESSAGE[ErrorCode]\r
220 else:\r
221 Message = gERROR_MESSAGE[UNKNOWN_ERROR]\r
222\r
4231a819 223 if ExtraData is None:\r
f51461c8
LG
224 ExtraData = ""\r
225\r
226 TemplateDict = {\r
227 "tool" : _TOOL_NAME,\r
228 "file" : File,\r
229 "line" : Line,\r
230 "errorcode" : ErrorCode,\r
231 "msg" : Message,\r
232 "extra" : ExtraData\r
233 }\r
234\r
4231a819 235 if File is not None:\r
f51461c8
LG
236 LogText = _ERROR_MESSAGE_TEMPLATE % TemplateDict\r
237 else:\r
238 LogText = __ERROR_MESSAGE_TEMPLATE_WITHOUT_FILE % TemplateDict\r
239\r
240 if not SUPRESS_ERROR:\r
241 _ERROR_LOGGER.log(ERROR, LogText)\r
242 if RaiseError:\r
243 raise FatalError(ErrorCode)\r
244\r
f7496d71 245\r
f51461c8
LG
246## Initialize log system\r
247#\r
248def Initialize():\r
249 #\r
f7496d71
LG
250 # Since we use different format to log different levels of message into\r
251 # different place (stdout or stderr), we have to use different "Logger"\r
f51461c8
LG
252 # objects to do this.\r
253 #\r
254 # For DEBUG level (All DEBUG_0~9 are applicable)\r
255 _DEBUG_LOGGER.setLevel(INFO)\r
256 _DebugChannel = StreamHandler(stdout)\r
257 _DebugChannel.setFormatter(_DEBUG_FORMATTER)\r
258 _DEBUG_LOGGER.addHandler(_DebugChannel)\r
259 #\r
260 # For VERBOSE, INFO, WARN level\r
261 #\r
262 _INFO_LOGGER.setLevel(INFO)\r
263 _InfoChannel = StreamHandler(stdout)\r
264 _InfoChannel.setFormatter(_INFO_FORMATTER)\r
265 _INFO_LOGGER.addHandler(_InfoChannel)\r
266 #\r
267 # For ERROR level\r
268 #\r
269 _ERROR_LOGGER.setLevel(INFO)\r
270 _ErrorCh = StreamHandler(stderr)\r
271 _ErrorCh.setFormatter(_ERROR_FORMATTER)\r
272 _ERROR_LOGGER.addHandler(_ErrorCh)\r
273\r
274\r
275## Set log level\r
276#\r
277# @param Level One of log level in _LogLevel\r
278#\r
279def SetLevel(Level):\r
280 if Level not in _LOG_LEVELS:\r
281 Info("Not supported log level (%d). Use default level instead." % \\r
282 Level)\r
283 Level = INFO\r
284 _DEBUG_LOGGER.setLevel(Level)\r
285 _INFO_LOGGER.setLevel(Level)\r
286 _ERROR_LOGGER.setLevel(Level)\r
287\r
288## Get current log level\r
289#\r
290def GetLevel():\r
291 return _INFO_LOGGER.getEffectiveLevel()\r
292\r
293## Raise up warning as error\r
294#\r
295def SetWarningAsError():\r
296 GlobalData.gWARNING_AS_ERROR = True\r
297\r
298## Specify a file to store the log message as well as put on console\r
299#\r
300# @param LogFile The file path used to store the log message\r
301#\r
302def SetLogFile(LogFile):\r
303 if os.path.exists(LogFile):\r
304 remove(LogFile)\r
305\r
306 _Ch = FileHandler(LogFile)\r
307 _Ch.setFormatter(_DEBUG_FORMATTER)\r
308 _DEBUG_LOGGER.addHandler(_Ch)\r
309\r
310 _Ch = FileHandler(LogFile)\r
311 _Ch.setFormatter(_INFO_FORMATTER)\r
312 _INFO_LOGGER.addHandler(_Ch)\r
313\r
314 _Ch = FileHandler(LogFile)\r
315 _Ch.setFormatter(_ERROR_FORMATTER)\r
316 _ERROR_LOGGER.addHandler(_Ch)\r
317\r
318\r
319\r