~ubuntu-branches/ubuntu/natty/moin/natty-updates

« back to all changes in this revision

Viewing changes to MoinMoin/web/profile.py

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard
  • Date: 2008-06-22 21:17:13 UTC
  • mto: This revision was merged to the branch mainline in revision 18.
  • Revision ID: james.westby@ubuntu.com-20080622211713-inlv5k4eifxckelr
ImportĀ upstreamĀ versionĀ 1.7.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- coding: iso-8859-1 -*-
2
 
"""
3
 
    MoinMoin - WSGI middlewares for profiling
4
 
 
5
 
    These have been ported from server_standalone to provide application
6
 
    profiling for a WSGI application. They are implemented as WSGI
7
 
    middlewares, so they can be plugged right in front of the MoinMoin
8
 
    WSGI application. Attention has to be payed, that at the end of
9
 
    profiling the `shutdown`-method has to be invoked, so that the
10
 
    middlewares can write the reports to the filesystem.
11
 
 
12
 
    TODO: in pre-WSGI MoinMoin those profilers where integrated in
13
 
          the standalone server and also some other gateway interfaces.
14
 
          In the near future the middlewares here could be again made
15
 
          configurable automatically with command line switches or
16
 
          wiki configuration options.
17
 
 
18
 
    @copyright: 2008 MoinMoin:FlorianKrupicka,
19
 
    @license: GNU GPL, see COPYING for details.
20
 
"""
21
 
from werkzeug import get_current_url
22
 
 
23
 
from MoinMoin import log
24
 
logging = log.getLogger(__name__)
25
 
 
26
 
class ProfilerMiddleware(object):
27
 
    """ Abstract base class for profiling middlewares.
28
 
 
29
 
    Concrete implementations of this class should provide implementations
30
 
    of `run_profile` and `shutdown`, the latter which should be called by
31
 
    the code utilizing the profiler.
32
 
    """
33
 
    def __init__(self, app):
34
 
        self.app = app
35
 
 
36
 
    def profile(self, environ, start_response):
37
 
        """
38
 
        Profile the request. Exceptions encountered during the profile are
39
 
        logged before being propagated for further handling.
40
 
        """
41
 
        method = environ.get('REQUEST_METHOD', 'GET')
42
 
        url = get_current_url(environ)
43
 
        logging.debug("Profiling call for '%s %s'", method, url)
44
 
        try:
45
 
            res = self.run_profile(self.app, (environ, start_response))
46
 
        except Exception, e:
47
 
            logging.exception("Exception while profiling '%s %s'", method, url)
48
 
            raise
49
 
        return res
50
 
 
51
 
    __call__ = profile
52
 
 
53
 
    def run_profile(self, app, *args, **kwargs):
54
 
        """ Override in subclasses.
55
 
 
56
 
        Several profilers available for python use the same call signature,
57
 
        therefore simplifying the implementation.
58
 
        """
59
 
        raise NotImplementedError()
60
 
 
61
 
    def shutdown(self):
62
 
        """ Override in subclasses to clean up when server/script shuts down. """
63
 
        pass
64
 
 
65
 
class CProfileMiddleware(ProfilerMiddleware):
66
 
    """ A profiler based on the the cProfile module from the standard lib. """
67
 
    def __init__(self, app, filename):
68
 
        super(CProfileMiddleware, self).__init__(app)
69
 
        import cProfile
70
 
        self._profile = cProfile.Profile()
71
 
        self._filename = filename
72
 
        self.run_profile = self._profile.runcall
73
 
 
74
 
    def shutdown(self):
75
 
        self._profile.dump_stats(self._filename)
76
 
 
77
 
class HotshotMiddleware(ProfilerMiddleware):
78
 
    """ A profiler based on the more recent hotshot module from the stdlib. """
79
 
    def __init__(self, app, *args, **kwargs):
80
 
        super(HotshotMiddleware, self).__init__(app)
81
 
        import hotshot
82
 
        self._profile = hotshot.Profile(*args, **kwargs)
83
 
        self.run_profile = self._profile.runcall
84
 
 
85
 
    def shutdown(self):
86
 
        self._profile.close()
87
 
 
88
 
class PycallgraphMiddleware(ProfilerMiddleware):
89
 
    """ A call graphing middleware utilizing the pycallgraph 3rd party
90
 
    module (available at http://pycallgraph.slowchop.com/). """
91
 
    def __init__(self, app, filename):
92
 
        super(PycallgraphMiddleware, self).__init__(app)
93
 
        import pycallgraph
94
 
        pycallgraph.settings['include_stdlib'] = False
95
 
        self._filename = filename
96
 
        globs = ['pycallgraph.*', 'unknown.*']
97
 
        f = pycallgraph.GlobbingFilter(exclude=globs, max_depth=9999)
98
 
        self._filter = f
99
 
        self.pycallgraph = pycallgraph
100
 
 
101
 
    def run_profile(self, app, *args, **kwargs):
102
 
        pycallgraph = self.pycallgraph
103
 
        pycallgraph.start_trace(reset=True, filter_func=self._filter)
104
 
        try:
105
 
            return app(*args, **kwargs)
106
 
        finally:
107
 
            pycallgraph.stop_trace()
108
 
 
109
 
    def shutdown(self):
110
 
        fname = self._filename
111
 
        pycallgraph = self.pycallgraph
112
 
        if fname.endswith('.png'):
113
 
            logging.info("Saving the rendered callgraph to '%s'", fname)
114
 
            pycallgraph.make_dot_graph(fname)
115
 
        elif fname.endswith('.dot'):
116
 
            logging.info("Saving the raw callgraph to '%s'", fname)
117
 
            pycallgraph.save_dot(fname)