4fef6bf7b5e65bc20afdc9692fdc5b349ece0f59
[wolnelektury.git] / apps / debug_toolbar / panels / cache.py
1 from debug_toolbar.panels import DebugPanel
2 try: from cStringIO import StringIO
3 except ImportError: import StringIO
4 from django.core import cache
5 from django.core.cache.backends.base import BaseCache
6 import time
7 import inspect
8 import os.path
9 from django.template.loader import render_to_string
10
11 class CacheStatTracker(BaseCache):
12     """A small class used to track cache calls."""
13     def __init__(self, cache):
14         self.cache = cache
15         self.reset()
16
17     def reset(self):
18         self.calls = []
19         self.hits = 0
20         self.misses = 0
21         self.sets = 0
22         self.gets = 0
23         self.get_many = 0
24         self.deletes = 0
25         self.total_time = 0
26
27     def _get_func_info(self):
28         stack = inspect.stack()[2]
29         return (os.path.basename(stack[1]), stack[2], stack[3], stack[4])
30     
31     def get(self, key, default=None):
32         t = time.time()
33         value = self.cache.get(key, default)
34         this_time = time.time()-t
35         self.total_time += this_time*1000
36         if value is None:
37             self.misses += 1
38         else:
39             self.hits += 1
40         self.gets += 1
41         self.calls.append((this_time, 'get', (key,), self._get_func_info()))
42         return value
43
44     def set(self, key, value, timeout=None):
45         t = time.time()
46         self.cache.set(key, value, timeout)
47         this_time = time.time()-t
48         self.total_time += this_time*1000
49         self.sets += 1
50         self.calls.append((this_time, 'set', (key, value, timeout), self._get_func_info()))
51
52     def delete(self, key):
53         t = time.time()
54         self.instance.delete(key, value)
55         this_time = time.time()-t
56         self.total_time += this_time*1000
57         self.deletes += 1
58         self.calls.append((this_time, 'delete', (key,), self._get_func_info()))
59
60     def get_many(self, keys):
61         t = time.time()
62         results = self.cache.get_many(keys)
63         this_time = time.time()-t
64         self.total_time += this_time*1000
65         self.get_many += 1
66         for key, value in results.iteritems():
67             if value is None:
68                 self.misses += 1
69             else:
70                 self.hits += 1
71         self.calls.append((this_time, 'get_many', (keys,), self._get_func_info()))
72
73 class CacheDebugPanel(DebugPanel):
74     """
75     Panel that displays the cache statistics.
76     """
77     name = 'Cache'
78
79     def __init__(self, request):
80         # This is hackish but to prevent threading issues
81         # is somewhat needed
82         if isinstance(cache.cache, CacheStatTracker):
83             cache.cache.reset()
84             self.cache = cache.cache
85         else:
86             self.cache = CacheStatTracker(cache.cache)
87             cache.cache = self.cache
88         super(CacheDebugPanel, self).__init__(request)
89
90     def title(self):
91         return 'Cache: %.2fms' % self.cache.total_time
92
93     def url(self):
94         return ''
95
96     def content(self):
97         context = dict(
98             cache_calls = len(self.cache.calls),
99             cache_time = self.cache.total_time,
100             cache = self.cache,
101         )
102         return render_to_string('debug_toolbar/panels/cache.html', context)