mirror of
https://github.com/pallets-eco/flask-debugtoolbar.git
synced 2026-01-06 05:30:12 -06:00
- Rename the package to flask_debugtoolbar - Fix importing of the panels so that the views in the panels are correctly registered in the blueprint There is still one major problem in the sqlalchemy panel where we are not able to get the SQLAlchemy reference
117 lines
3.2 KiB
Python
117 lines
3.2 KiB
Python
import sys
|
|
try:
|
|
import cProfile as profile
|
|
except ImportError:
|
|
import profile
|
|
import functools
|
|
import os.path
|
|
import pstats
|
|
|
|
from flask import current_app
|
|
from flask_debugtoolbar.panels import DebugPanel
|
|
from flask_debugtoolbar.utils import format_fname
|
|
|
|
|
|
class ProfilerDebugPanel(DebugPanel):
|
|
"""
|
|
Panel that displays the time a response took with cProfile output.
|
|
"""
|
|
name = 'Profiler'
|
|
|
|
user_activate = True
|
|
|
|
def has_content(self):
|
|
return bool(self.profiler)
|
|
|
|
def process_request(self, request):
|
|
if not self.is_active:
|
|
return
|
|
|
|
self.profiler = profile.Profile()
|
|
self.stats = None
|
|
|
|
def process_view(self, request, view_func, view_kwargs):
|
|
if self.is_active:
|
|
return functools.partial(self.profiler.runcall, view_func)
|
|
|
|
def process_response(self, request, response):
|
|
if not self.is_active:
|
|
return False
|
|
|
|
if self.profiler is not None:
|
|
self.profiler.disable()
|
|
try:
|
|
stats = pstats.Stats(self.profiler)
|
|
except TypeError:
|
|
self.is_active = False
|
|
return False
|
|
function_calls = []
|
|
for func in stats.sort_stats(1).fcn_list:
|
|
current = {}
|
|
info = stats.stats[func]
|
|
|
|
# Number of calls
|
|
if info[0] != info[1]:
|
|
current['ncalls'] = '%d/%d' % (info[1], info[0])
|
|
else:
|
|
current['ncalls'] = info[1]
|
|
|
|
# Total time
|
|
current['tottime'] = info[2] * 1000
|
|
|
|
# Quotient of total time divided by number of calls
|
|
if info[1]:
|
|
current['percall'] = info[2] * 1000 / info[1]
|
|
else:
|
|
current['percall'] = 0
|
|
|
|
# Cumulative time
|
|
current['cumtime'] = info[3] * 1000
|
|
|
|
# Quotient of the cumulative time divded by the number of
|
|
# primitive calls.
|
|
if info[0]:
|
|
current['percall_cum'] = info[3] * 1000 / info[0]
|
|
else:
|
|
current['percall_cum'] = 0
|
|
|
|
# Filename
|
|
filename = pstats.func_std_string(func)
|
|
current['filename_long'] = filename
|
|
current['filename'] = format_fname(filename)
|
|
function_calls.append(current)
|
|
|
|
self.stats = stats
|
|
self.function_calls = function_calls
|
|
# destroy the profiler just in case
|
|
return response
|
|
|
|
def title(self):
|
|
if not self.is_active:
|
|
return "Profiler not active"
|
|
return 'View: %.2fms' % (float(self.stats.total_tt)*1000,)
|
|
|
|
def nav_title(self):
|
|
return 'Profiler'
|
|
|
|
def nav_subtitle(self):
|
|
if not self.is_active:
|
|
return "in-active"
|
|
return 'View: %.2fms' % (float(self.stats.total_tt)*1000,)
|
|
|
|
def url(self):
|
|
return ''
|
|
|
|
def content(self):
|
|
if not self.is_active:
|
|
return "The profiler is not activated, activate it to use it"
|
|
|
|
context = {
|
|
'stats': self.stats,
|
|
'function_calls': self.function_calls,
|
|
}
|
|
return self.render('panels/profiler.html', context)
|
|
|
|
|
|
|