## @file\r
# This file implements the log mechanism for Python tools.\r
#\r
-# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>\r
-# This program and the accompanying materials\r
-# are licensed and made available under the terms and conditions of the BSD License\r
-# which accompanies this distribution. The full text of the license may be found at\r
-# http://opensource.org/licenses/bsd-license.php\r
+# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
#\r
-# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+# Copyright 2001-2016 by Vinay Sajip. All Rights Reserved.\r
#\r
+# Permission to use, copy, modify, and distribute this software and its\r
+# documentation for any purpose and without fee is hereby granted,\r
+# provided that the above copyright notice appear in all copies and that\r
+# both that copyright notice and this permission notice appear in\r
+# supporting documentation, and that the name of Vinay Sajip\r
+# not be used in advertising or publicity pertaining to distribution\r
+# of the software without specific, written prior permission.\r
+# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING\r
+# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL\r
+# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR\r
+# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER\r
+# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT\r
+# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\r
+# This copyright is for QueueHandler.\r
\r
## Import modules\r
+from __future__ import absolute_import\r
import Common.LongFilePathOs as os, sys, logging\r
import traceback\r
-from BuildToolError import *\r
+from .BuildToolError import *\r
+try:\r
+ from logging.handlers import QueueHandler\r
+except:\r
+ class QueueHandler(logging.Handler):\r
+ """\r
+ This handler sends events to a queue. Typically, it would be used together\r
+ with a multiprocessing Queue to centralise logging to file in one process\r
+ (in a multi-process application), so as to avoid file write contention\r
+ between processes.\r
+\r
+ This code is new in Python 3.2, but this class can be copy pasted into\r
+ user code for use with earlier Python versions.\r
+ """\r
+\r
+ def __init__(self, queue):\r
+ """\r
+ Initialise an instance, using the passed queue.\r
+ """\r
+ logging.Handler.__init__(self)\r
+ self.queue = queue\r
+\r
+ def enqueue(self, record):\r
+ """\r
+ Enqueue a record.\r
+\r
+ The base implementation uses put_nowait. You may want to override\r
+ this method if you want to use blocking, timeouts or custom queue\r
+ implementations.\r
+ """\r
+ self.queue.put_nowait(record)\r
+\r
+ def prepare(self, record):\r
+ """\r
+ Prepares a record for queuing. The object returned by this method is\r
+ enqueued.\r
+\r
+ The base implementation formats the record to merge the message\r
+ and arguments, and removes unpickleable items from the record\r
+ in-place.\r
+\r
+ You might want to override this method if you want to convert\r
+ the record to a dict or JSON string, or send a modified copy\r
+ of the record while leaving the original intact.\r
+ """\r
+ # The format operation gets traceback text into record.exc_text\r
+ # (if there's exception data), and also returns the formatted\r
+ # message. We can then use this to replace the original\r
+ # msg + args, as these might be unpickleable. We also zap the\r
+ # exc_info and exc_text attributes, as they are no longer\r
+ # needed and, if not None, will typically not be pickleable.\r
+ msg = self.format(record)\r
+ record.message = msg\r
+ record.msg = msg\r
+ record.args = None\r
+ record.exc_info = None\r
+ record.exc_text = None\r
+ return record\r
+\r
+ def emit(self, record):\r
+ """\r
+ Emit a record.\r
+\r
+ Writes the LogRecord to the queue, preparing it for pickling first.\r
+ """\r
+ try:\r
+ self.enqueue(self.prepare(record))\r
+ except Exception:\r
+ self.handleError(record)\r
\r
## Log level constants\r
DEBUG_0 = 1\r
"msg" : Message,\r
}\r
\r
- if ExtraData != None:\r
+ if ExtraData is not None:\r
LogText = _DebugMessageTemplate % TemplateDict + "\n %s" % ExtraData\r
else:\r
LogText = _DebugMessageTemplate % TemplateDict\r
return\r
\r
# if no tool name given, use caller's source file name as tool name\r
- if ToolName == None or ToolName == "":\r
+ if ToolName is None or ToolName == "":\r
ToolName = os.path.basename(traceback.extract_stack()[-2][0])\r
\r
- if Line == None:\r
+ if Line is None:\r
Line = "..."\r
else:\r
Line = "%d" % Line\r
"msg" : Message,\r
}\r
\r
- if File != None:\r
+ if File is not None:\r
LogText = _WarningMessageTemplate % TemplateDict\r
else:\r
LogText = _WarningMessageTemplateWithoutFile % TemplateDict\r
\r
- if ExtraData != None:\r
+ if ExtraData is not None:\r
LogText += "\n %s" % ExtraData\r
\r
_InfoLogger.log(WARN, LogText)\r
\r
- # Raise an execption if indicated\r
+ # Raise an exception if indicated\r
if _WarningAsError == True:\r
raise FatalError(WARNING_AS_ERROR)\r
\r
## Log ERROR message\r
#\r
# Once an error messages is logged, the tool's execution will be broken by raising\r
-# an execption. If you don't want to break the execution later, you can give\r
+# an exception. If you don't want to break the execution later, you can give\r
# "RaiseError" with "False" value.\r
#\r
# @param ToolName The name of the tool. If not given, the name of caller\r
# @param File The name of file which caused the error.\r
# @param Line The line number in the "File" which caused the warning.\r
# @param ExtraData More information associated with "Message"\r
-# @param RaiseError Raise an exception to break the tool's executuion if\r
+# @param RaiseError Raise an exception to break the tool's execution if\r
# it's True. This is the default behavior.\r
#\r
def error(ToolName, ErrorCode, Message=None, File=None, Line=None, ExtraData=None, RaiseError=IsRaiseError):\r
- if Line == None:\r
+ if Line is None:\r
Line = "..."\r
else:\r
Line = "%d" % Line\r
\r
- if Message == None:\r
+ if Message is None:\r
if ErrorCode in gErrorMessage:\r
Message = gErrorMessage[ErrorCode]\r
else:\r
Message = gErrorMessage[UNKNOWN_ERROR]\r
\r
- if ExtraData == None:\r
+ if ExtraData is None:\r
ExtraData = ""\r
\r
TemplateDict = {\r
"extra" : ExtraData\r
}\r
\r
- if File != None:\r
+ if File is not None:\r
LogText = _ErrorMessageTemplate % TemplateDict\r
else:\r
LogText = _ErrorMessageTemplateWithoutFile % TemplateDict\r
\r
_ErrorLogger.log(ERROR, LogText)\r
- if RaiseError:\r
+\r
+ if RaiseError and IsRaiseError:\r
raise FatalError(ErrorCode)\r
\r
# Log information which should be always put out\r
quiet = _ErrorLogger.error\r
\r
## Initialize log system\r
-def Initialize():\r
+def LogClientInitialize(log_q):\r
#\r
# Since we use different format to log different levels of message into different\r
# place (stdout or stderr), we have to use different "Logger" objects to do this.\r
#\r
# For DEBUG level (All DEBUG_0~9 are applicable)\r
_DebugLogger.setLevel(INFO)\r
- _DebugChannel = logging.StreamHandler(sys.stdout)\r
+ _DebugChannel = QueueHandler(log_q)\r
_DebugChannel.setFormatter(_DebugFormatter)\r
_DebugLogger.addHandler(_DebugChannel)\r
\r
# For VERBOSE, INFO, WARN level\r
_InfoLogger.setLevel(INFO)\r
- _InfoChannel = logging.StreamHandler(sys.stdout)\r
+ _InfoChannel = QueueHandler(log_q)\r
_InfoChannel.setFormatter(_InfoFormatter)\r
_InfoLogger.addHandler(_InfoChannel)\r
\r
# For ERROR level\r
_ErrorLogger.setLevel(INFO)\r
- _ErrorCh = logging.StreamHandler(sys.stderr)\r
+ _ErrorCh = QueueHandler(log_q)\r
_ErrorCh.setFormatter(_ErrorFormatter)\r
_ErrorLogger.addHandler(_ErrorCh)\r
\r
_InfoLogger.setLevel(Level)\r
_ErrorLogger.setLevel(Level)\r
\r
+## Initialize log system\r
+def Initialize():\r
+ #\r
+ # Since we use different format to log different levels of message into different\r
+ # place (stdout or stderr), we have to use different "Logger" objects to do this.\r
+ #\r
+ # For DEBUG level (All DEBUG_0~9 are applicable)\r
+ _DebugLogger.setLevel(INFO)\r
+ _DebugChannel = logging.StreamHandler(sys.stdout)\r
+ _DebugChannel.setFormatter(_DebugFormatter)\r
+ _DebugLogger.addHandler(_DebugChannel)\r
+\r
+ # For VERBOSE, INFO, WARN level\r
+ _InfoLogger.setLevel(INFO)\r
+ _InfoChannel = logging.StreamHandler(sys.stdout)\r
+ _InfoChannel.setFormatter(_InfoFormatter)\r
+ _InfoLogger.addHandler(_InfoChannel)\r
+\r
+ # For ERROR level\r
+ _ErrorLogger.setLevel(INFO)\r
+ _ErrorCh = logging.StreamHandler(sys.stderr)\r
+ _ErrorCh.setFormatter(_ErrorFormatter)\r
+ _ErrorLogger.addHandler(_ErrorCh)\r
+\r
def InitializeForUnitTest():\r
Initialize()\r
SetLevel(SILENT)\r