| Viewing file:  profiler.py (5.03 KB)      -rw-r--r-- Select action/file-type:
 
  (+) |  (+) |  (+) | Code (+) | Session (+) |  (+) | SDB (+) |  (+) |  (+) |  (+) |  (+) |  (+) | 
 
# -*- coding: utf-8 -*-"""
 werkzeug.contrib.profiler
 ~~~~~~~~~~~~~~~~~~~~~~~~~
 
 This module provides a simple WSGI profiler middleware for finding
 bottlenecks in web application.  It uses the :mod:`profile` or
 :mod:`cProfile` module to do the profiling and writes the stats to the
 stream provided (defaults to stderr).
 
 Example usage::
 
 from werkzeug.contrib.profiler import ProfilerMiddleware
 app = ProfilerMiddleware(app)
 
 :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details.
 :license: BSD, see LICENSE for more details.
 """
 import sys
 import time
 import os.path
 try:
 try:
 from cProfile import Profile
 except ImportError:
 from profile import Profile
 from pstats import Stats
 available = True
 except ImportError:
 available = False
 
 
 class MergeStream(object):
 
 """An object that redirects `write` calls to multiple streams.
 Use this to log to both `sys.stdout` and a file::
 
 f = open('profiler.log', 'w')
 stream = MergeStream(sys.stdout, f)
 profiler = ProfilerMiddleware(app, stream)
 """
 
 def __init__(self, *streams):
 if not streams:
 raise TypeError('at least one stream must be given')
 self.streams = streams
 
 def write(self, data):
 for stream in self.streams:
 stream.write(data)
 
 
 class ProfilerMiddleware(object):
 
 """Simple profiler middleware.  Wraps a WSGI application and profiles
 a request.  This intentionally buffers the response so that timings are
 more exact.
 
 By giving the `profile_dir` argument, pstat.Stats files are saved to that
 directory, one file per request. Without it, a summary is printed to
 `stream` instead.
 
 For the exact meaning of `sort_by` and `restrictions` consult the
 :mod:`profile` documentation.
 
 .. versionadded:: 0.9
 Added support for `restrictions` and `profile_dir`.
 
 :param app: the WSGI application to profile.
 :param stream: the stream for the profiled stats.  defaults to stderr.
 :param sort_by: a tuple of columns to sort the result by.
 :param restrictions: a tuple of profiling strictions, not used if dumping
 to `profile_dir`.
 :param profile_dir: directory name to save pstat files
 """
 
 def __init__(self, app, stream=None,
 sort_by=('time', 'calls'), restrictions=(), profile_dir=None):
 if not available:
 raise RuntimeError('the profiler is not available because '
 'profile or pstat is not installed.')
 self._app = app
 self._stream = stream or sys.stdout
 self._sort_by = sort_by
 self._restrictions = restrictions
 self._profile_dir = profile_dir
 
 def __call__(self, environ, start_response):
 response_body = []
 
 def catching_start_response(status, headers, exc_info=None):
 start_response(status, headers, exc_info)
 return response_body.append
 
 def runapp():
 appiter = self._app(environ, catching_start_response)
 response_body.extend(appiter)
 if hasattr(appiter, 'close'):
 appiter.close()
 
 p = Profile()
 start = time.time()
 p.runcall(runapp)
 body = b''.join(response_body)
 elapsed = time.time() - start
 
 if self._profile_dir is not None:
 prof_filename = os.path.join(self._profile_dir,
 '%s.%s.%06dms.%d.prof' % (
 environ['REQUEST_METHOD'],
 environ.get('PATH_INFO').strip(
 '/').replace('/', '.') or 'root',
 elapsed * 1000.0,
 time.time()
 ))
 p.dump_stats(prof_filename)
 
 else:
 stats = Stats(p, stream=self._stream)
 stats.sort_stats(*self._sort_by)
 
 self._stream.write('-' * 80)
 self._stream.write('\nPATH: %r\n' % environ.get('PATH_INFO'))
 stats.print_stats(*self._restrictions)
 self._stream.write('-' * 80 + '\n\n')
 
 return [body]
 
 
 def make_action(app_factory, hostname='localhost', port=5000,
 threaded=False, processes=1, stream=None,
 sort_by=('time', 'calls'), restrictions=()):
 """Return a new callback for :mod:`werkzeug.script` that starts a local
 server with the profiler enabled.
 
 ::
 
 from werkzeug.contrib import profiler
 action_profile = profiler.make_action(make_app)
 """
 def action(hostname=('h', hostname), port=('p', port),
 threaded=threaded, processes=processes):
 """Start a new development server."""
 from werkzeug.serving import run_simple
 app = ProfilerMiddleware(app_factory(), stream, sort_by, restrictions)
 run_simple(hostname, port, app, False, None, threaded, processes)
 return action
 
 |