Хостинг Django от «Джино»
Table of contents

Отладка

По материалам сайта 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',
)

Затем можно осуществлять журналирование из любой функции представления:

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, возвращённый функцией представления, но также шаблоны и контексты, которые были использованы для его рендеринга.


Ищем Python программистов

Found misprint?
Select it with the mouse and hit Enter
Ctrl-Enter
Processed:
33 1 199 25


The full repository of DjangoBook translation you can get on GitHub.
We appreciate your patches!

We are glad to hear your questions, comments or suggestions!
(Open in new tab)

Users number: 601

Русская группа

на поддержку перевода
Яндекс Яндекс.Деньги Хочу такую же кнопку
Ускорить процесс перевода!
ЯМ:41001223475816


© 2008-2012 Ruslan Popov @ gmail.com Powered by Django 1.2.5