"""
Need Django and CProfile.
Just append this middleware class in MIDDLEWARE in django settings.
"""
from django.core.exceptions import MiddlewareNotUsed
from django.utils.deprecation import MiddlewareMixin
from django.conf import settings
import cProfile
import pstats
import marshal
from io import StringIO
class ProfileMiddleware(MiddlewareMixin):
"""
view를 프로파일링하는 미들웨어 입니다. 본래는 debug가 true일 때만 실행해야 하지만, debug 상태에선 실제 배포 상태와는 다른 함수들이 실행되어
시간 지연이 발생하기 때문에 false 상태에서도 실행되도록 해놓았습니다. 대신 debug settings 파일 내부에만 미들웨어가 추가되어 있기에 배포 설정으로
서버를 열 경우 실행되지 않습니다.
사용법은 실행할 url 뒤에 profile 패러미터를 추가하면 됩니다. 만약 파일을 다운로드 받고 싶다면 profilebin 패러미터를 추가하면 됩니다.
"""
def __init__(self, get_response=None):
self.profiler = None
super().__init__(get_response)
def process_view(self, request, view_func, view_args, view_kwargs):
if 'profile' in request.GET or 'profilebin' in request.GET:
self.profiler = cProfile.Profile()
args = (request,) + view_args
return self.profiler.runcall(view_func, *args, **view_kwargs)
return None
def process_response(self, request, response):
if 'profile' in request.GET:
self.profiler.create_stats()
out = StringIO()
stats = pstats.Stats(self.profiler, stream=out)
# Values for stats.sort_stats():
# - calls call count
# - cumulative cumulative time
# - file file name
# - module file name
# - pcalls primitive call count
# - line line number
# - name function name
# - nfl name/file/line
# - stdname standard name
# - time internal time
stats.sort_stats('time').print_stats(.2)
response.content = out.getvalue()
response['Content-type'] = 'text/plain'
if 'profilebin' in request.GET:
self.profiler.create_stats()
response.content = marshal.dumps(self.profiler.stats)
filename = request.path.strip('/').replace('/', '_') + '.pstat'
response['Content-Disposition'] = \
'attachment; filename=%s' % (filename,)
response['Content-type'] = 'application/octet-stream'
return response