File: profilemiddleware.py

package info (click to toggle)
0ad 0.0.23.1-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 78,292 kB
  • sloc: cpp: 245,166; ansic: 200,249; python: 13,754; sh: 6,104; perl: 4,620; makefile: 977; xml: 810; java: 533; ruby: 229; erlang: 46; pascal: 30; sql: 21; tcl: 4
file content (83 lines) | stat: -rw-r--r-- 3,583 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# http://www.no-ack.org/2010/12/yet-another-profiling-middleware-for.html

import os
import re
import tempfile
from cStringIO import StringIO

from django.conf import settings
import hotshot
import hotshot.stats

COMMENT_SYNTAX = ((re.compile(r'^application/(.*\+)?xml|text/html$', re.I), '<!--', '-->'),
                  (re.compile(r'^application/j(avascript|son)$',     re.I), '/*',   '*/' ))

class ProfileMiddleware(object):
    def process_view(self, request, callback, args, kwargs):
        # Create a profile, writing into a temporary file.
        filename = tempfile.mktemp()
        profile = hotshot.Profile(filename)

        try:
            try:
                # Profile the call of the view function.
                response = profile.runcall(callback, request, *args, **kwargs)

                # If we have got a 3xx status code, further
                # action needs to be taken by the user agent
                # in order to fulfill the request. So don't
                # attach any stats to the content, because of
                # the content is supposed to be empty and is
                # ignored by the user agent.
                if response.status_code // 100 == 3:
                    return response

                # Detect the appropriate syntax based on the
                # Content-Type header.
                for regex, begin_comment, end_comment in COMMENT_SYNTAX:
                    if regex.match(response['Content-Type'].split(';')[0].strip()):
                        break
                else:
                    # If the given Content-Type is not
                    # supported, don't attach any stats to
                    # the content and return the unchanged
                    # response.
                    return response

                # The response can hold an iterator, that
                # is executed when the content property
                # is accessed. So we also have to profile
                # the call of the content property.
                content = profile.runcall(response.__class__.content.fget, response)
            finally:
                profile.close()

            # Load the stats from the temporary file and
            # write them in a human readable format,
            # respecting some optional settings into a
            # StringIO object.
            stats = hotshot.stats.load(filename)
            if getattr(settings, 'PROFILE_MIDDLEWARE_STRIP_DIRS', False):
                stats.strip_dirs()
            if getattr(settings, 'PROFILE_MIDDLEWARE_SORT', None):
                stats.sort_stats(*settings.PROFILE_MIDDLEWARE_SORT)
            stats.stream = StringIO()
            stats.print_stats(*getattr(settings, 'PROFILE_MIDDLEWARE_RESTRICTIONS', []))
        finally:
            os.unlink(filename)

        # Construct an HTML/XML or Javascript comment, with
        # the formatted stats, written to the StringIO object
        # and attach it to the content of the response.
        comment = '\n%s\n\n%s\n\n%s\n' % (begin_comment, stats.stream.getvalue().strip(), end_comment)
        response.content = content + comment

        # If the Content-Length header is given, add the
        # number of bytes we have added to it. If the
        # Content-Length header is ommited or incorrect,
        # it remains so in order to don't change the
        # behaviour of the web server or user agent.
        if response.has_header('Content-Length'):
            response['Content-Length'] = int(response['Content-Length']) + len(comment)

        return response