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