[Piglit] [PATCH] Added simple thread-safe logging support

Eoff, Ullysses A ullysses.a.eoff at intel.com
Tue Jan 18 15:05:32 PST 2011


Please disregard this patch... I'm working on a different solution.

> -----Original Message-----
> From: U. Artie Eoff [mailto:ullysses.a.eoff at intel.com]
> Sent: Tuesday, January 18, 2011 11:38 AM
> To: piglit at lists.freedesktop.org
> Cc: Eoff, Ullysses A
> Subject: [PATCH] Added simple thread-safe logging support
> 
> Added simple thread-safe logging support.  Changed test status output
> so that
> it has single-line context. This logging technique will ensure that
> output messages are not interleaved when future support is added for
> concurrent testing.  This changeset was tested with Python 2.7 on
> Linux.  It should be cross platform, however, and compatible with at
> least
> Python 2.5 (someone please verify if necessary).
> ---
>  framework/core.py     |   14 +++++++---
>  framework/log.py      |   71
> +++++++++++++++++++++++++++++++++++++++++++++++++
>  framework/patterns.py |   50 ++++++++++++++++++++++++++++++++++
>  framework/threads.py  |   45 +++++++++++++++++++++++++++++++
>  piglit-run.py         |    4 ++-
>  5 files changed, 179 insertions(+), 5 deletions(-)
>  create mode 100644 framework/log.py
>  create mode 100644 framework/patterns.py
>  create mode 100644 framework/threads.py
> 
> diff --git a/framework/core.py b/framework/core.py
> index b237df6..6454edf 100644
> --- a/framework/core.py
> +++ b/framework/core.py
> @@ -32,6 +32,8 @@ import sys
>  import time
>  import traceback
> 
> +import log
> +
>  __all__ = [
>  	'Environment',
>  	'checkDir',
> @@ -301,10 +303,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.Log(channel = path, msg = msg)
> +
>  		# 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()
> @@ -322,14 +328,14 @@ 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'] }
> +			#if result['result'] != 'pass':
> +			status("%(result)s" % { 'result': result['result'] })
> 
>  			result.write(env.file, path)
>  			if Test.sleep:
>  				time.sleep(Test.sleep)
>  		else:
> -			print "Dry-run: %(path)s" % locals()
> +			status("dry-run")
> 
>  	# Returns True iff the given error message should be ignored
>  	def isIgnored(self, error):
> diff --git a/framework/log.py b/framework/log.py
> new file mode 100644
> index 0000000..d69a26d
> --- /dev/null
> +++ b/framework/log.py
> @@ -0,0 +1,71 @@
> +#!/usr/bin/env python
> +#
> +# 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:
> +#
> +# This permission notice 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 AUTHOR(S) 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.
> +
> +# Piglit logging
> +
> +from patterns import Singleton
> +from threads import synchronized_self
> +import logging
> +
> +def Initialize():
> +	# basicConfig will not do anything if the root has any handlers
> +	# so remove them
> +	root    = logging.getLogger()
> +	handlers= root.handlers
> +	for handler in handlers:
> +		root.removeHandler(handler)
> +
> +	format      = "[%(asctime)s]:: %(name)s :: %(message)s"
> +	#dateformat  = "%a, %d %b %Y %H:%M:%S"
> +	level       = logging.INFO
> +
> +	logging.basicConfig(
> +		format  = format,
> +		#datefmt = dateformat,
> +		level   = level
> +	)
> +
> +class Logger(Singleton):
> +	@synchronized_self
> +	def __LogMessage(self, logfunc, message, **kwargs):
> +		[logfunc(line, **kwargs) for line in message.split('\n')]
> +
> +	@synchronized_self
> +	def GetLogger(self, channel = None):
> +		if len(logging.root.handlers) == 0:
> +			logging.basicConfig()
> +		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..9f43e20
> --- /dev/null
> +++ b/framework/patterns.py
> @@ -0,0 +1,50 @@
> +#!/usr/bin/env python
> +#
> +# 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:
> +#
> +# This permission notice 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 AUTHOR(S) 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.
> +
> +# Piglit design patterns
> +
> +
> +class Singleton(object):
> +	'''
> +		Modeled after
> http://www.python.org/download/releases/2.2.3/descrintro/#__new__
> +	'''
> +	def __new__(cls, *args, **kwargs):
> +		it = cls.__dict__.get('__it__')
> +		if it is not None:
> +			return it
> +		cls.__it__ = it = object.__new__(cls)
> +		it.init(*args, **kwargs)
> +		return it
> +
> +	def init(self, *args, **kwargs):
> +		''' Derived classes should override this method '''
> +		pass
> +
> +	@classmethod
> +	def GetInstance(cls, *args, **kwargs):
> +		return cls(*args, **kwargs)
> +
> +	@classmethod
> +	def ClearInstance(cls):
> +		if cls.__dict__.get('__it__') is not None:
> +			del cls.__it__
> diff --git a/framework/threads.py b/framework/threads.py
> new file mode 100644
> index 0000000..1215e10
> --- /dev/null
> +++ b/framework/threads.py
> @@ -0,0 +1,45 @@
> +#!/usr/bin/env python
> +#
> +# 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:
> +#
> +# This permission notice 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 AUTHOR(S) 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.
> +
> +# Piglit threads
> +
> +from threading import RLock
> +from weakref import WeakKeyDictionary
> +
> +######################################################################
> #######
> +##### Decorators
> +######################################################################
> #######
> +
> +# provides synchronized access to all instance methods of a instance
> that use this decorator
> +def synchronized_self(function):
> +	def wrapper(self, *args, **kwargs):
> +		synchronized_self.locks.setdefault(self, RLock()).acquire()
> +		try:
> +			return function(self, *args, **kwargs)
> +		finally:
> +			synchronized_self.locks[self].release()
> +	return wrapper
> +
> +synchronized_self.locks = WeakKeyDictionary()
> +
> +
> diff --git a/piglit-run.py b/piglit-run.py
> index 9f0eca6..0f7f15b 100755
> --- a/piglit-run.py
> +++ b/piglit-run.py
> @@ -27,7 +27,7 @@ import re
>  import sys
> 
>  import framework.core as core
> -
> +import framework.log as log
> 
> 
> 
> #######################################################################
> ######
> @@ -85,6 +85,8 @@ def main():
>  	if len(args) != 2:
>  		usage()
> 
> +	log.Initialize()
> +
>  	profileFilename = args[0]
>  	resultsDir = args[1]
> 
> --
> 1.7.3.4



More information about the Piglit mailing list