[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