Deploy in Makefile.
[wolnelektury.git] / src / wolnelektury / middleware.py
1 # -*- coding: utf-8 -*-
2 # Original version taken from http://www.djangosnippets.org/snippets/186/
3 # Original author: udfalkso
4 # Modified by: Shwagroo Team
5
6 import sys
7 import os
8 import re
9 import hotshot
10 import hotshot.stats
11 import tempfile
12 import StringIO
13 import pprint
14
15 from django.conf import settings
16 from django.db import connection
17
18
19 words_re = re.compile(r'\s+')
20
21 group_prefix_re = [
22     re.compile("^.*/django/[^/]+"),
23     re.compile("^(.*)/[^/]+$"),  # extract module path
24     re.compile(".*"),            # catch strange entries
25 ]
26
27
28 class ProfileMiddleware(object):
29     """
30     Displays hotshot profiling for any view.
31     http://yoursite.com/yourview/?prof
32
33     Add the "prof" key to query string by appending ?prof (or &prof=)
34     and you'll see the profiling results in your browser.
35     It's set up to only be available in django's debug mode, is available for superuser otherwise,
36     but you really shouldn't add this middleware to any production configuration.
37
38     WARNING: It uses hotshot profiler which is not thread safe.
39     """
40     def process_request(self, request):
41         if (settings.DEBUG or request.user.is_superuser) and 'prof' in request.GET:
42             connection.queries = []
43             self.tmpfile = tempfile.mktemp()
44             self.prof = hotshot.Profile(self.tmpfile)
45
46     def process_view(self, request, callback, callback_args, callback_kwargs):
47         if (settings.DEBUG or request.user.is_superuser) and 'prof' in request.GET:
48             return self.prof.runcall(callback, request, *callback_args, **callback_kwargs)
49
50     def get_group(self, file):
51         for g in group_prefix_re:
52             name = g.findall(file)
53             if name:
54                 return name[0]
55
56     def get_summary(self, results_dict, sum):
57         list = [(item[1], item[0]) for item in results_dict.items()]
58         list.sort(reverse=True)
59         list = list[:40]
60
61         res = "      tottime\n"
62         for item in list:
63             if sum == 0:
64                 foo = 0
65             else:
66                 foo = 100*item[0]/sum
67             res += "%4.1f%% %7.3f %s\n" % (foo, item[0], item[1])
68
69         return res
70
71     def summary_for_files(self, stats_str):
72         stats_str = stats_str.split("\n")[5:]
73
74         mystats = {}
75         mygroups = {}
76
77         sum = 0
78
79         for s in stats_str:
80             fields = words_re.split(s)
81             if len(fields) == 7:
82                 time = float(fields[2])
83                 sum += time
84                 file = fields[6].split(":")[0]
85
86                 if file not in mystats:
87                     mystats[file] = 0
88                 mystats[file] += time
89
90                 group = self.get_group(file)
91                 if group not in mygroups:
92                     mygroups[group] = 0
93                 mygroups[group] += time
94
95         return "<pre>" + \
96                " ---- By file ----\n\n" + self.get_summary(mystats, sum) + "\n" + \
97                " ---- By group ---\n\n" + self.get_summary(mygroups, sum) + \
98                "</pre>"
99
100     def process_response(self, request, response):
101         if (settings.DEBUG or request.user.is_superuser) and 'prof' in request.GET:
102             self.prof.close()
103
104             out = StringIO.StringIO()
105             old_stdout = sys.stdout
106             sys.stdout = out
107
108             stats = hotshot.stats.load(self.tmpfile)
109             stats.sort_stats('time', 'calls')
110             stats.print_stats()
111
112             sys.stdout = old_stdout
113             stats_str = out.getvalue()
114
115             if response and response.content and stats_str:
116                 response.content = "<pre>" + stats_str + "</pre>"
117
118             response.content = "\n".join(response.content.split("\n")[:40])
119
120             response.content += self.summary_for_files(stats_str)
121
122             os.unlink(self.tmpfile)
123
124             response.content += '\n%d SQL Queries:\n' % len(connection.queries)
125             response.content += pprint.pformat(connection.queries)
126
127         return response