[Piglit] [PATCH] Added a simple logging class. Updated Test::doRun to use the new log.
Chad Versace
chad at chad-versace.us
Thu Jan 20 11:01:15 PST 2011
The patch looks good to me.
On 01/20/2011 09:30 AM, Ian Romanick wrote:
> 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()
_______________________________________________
Piglit mailing list
Piglit at lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/piglit
--
Chad Versace
chad.versace at intel.com
chad at chad-versace.us
More information about the Piglit
mailing list