Skip to content

Instantly share code, notes, and snippets.

@LeonardoGentile
Last active November 16, 2017 11:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LeonardoGentile/a939d390a6cac0895aa74b3309c8d27e to your computer and use it in GitHub Desktop.
Save LeonardoGentile/a939d390a6cac0895aa74b3309c8d27e to your computer and use it in GitHub Desktop.
Django 1.11 PyCallGraph Middleware
  1. Install PyCallgraph with pip install pycallgraph
  2. Copy and paste callgraph_middleware.py file somewhere in your django project
  3. In your dev settings file add the middleware to the existing ones
  4. In settings add the CALL_GRAPH_URLS. This a list of dict, where each dict has 2 keys:
  • name: this is the name of the url to debug (you have to use named url patterns)
  • methods: the request methods that will trigger the debug

The middleware will call PyCallGraph and print an svg (or png) graph only if:

  • The urls have a ?graph params
  • The urls match any of the conf in the CALL_GRAPH_URLS list
# -*- encoding: UTF-8 -*-
import time
from django.conf import settings
from django.urls import resolve
from pycallgraph import Config
from pycallgraph import PyCallGraph
from pycallgraph.output import GraphvizOutput
from pycallgraph import GlobbingFilter
# New in Django 1.10
class CallgraphMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
# __call__ method is called when the instance is called (treating an instance as a function)
def __call__(self, request):
# Code to be executed for each request before
# the view (and later middleware) are called.
if settings.DEBUG and self.to_debug(request):
config = Config()
config.trace_filter = GlobbingFilter(include=['contracts.*'], exclude=[])
graphviz = GraphvizOutput(output_file='callgraph-' + str(time.time()) + '.svg', output_type='svg') # or 'png'
pycallgraph = PyCallGraph(output=graphviz, config=config)
pycallgraph.start()
# noinspection PyAttributeOutsideInit
self.pycallgraph = pycallgraph
response = self.get_response(request)
# Code to be executed for each request/response after
# the view is called.
self.pycallgraph.done()
else:
response = self.get_response(request)
return response
@staticmethod
def to_debug(request):
method = request.method
if method is 'GET' and 'graph' in request.GET:
return True
url_path = request.path
url_name = getattr(resolve(url_path), 'url_name', None)
urls = getattr(settings, 'CALL_GRAPH_URLS', None)
for url in urls:
if url.get('name', None) is url_name and method in url.get('methods', None):
return True
return False
# ...
MIDDLEWARE = MIDDLEWARE + [
'project_name.callgraph_middleware.CallgraphMiddleware',
]
CALL_GRAPH_URLS = [
{'name': 'home', 'methods': ['GET', 'POST']},
{'name': 'add-item', 'methods': ['POST']}
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment