Главная | Архив новостей | Общение | Площадка | Примеры OpenID
Хостинг Django от «Джино»
Оглавление

Отладка

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


Увидели ошибку?
Выделите её мышкой и нажмите
Ctrl-Enter
Обработано:
1049 49 130 71

Версия книги
1.0 2.0
Версия 2.0 в процессе перевода!

Мой луч
Многообразие света

Полезное
Актуальные вакансии, Python работа для python-разработчиков.


Скачать в формате
CHM от 2 сентября

Заказать PDF файл можно через почту, чат, джаббер. Всего 2WMZ. Содержимое точно соответствует содержимому сайта.
Чем чаще заказываете — тем больше перевожу.

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

на поддержку перевода
Яндекс Яндекс.Деньги Хочу такую же кнопку
Ускорить процесс перевода!
R130494980980
Z425285133788
E112528079659
U327380922061

Книга помогла реализовать:
Проект «Мой луч»
АРМ УФМС.


Мой вебсайт стоит666 337,31 руб

© 2008-2009 Ruslan Popov @ gmail.com Powered by Django 1.1 beta 1 SVN-11114
Главная | Архив новостей | Общение | Площадка | Примеры OpenID