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

U. Artie Eoff ullysses.a.eoff at intel.com
Tue Jan 18 11:37:39 PST 2011


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