По материалам сайта http://simonwillison.net/2008/May/22/debugging/.
Стандартная страница ошибки Django — великолепна. Она предоставляет детальную трассировку, предоставляя локальные переменные, позволяет вам разворачивать строки кода вокруг строки с ошибкой, предоставляет текстовое описание исключения, удобное для отправки по почте коллегам и даже возможность отправить одной кнопкой детали ошибки на http://dpaste.com/, чтобы вы могли обсудить её на IRC канале. Страница предоставляет информацию о настройках приложения, о содержимом переменных запроса GET, POST и COOKIE и о всех значительных полях META собранных из среды HTTP сервера (отличный метод вспомнить, как правильно писать HTTP_REFERER).
Первым полезным советом будет то, что вы можете всегда вызвать отображение страницы с ошибкой при обработке любого представления, просто добавив строку:
assert False
Вы можете указать выражение, которое будет отображено в начале страницы:
assert False, request.GET
Одним из стандартных мест для использования такого подхода является сложная форма. Если вам требуется увидеть данные, которые были переданы пользователем, вставьте assert False в представление, на которое указывает форма и используйте полученную страницу с ошибкой для исследования данных.
Если необходимо иметь информацию о том, что происходит при
выполнении функции представления, самым быстрым способом будет
поместить в представление оператор
print. Сервер разработки выводит результат
обработки оператора print напрямую на
терминал. Это альтернатива со стороны сервера JavaScript
функции alert().
Если требуется более сложный подход к журналированию, лучше использовать соответствующий модуль языка Python, который является частью стандартной библиотеки. Вы можете настроить его в файле настроек проекта —
settings.py:
import logging
logging.basicConfig(
level = logging.DEBUG,
format = '%(asctime)s %(levelname)s %(message)s',
)
Для 1.3 смотрите https://docs.djangoproject.com/en/1.3/topics/logging/
Затем можно осуществлять журналирование из любой функции представления:
def my_view(request):
import logging
logging.debug("A log message")
...
И снова, этот метод приведёт к выводу отладочных сообщений на терминал сервера разработки. Если требуется выводить сообщения в файл, вы можете это реализовать, немного усовершенствовав метод:
logging.basicConfig(
level = logging.DEBUG,
format = '%(asctime)s %(levelname)s %(message)s',
filename = '/tmp/myapp.log',
filemode = 'w'
)
После этого вы можете использовать tail -f /tmp/myapp.log для отслеживания отладочной информации в реальном времени. Этот способ может использоваться как во время отладки приложения, так и в боевом режиме.
Всё описанное выше лишь слегка затрагивает возможности стандартного модуля журналирования языка Python. Если немного покопаться в документации, вы сможете использовать этот модуль для ротации журнальных файлов, для отправки сообщений по сети и даже отправлять их методом POST на сторонний веб-сервер.
Довольно часто приходится иметь дело с ошибкой, которая проявляется только в определённых ситуациях, ведь функция может вызываться из дюжины различных мест вашей программы, но ошибка происходит только в одном, очень особом, случае. Вы можете использовать модуль трассировки для сохранения состояния стека, это позволит вам понять как была вызвана проблемная функция:
import logging, traceback, pprint
def my_buggy_function(arg):
...
if error_condition:
stack = pprint.pformat(traceback.extract_stack())
logging.debug('An error occurred: %s' % stack)
Кортеж, полученный в результате выполнения
traceback.extract_stack(), включает в
себя номера строк, имена функций и пути к файлам Python,
т.е. вы можете реконструировать достаточный объём информации о
работе своей программы.
Наиболее мощным оружием в процессе отладки является соответствующий отладчик — pdb. Он поставляется в стандартной библиотеке языка Python и является отладчиком командной строки. Существует множество способов активации отладчика, но наиболее прямым способом является добавление нижеприведённой строки в функцию представления:
import pdb; pdb.set_trace()
При посещении соответствующей страницы браузером, последний «подвиснет» — будет казаться, что страница загружается крайне медленно. На самом деле сервер разработки прекратит выполнение функции представления и передаст управление отладчику, вы получаете к нему доступ на консоли и можете взаимодействовать с кодом представления.
Я упомянул, что вы никогда, ещё раз, никогда не должны оставлять эту строчку при установке проекта на боевой сервер?
Таким образом, вы получили подвисший сервер разработки и приглашение отладчика на консоли. Что же со всем этим делать? Да всё, что угодно. Сначала следовало бы почитать документацию на отладчик, но далее приведены несколько полезных команд:
list — Отображает строки исходного кода вокруг текущей точки выполнения. Вы можете выполнять эту команду многократно для увеличения объёма отображаемого кода.
n — Выполняет следующую строку.
s — Аналогично предыдущей команде, но заходит в любую вызываемую функцию.
r — Выполняет текущую функцию до конца.
u — Переходит на один уровень вверх по стеку, т.е., можно перейти в родительскую функцию.
locals() — Это не команда отладчика, но очень полезна для получения текущей области видимости.
При использовании отладчика вы не только можете просматривать содержимое переменных, но и свободно менять их, вызывать функции и всячески взаимодействовать с приложением во время его работы.
Но следует помнить, что всё это время браузер будет пытаться получить страницу. Если вы нажмёте c, то ваше приложение продолжит работу, запрос будет обработан и ваш браузер вздохнёт с облегчением.
К счастью, нет необходимости в «замораживании» сервера разработки во время работы с отладчиком. Отладчик отлично работает в интерактивной оболочке Django. Просто запустите проблемную функцию и затем делайте так:
>>> def function_that_raises_an_exception():
... assert False
...
>>> function_that_raises_an_exception()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in function_that_raises_an_exception
AssertionError
>>> import pdb; pdb.pm()
> <stdin>(2)function_that_raises_an_exception()
(Pdb)
Метод pdb.pm() позволяет вам вернуться
для отладки самого последнего исключения, даже если вы ещё не
произвели импорт модуля отладчика на время вызова исключения.
И последний совет по использованию отладчика: вы можете
использовать его для отладки скриптов командной строки,
подобных ./manage.py. Запустите его так:
python -i manage.py buggy_command
Аргумент -i указывает интерпретатору, что надо
перейти в интерактивный режим после запуска скрипта. Если
скрипт вызывает исключение, вы можете использовать метод
pdb.pm() для отладки.
Стандартным поведением Django в «боевом» режиме (т.е., когда параметр DEBUG установлен в False) является отправка на почту отчёта о вызванном исключении всем, кто перечислен в секции ADMINS. Также можно включить отправку отчётов на каждую ошибку 404 с помощью параметра SEND_BROKEN_LINK_EMAILS, отправка будет осуществлена всем, кто перечислен в секции MANAGERS. Больше эти настройки ничего не делают — это древний кусочек Django.
При работе сайта под высокой нагрузкой, вероятно, вам пригодится решение django-db-log от Дэвида Крамера (David Cramer), которое записывает исключения в таблицу базы данных. Оно по-хитрому использует MD5 хэш от трассировки для объединения множества сообщений об одной ошибке. Так же оно является отличным примером того, как использовать обработчик process_exception Django для своих целей.
ProfilerMiddleware — позволяет получить вывод модуля cProfile для конкретного URL, если добавить к нему ?prof.
DebugFooter — добавляет снизу страницы информацию о загруженных шаблонах и о выполненных SQL запросах.
Завершим этот раздел по интерактивному исследованию вашего приложения советом изучить использование TestClient. Несмотря на то, что он был разработан для юнит-тестов Django, он подойдёт и для нашей цели. Этот инструмент позволяет имитировать запрос к вашему приложению из вашего кода. Пример:
>>> from django.test.client import Client
>>> c = Client()
>>> response = c.get("/") # The homepage
>>> response
<django.http.HttpResponse object at 0x2300470>
>>> print response
Vary: Cookie
Content-Type: text/html; charset=utf-8
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
...
В ответ вы получите объект
HttpResponse, который можно
интерактивно исследовать.
Существует ещё одна функция, которая может помочь в интерактивной отладке приложения —
setup_test_environment(). Пример:
>>> from django.test.utils import setup_test_environment
>>> setup_test_environment()
>>> from django.test.client import Client
>>> c = Client()
>>> response = c.get("/")
>>> response.template
[<django.template.Template object at 0x2723dd0>,
<django.template.Template object at 0x2723f30>,
<django.template.Template object at 0x273ee10>]
>>> response.context
[ list of Context objects ]
Это позволяет вам исследовать не только HTML, возвращённый функцией представления, но также шаблоны и контексты, которые были использованы для его рендеринга.
| Пред. | Уровень выше | След. |
| Новый проект | Начало | Быстрый старт |
0 comments | Make a comment