strona główna

Django: powiadomienia

Wczoraj przyszło mi do głowy, że powiadomienia o błędach to jednocześnie jeden z bardziej przydatnych i najmniej widocznych elementów Django. To dzięki nim zdarza mi się poprawić błędy i wysłać do użytkownika informację, że jakaś strona działa już poprawnie nawet jeśli nie chciało mu się zgłaszać usterki.

Na przykład:

 
from django.shortcuts import render_to_response
 
def gather_user_data(user):
    # in reality this would be more complex
    return {'email': user.email}
 
def profile_view(request):
    data = {'user': request.user}
    data.update(gather_user_data(request.user))
    return render_to_response('profile_view.html',
                              dictionary = data)
 

Widok profile_view zawiera błąd ujawniający się tylko w niektórych sytuacjach. Jeśli trafi na niego ktoś na serwerze produkcyjnym, zobaczy standardowe 500 Internal server error, a Django automatycznie wyśle do mnie taki raport:

 
Traceback (most recent call last):
 
  File "/home/marcink/checkout/django-trunk/django/core/handlers/base.py",
  line 86, in get_response
    response = callback(request, *callback_args, **callback_kwargs)
 
  File "/home/marcink/checkout/utils/blogowe/errtest/../errtest/errapp/views.py",
  line 8, in profile_view
    data.update(gather_user_data(request.user))
 
  File "/home/marcink/checkout/utils/blogowe/errtest/../errtest/errapp/views.py",
  line 4, in gather_user_data
    return {'email': user.email}
 
AttributeError: 'AnonymousUser' object has no attribute 'email'
 
< wsgirequest GET:< QueryDict: {}>,
POST:< querydict : {}>,
COOKIES:{'django_log_selectedLevel': '0',
 'django_log_showLocation': '1',
 'sessionid': '915922a5710cf210e2f5fae47e0f8900'},
META:{'COLORTERM': 'gnome-terminal',
 'CONTENT_LENGTH': '',
 'CONTENT_TYPE': 'text/plain',
 'DBUS_SESSION_BUS_ADDRESS': 'unix:abstract=/tmp/dbus-BibuFgosrz,guid=c50cabac45d33af5b6936d0049024c87',
 'DESKTOP_SESSION': 'default',
 'DISPLAY': ':0.0',
 'DJANGO_DIR': '/home/marcink/checkout/django-trunk',
 'DJANGO_SETTINGS_MODULE': 'errtest.settings',
 'FCGI_PORT': '9014',
 'GATEWAY_INTERFACE': 'CGI/1.1',
 'GDMSESSION': 'default',
 'GDM_LANG': 'en_US.UTF-8',
 'GDM_XSERVER_LOCATION': 'local',
 'GNOME_DESKTOP_SESSION_ID': 'Default',
 'GNOME_KEYRING_PID': '7904',
 'GNOME_KEYRING_SOCKET': '/tmp/keyring-glnuCS/socket',
 'GTK_RC_FILES': '/etc/gtk/gtkrc:/home/marcink/.gtkrc-1.2-gnome2',
 'HISTCONTROL': 'ignoreboth',
 'HOME': '/home/marcink',
 'HTTP_ACCEPT': 'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5',
 'HTTP_ACCEPT_CHARSET': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
 'HTTP_ACCEPT_ENCODING': 'gzip,deflate',
 'HTTP_ACCEPT_LANGUAGE': 'en-us,en;q=0.5',
 'HTTP_CACHE_CONTROL': 'max-age=0',
 'HTTP_CONNECTION': 'keep-alive',
 'HTTP_COOKIE': 'sessionid=915922a5710cf210e2f5fae47e0f8900; django_log_showLocation=1; django_log_selectedLevel=0',
 'HTTP_HOST': '127.0.0.1:5003',
 'HTTP_KEEP_ALIVE': '300',
 'HTTP_USER_AGENT': 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.17) Gecko/20080922 Ubuntu/7.10 (gutsy) Firefox/2.0.0.17',
 'JAVA_HOME': '/home/marcink/devel/jre1.6.0/',
 'LANG': 'en_US.UTF-8',
 'LD_LIBRARY_PATH': '/home/marcink/checkout/ldev_comicspot/comicspot/../other',
 'LESSCLOSE': '/usr/bin/lesspipe %s %s',
 'LESSOPEN': '| /usr/bin/lesspipe %s',
 'LOGNAME': 'marcink',
 'LS_COLORS': 'no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.avi=01;35:*.fli=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.flac=01;35:*.mp3=01;35:*.mpc=01;35:*.ogg=01;35:*.wav=01;35:',
 'OLDPWD': '/home/marcink',
 'OTHER_DIR': '/home/marcink/checkout/ldev_comicspot/comicspot/../other',
 'OUTER_DIR': '/home/marcink/checkout/ldev_comicspot/comicspot/..',
 'PATH': '/home/marcink/bin:/home/marcink/local/bin:/home/marcink/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games',
 'PATH_INFO': u'/profile/',
 'PROJECT_BASE_DIR': '/home/marcink/checkout/ldev_comicspot/comicspot',
 'PROJECT_DIR': '/home/marcink/checkout/ldev_comicspot/comicspot/comicspot',
 'PROJECT_NAME': 'comicspot',
 'PWD': '/home/marcink/checkout/utils/blogowe/errtest',
 'PYTHONPATH': '/home/marcink/checkout/django-trunk',
 'QUERY_STRING': '',
 'REMOTE_ADDR': '127.0.0.1',
 'REMOTE_HOST': '',
 'REQUEST_METHOD': 'GET',
 'RUN_MAIN': 'true',
 'SCRIPT_NAME': u'',
 'SERVER_NAME': 'raven.loc',
 'SERVER_PORT': '5003',
 'SERVER_PROTOCOL': 'HTTP/1.1',
 'SERVER_SOFTWARE': 'WSGIServer/0.1 Python/2.5.1',
 'SESSION_MANAGER': 'local/raven:/tmp/.ICE-unix/7907',
 'SHELL': '/bin/bash',
 'SHLVL': '1',
 'SSH_AGENT_PID': '7947',
 'SSH_AUTH_SOCK': '/tmp/ssh-lBRzQZ7907/agent.7907',
 'TERM': 'xterm',
 'TZ': 'America/Chicago',
 'USER': 'marcink',
 'USERNAME': 'marcink',
 'WINDOWID': '39852701',
 'WINDOWPATH': '7',
 'XAUTHORITY': '/tmp/.gdmELMXJU',
 'XDG_DATA_DIRS': '/usr/local/share/:/usr/share/:/usr/share/gdm/',
 'XDG_SESSION_COOKIE': '90de2c2a7bf31a95a76c4900471ce700-1224887428.976645-1927173936',
 '_': '/usr/bin/python',
 'wsgi.errors': < open file '< stderr>', mode 'w' at 0xb7dc30b0>,
 'wsgi.file_wrapper': < class 'django.core.servers.basehttp.FileWrapper'>,
 'wsgi.input': < socket ._fileobject object at 0x854a72c>,
 'wsgi.multiprocess': False,
 'wsgi.multithread': True,
 'wsgi.run_once': False,
 'wsgi.url_scheme': 'http',
 'wsgi.version': (1, 0)}>
 

Po pierwsze – dowiaduję się o problemie bez żadnej akcji ze strony użytkownika. Po drugie – dostaję mnóstwo informacji o błędzie: opis wyjątku (tutaj – brak atrybutu email w AnonymousUser), dokładnie wskazane miejsce wystąpienia razem z pełnym stosem wywołań funkcji, zawartość parametrów przekazanych przez GET i POST i zawartość zmiennych środowiskowych. W praktyce zwykle wystarcza to do złożenia testu pozwalającego na powtórzenie i usunięcie błędu.

O autorze: nazywam się Marcin Kaszyński i od ponad 10 lat zajmuję się tworzeniem oprogramowania, od projektowania przez programowanie do zarządzania projektami włącznie. Prowadzę warsztaty Django, będące szybkim i łatwym sposobem na poznanie tego środowiska i rozpoczęcie pracy z pełnym wykorzystaniem jego możliwości.

Dodaj komentarz