/debug_toolbar/panels/cache.py

https://github.com/ross/django-debug-toolbar · Python · 105 lines · 86 code · 14 blank · 5 comment · 7 complexity · a08298b0357b6f725f949ebc1724ee84 MD5 · raw file

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