[Piglit] [PATCH] Added a simple logging class. Updated Test::doRun to use the new log.

Ian Romanick idr at freedesktop.org
Thu Jan 20 09:30:41 PST 2011


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/19/2011 05:25 PM, U. Artie Eoff wrote:
> Added log.py which includes a simple Logger class that wraps some
> basic functions from the Python logging module. The log wrapper
> simplifies setup and will accommodate thread synchronization in the
> future.  Test::doRun now uses the new log facility.
> NOTE: this changes the format of the 'test progress' previously
> printed via stdout.
> 
> Added patterns.py which includes a Singleton class design pattern
> to support the Logger class.  Future design patterns can be added
> to this file.
> 
> Tested with Python 2.7 on Linux.  All should be compatible with
> Windows and Mac and most earlier widely-used versions of Python.

I like the change.  I want some comment from non-Intel people before I
push this change.  Part of the reason for the change in output format is
that Artie's next change set is going to make CPU-only tests (e.g., all
of the parser tests) and GPU tests run concurrently.  Without this
change to the logging, you'd see things like:

Test: some_test
Test: some_other_test
    result: skip
    result: fail

That seems bad.  Which test failed and which test was skipped?

I'd like to hear

a) People don't hate the change.

b) The change works on Mac and Windows.

> ---
>  framework/core.py     |   12 ++++--
>  framework/log.py      |   46 ++++++++++++++++++++++++++
>  framework/patterns.py |   87 +++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 141 insertions(+), 4 deletions(-)
>  create mode 100644 framework/log.py
>  create mode 100644 framework/patterns.py
> 
> diff --git a/framework/core.py b/framework/core.py
> index b975cb3..8d98f70 100644
> --- a/framework/core.py
> +++ b/framework/core.py
> @@ -31,6 +31,7 @@ import subprocess
>  import sys
>  import time
>  import traceback
> +from log import log
>  from cStringIO import StringIO
>  
>  __all__ = [
> @@ -304,10 +305,14 @@ class Test:
>  		if len(env.exclude_filter) > 0:
>  			if True in map(lambda f: f.search(path) != None, env.exclude_filter):
>  				return None
> +
> +		def status(msg):
> +			log(msg = msg, channel = path)
> +
>  		# Run the test
>  		if env.execute:
>  			try:
> -				print "Test: %(path)s" % locals()
> +				status("running")
>  				time_start = time.time()
>  				result = self.run()
>  				time_end = time.time()
> @@ -325,9 +330,8 @@ class Test:
>  				result['exception'] = str(sys.exc_info()[0]) + str(sys.exc_info()[1])
>  				result['traceback'] = '@@@' + "".join(traceback.format_tb(sys.exc_info()[2]))
>  
> -			if result['result'] != 'pass':
> -				print "    result: %(result)s" % { 'result': result['result'] }
> -
> +			status(result['result'])
> +			
>  			result.write(env.file, path)
>  			if Test.sleep:
>  				time.sleep(Test.sleep)
> diff --git a/framework/log.py b/framework/log.py
> new file mode 100644
> index 0000000..c3fbdd7
> --- /dev/null
> +++ b/framework/log.py
> @@ -0,0 +1,46 @@
> +#
> +# Copyright (c) 2010 Intel Corporation
> +#
> +# Permission is hereby granted, free of charge, to any person obtaining a
> +# copy of this software and associated documentation files (the "Software"),
> +# to deal in the Software without restriction, including without limitation
> +# the rights to use, copy, modify, merge, publish, distribute, sublicense,
> +# and/or sell copies of the Software, and to permit persons to whom the
> +# Software is furnished to do so, subject to the following conditions:
> +#
> +# The above copyright notice and this permission notice (including the next
> +# paragraph) shall be included in all copies or substantial portions of the
> +# Software.
> +#
> +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> +# IN THE SOFTWARE.
> +#
> +
> +from patterns import Singleton
> +import logging
> +
> +class Logger(Singleton):
> +	def __logMessage(self, logfunc, message, **kwargs):
> +		[logfunc(line, **kwargs) for line in message.split('\n')]
> +
> +	def getLogger(self, channel = None):
> +		if 0 == len(logging.root.handlers):
> +			logging.basicConfig(
> +				format = "[%(asctime)s] :: %(message)+8s :: %(name)s",
> +				datefmt = "%c",
> +				level = logging.INFO,
> +			)
> +		if channel is None:
> +			channel = "base"
> +		logger = logging.getLogger(channel)
> +		return logger
> +
> +	def log(self, type = logging.INFO, msg = "", channel = None):
> +		self.__logMessage(lambda m, **kwargs: self.getLogger(channel).log(type, m, **kwargs), msg)
> +
> +log = Logger().log
> diff --git a/framework/patterns.py b/framework/patterns.py
> new file mode 100644
> index 0000000..3d7f22b
> --- /dev/null
> +++ b/framework/patterns.py
> @@ -0,0 +1,87 @@
> +#
> +# Copyright (c) 2010 Intel Corporation
> +#
> +# Permission is hereby granted, free of charge, to any person obtaining a
> +# copy of this software and associated documentation files (the "Software"),
> +# to deal in the Software without restriction, including without limitation
> +# the rights to use, copy, modify, merge, publish, distribute, sublicense,
> +# and/or sell copies of the Software, and to permit persons to whom the
> +# Software is furnished to do so, subject to the following conditions:
> +#
> +# The above copyright notice and this permission notice (including the next
> +# paragraph) shall be included in all copies or substantial portions of the
> +# Software.
> +#
> +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> +# IN THE SOFTWARE.
> +#
> +
> +import threading
> +
> +class Singleton(object):
> +	'''
> +		Modeled after http://www.python.org/download/releases/2.2.3/descrintro/*__new__
> +
> +		A thread-safe (mostly -- see NOTE) Singleton class pattern.
> +
> +		NOTE: deleting a singleton instance (i.e. Singleton::delInstance) does not guarantee that something
> +		else is currently using it. To reduce this risk, a program should not hold a reference to the
                     ^^^^^^^^^^^^
I think that should be "is not currently".  I can change that when I
push the patch.

> +		instance.  Rather, use the create/construct syntax (see example below) to access the instance.  Yet,
> +		this still does not guarantee that this type of usage will result in a desired effect in a
> +		multithreaded program.
> +		You've been warned so use the singleton pattern wisely!
> +
> +		Example:
> +		
> +		class MySingletonClass(Singleton):
> +			def init(self):
> +				print "in MySingletonClass::init()", self
> +
> +			def foo(self):
> +				print "in MySingletonClass::foo()", self
> +
> +		MySingletonClass().foo()
> +		MySingletonClass().foo()
> +		MySingletonClass().foo()
> +
> +		---> output will look something like this:
> +		in MySingletonClass::init() <__main__.MySingletonClass object at 0x7ff5b322f3d0>
> +		in MySingletonClass::foo() <__main__.MySingletonClass object at 0x7ff5b322f3d0>
> +		in MySingletonClass::foo() <__main__.MySingletonClass object at 0x7ff5b322f3d0>
> +		in MySingletonClass::foo() <__main__.MySingletonClass object at 0x7ff5b322f3d0>
> +	'''
> +
> +	lock = threading.RLock()
> +
> +	def __new__(cls, *args, **kwargs):
> +		try:
> +			cls.lock.acquire()
> +			it = cls.__dict__.get('__it__')
> +			if it is not None:
> +				return it
> +			cls.__it__ = it = object.__new__(cls)
> +			it.init(*args, **kwargs)
> +			return it
> +		finally: # this always gets called, even when returning from within the try block
> +			cls.lock.release()
> +
> +	def init(self, *args, **kwargs):
> +		'''
> +			Derived classes should override this method to do its initializations
> +			The derived class should not implement a '__init__' method.
> +		'''
> +		pass
> +
> +	@classmethod
> +	def delInstance(cls):
> +		cls.lock.acquire()
> +		try:
> +			if cls.__dict__.get('__it__') is not None:
> +				del cls.__it__
> +		finally:
> +			cls.lock.release()
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iEYEARECAAYFAk04cUEACgkQX1gOwKyEAw8n3ACfVQ9EvRotpLzpWxMXII+Vm5gG
mgEAoIzepFvhSbZBmNt3Rq8iJjThWX4M
=TJ/x
-----END PGP SIGNATURE-----


More information about the Piglit mailing list