diff --git a/Dockerfile-django-dev b/Dockerfile-django-dev index 1cb41b5c..593bdfdc 100644 --- a/Dockerfile-django-dev +++ b/Dockerfile-django-dev @@ -4,6 +4,7 @@ RUN pip install pip-tools COPY ./requirements.txt . RUN pip-sync requirements.txt +RUN pip install django-debug-toolbar==3.5.0 WORKDIR /usr/src/app diff --git a/README.md b/README.md index f4949dc7..ebef3848 100644 --- a/README.md +++ b/README.md @@ -144,3 +144,14 @@ In addition to running pycodestyle, pydocstyle, and mypy, this will also check t Note that validating the API schema requires Node 16 (newer versions may work as well). You can install Node 16 with [NVM](https://github.com/nvm-sh/nvm?tab=readme-ov-file#installing-and-updating). + +# Profiling +You can use django-debug-toolbar to profile API requests. + +1. Follow the [dev stack setup tutorial](https://github.com/eecs-autograder/autograder-full-stack/blob/master/docs/development_setup.md) for the [autograder-full-stack repo](https://github.com/eecs-autograder/autograder-full-stack). +2. Populate the database with benchmark data. +Benchmark scripts should be added to autograder-server/benchmarks and should include: + - Instructions on how to run them on the development stack. + - Results from the last time they were run (and specifying what machine). +3. Visit the API URL in your browser with the query parameter `debug=true` appended. +For example: `https://localhost:/api/users/current/?debug=true` diff --git a/autograder/settings/base.py b/autograder/settings/base.py index d9e2f6e1..4f07dc94 100644 --- a/autograder/settings/base.py +++ b/autograder/settings/base.py @@ -256,3 +256,8 @@ DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' from autograder.settings.celery_settings import * # noqa + + +# Indicates that the Django service is running as part of the web development stack +# (specifically the web server rather than the graders or running linters). +IS_DEV_SERVER = os.environ.get('IS_DEV_SERVER', 'false') == 'true' diff --git a/autograder/settings/development.py b/autograder/settings/development.py index 72f81b86..9cd61744 100644 --- a/autograder/settings/development.py +++ b/autograder/settings/development.py @@ -21,44 +21,36 @@ EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' -# !!! IMPORTANT !!! -# As of 22 April, 2020, django-debug-toolbar 2.2 (required when using Django 3) -# causes a memory leak, which in turn causes MemoryError in tests that create -# subprocesses. If you need to profile something, install the library manually -# and then uncomment the settings below to enable it. Also uncomment the -# "__debug__" url pattern in urls.py. -# Once you are finished profiling, UNINSTALL the library an RE-COMMENT -# the settings. -# -# INSTALLED_APPS += [ -# 'debug_toolbar', -# ] -# def show_toolbar_callback(request): -# return DEBUG -# DEBUG_TOOLBAR_CONFIG = { -# 'SHOW_TOOLBAR_CALLBACK': show_toolbar_callback -# } -# DEBUG_TOOLBAR_PANELS = [ -# 'debug_toolbar.panels.versions.VersionsPanel', -# 'debug_toolbar.panels.timer.TimerPanel', -# 'debug_toolbar.panels.settings.SettingsPanel', -# 'debug_toolbar.panels.headers.HeadersPanel', -# 'debug_toolbar.panels.request.RequestPanel', -# 'debug_toolbar.panels.sql.SQLPanel', -# 'debug_toolbar.panels.profiling.ProfilingPanel', -# # 'debug_toolbar.panels.staticfiles.StaticFilesPanel', -# # 'debug_toolbar.panels.templates.TemplatesPanel', -# 'debug_toolbar.panels.cache.CachePanel', -# 'debug_toolbar.panels.signals.SignalsPanel', -# 'debug_toolbar.panels.logging.LoggingPanel', -# 'debug_toolbar.panels.redirects.RedirectsPanel', -# ] -# MIDDLEWARE += ( -# 'debug_toolbar.middleware.DebugToolbarMiddleware', -# 'autograder.non_html_debug_toolbar_middleware.NonHtmlDebugToolbarMiddleware', -# ) -# -# /IMPORTANT +if IS_DEV_SERVER: + INSTALLED_APPS += [ + 'debug_toolbar', + ] + + def show_toolbar_callback(request): + return DEBUG + + DEBUG_TOOLBAR_CONFIG = { + 'SHOW_TOOLBAR_CALLBACK': show_toolbar_callback + } + DEBUG_TOOLBAR_PANELS = [ + 'debug_toolbar.panels.versions.VersionsPanel', + 'debug_toolbar.panels.timer.TimerPanel', + 'debug_toolbar.panels.settings.SettingsPanel', + 'debug_toolbar.panels.headers.HeadersPanel', + 'debug_toolbar.panels.request.RequestPanel', + 'debug_toolbar.panels.sql.SQLPanel', + 'debug_toolbar.panels.profiling.ProfilingPanel', + # 'debug_toolbar.panels.staticfiles.StaticFilesPanel', + # 'debug_toolbar.panels.templates.TemplatesPanel', + 'debug_toolbar.panels.cache.CachePanel', + 'debug_toolbar.panels.signals.SignalsPanel', + # 'debug_toolbar.panels.logging.LoggingPanel', + 'debug_toolbar.panels.redirects.RedirectsPanel', + ] + MIDDLEWARE += ( + 'debug_toolbar.middleware.DebugToolbarMiddleware', + 'autograder.non_html_debug_toolbar_middleware.NonHtmlDebugToolbarMiddleware', + ) REST_FRAMEWORK.update({ 'TEST_REQUEST_DEFAULT_FORMAT': 'json' diff --git a/autograder/urls.py b/autograder/urls.py index f22fe6be..efbeaeda 100644 --- a/autograder/urls.py +++ b/autograder/urls.py @@ -25,13 +25,12 @@ url(r'^api/', include('autograder.mutant_hints.urls')), ] -if settings.DEBUG: +if settings.IS_DEV_SERVER: urlpatterns += [ url(r'^static/(?P.*)$', views.serve), ] - # See note in autograder/settings/development.py - # import debug_toolbar - # urlpatterns = [ - # url(r'^__debug__/', include(debug_toolbar.urls)), - # ] + urlpatterns + import debug_toolbar + urlpatterns = [ + url(r'^__debug__/', include(debug_toolbar.urls)), + ] + urlpatterns diff --git a/requirements-dev.txt b/requirements-dev.txt index 7e447556..6a2d77a3 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -16,7 +16,7 @@ coreapi==2.3.3 # via djangorestframework-stubs coreschema==0.0.4 # via coreapi -django==3.2.2 +django==3.2.25 # via # -c requirements.txt # django-stubs diff --git a/requirements.txt b/requirements.txt index 9d6acfce..10af4de0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -20,7 +20,7 @@ celery==4.4.7 # via -r requirements.in decorator==4.4.2 # via ipython -django==3.2.2 +django==3.2.25 # via # -r requirements.in # django-redis