[Repoze-checkins] r681 - in repoze.profile/trunk: . repoze/profile

Tres Seaver tseaver at palladion.com
Fri Feb 8 19:16:02 UTC 2008


Author: Tres Seaver <tseaver at palladion.com>
Date: Fri Feb  8 14:16:01 2008
New Revision: 681

Log:
Eggify the accumulating profiler.

Added:
   repoze.profile/trunk/repoze/profile/
   repoze.profile/trunk/repoze/profile/__init__.py
   repoze.profile/trunk/repoze/profile/profiler.py   (contents, props changed)
Modified:
   repoze.profile/trunk/CHANGES.txt
   repoze.profile/trunk/README.txt
   repoze.profile/trunk/TODO.txt
   repoze.profile/trunk/setup.py

Modified: repoze.profile/trunk/CHANGES.txt
==============================================================================
--- repoze.profile/trunk/CHANGES.txt	(original)
+++ repoze.profile/trunk/CHANGES.txt	Fri Feb  8 14:16:01 2008
@@ -1,4 +1,3 @@
-0.1
+repoze.profile 0.1 (2008-02-08)
 
   Initial release.
-

Modified: repoze.profile/trunk/README.txt
==============================================================================
--- repoze.profile/trunk/README.txt	(original)
+++ repoze.profile/trunk/README.txt	Fri Feb  8 14:16:01 2008
@@ -1 +1,4 @@
-A readme file.
+repoze.profile README
+
+  This package provides a WSGI middleware component which aggregates
+  profiling data across *all* requests to the WSGI application.

Modified: repoze.profile/trunk/TODO.txt
==============================================================================
--- repoze.profile/trunk/TODO.txt	(original)
+++ repoze.profile/trunk/TODO.txt	Fri Feb  8 14:16:01 2008
@@ -1 +1 @@
-List todo items here.
+- [_] Package up the profile component into an egg.

Added: repoze.profile/trunk/repoze/profile/__init__.py
==============================================================================
--- (empty file)
+++ repoze.profile/trunk/repoze/profile/__init__.py	Fri Feb  8 14:16:01 2008
@@ -0,0 +1,9 @@
+from paste.debug.profile import profile_decorator
+
+class OKView:
+    def __init__(self, context, request):
+        self.context = context
+        self.request = request
+
+    def __call__(self):
+        return 'OK'

Added: repoze.profile/trunk/repoze/profile/profiler.py
==============================================================================
--- (empty file)
+++ repoze.profile/trunk/repoze/profile/profiler.py	Fri Feb  8 14:16:01 2008
@@ -0,0 +1,78 @@
+""" Middleware that profiles all requests, accumulating timings.
+
+o Insprired by the paste.debug.profile version, which profiles single requests.
+"""
+import profile
+import threading
+
+DEFAULT_PROFILE_LOG = 'wsgi.prof'
+
+class AccumulatingProfileMiddleware(object):
+
+    def __init__(self, app,
+                 global_conf=None,
+                 log_filename=DEFAULT_PROFILE_LOG,
+                 discard_first_request=True,
+                ):
+        self.app = app
+        self.profiler = profile.Profile()
+        self.log_filename = log_filename
+        self.first_request = discard_first_request
+        self.lock = threading.Lock()
+
+    def __call__(self, environ, start_response):
+        catch_response = []
+        body = []
+
+        def replace_start_response(status, headers, exc_info=None):
+            catch_response.extend([status, headers])
+            start_response(status, headers, exc_info)
+            return body.append
+
+        def run_app():
+            app_iter = self.app(environ, replace_start_response)
+            try:
+                body.extend(app_iter)
+            finally:
+                if hasattr(app_iter, 'close'):
+                    app_iter.close()
+
+        self.lock.acquire()
+        try:
+            self.profiler.runctx('run_app()', globals(), locals())
+
+            if self.first_request: # discard to avoid timing warm-up
+                self.profiler = profile.Profile()
+                self.first_request = False
+            else:
+                self.profiler.dump_stats(self.log_filename)
+
+            body = ''.join(body)
+            return [body]
+        finally:
+            self.lock.release()
+
+
+def make_profile_middleware(app,
+                            global_conf,
+                            log_filename=DEFAULT_PROFILE_LOG,
+                            discard_first_request=True,
+                           ):
+    """Wrap the application in a component that will profile each
+    request, appending data from each request to an aggregate
+    file.
+
+    Nota bene
+    ---------
+
+    o This middleware serializes all requests (i.e., removing concurrency).
+
+    o The Python profiler is seriously SLOW (maybe an order of magnitude!).
+
+    o Ergo, NEVER USE THIS MIDDLEWARE IN PRODUCTION.
+    """
+    return AccumulatingProfileMiddleware(
+                app,
+                log_filename=log_filename,
+                discard_first_request=discard_first_request
+               )

Modified: repoze.profile/trunk/setup.py
==============================================================================
--- repoze.profile/trunk/setup.py	(original)
+++ repoze.profile/trunk/setup.py	Fri Feb  8 14:16:01 2008
@@ -24,9 +24,9 @@
 here = os.path.abspath(os.path.dirname(__file__))
 README = open(os.path.join(here, 'README.txt')).read()
 
-setup(name='repoze.atemplate',
+setup(name='repoze.profile',
       version=__version__,
-      description='A template for repoze projects',
+      description='Aggregate profiling for WSGI requests',
       long_description=README,
       classifiers=[
         "Development Status :: 1 - Planning",
@@ -51,14 +51,8 @@
       install_requires=[],
       #test_suite="repoze.",
       entry_points = """\
-        #[console_scripts]
-        #addzope2user = repoze.atemplate.scripts.adduser:main
-
-        #[repoze.project]
-        #initialize = repoze.atemplate.instance:mkinstance
-
-        #[paste.filter_app_factory]
-        #middleware = repoze.atemplate:constructor
+      [paste.filter_app_factory]
+      profile = repoze.profile.profiler:make_profile_middleware
       """
       )
 


More information about the Repoze-checkins mailing list