Sentry - na straży aplikacji Django
Ile razy zapomniałeś o jakimś drobiazgu, lub zrobiłeś jakiś błąd, przez który Twoja aplikacja Django wysypała się dopiero na serwerze produkcyjnym? Użytkownicy strony zobaczyli błąd 500 (bo utworzyłeś szablon 500.html
, prawda?) i tyle. Pół biedy, jeśli dostałeś powiadomienie o błędzie na maila, Django wysyła na tyle dużo informacji do ADMINS
-ów że lepsze to niż nic. Ale rodzi się pytanie - nie można by raportować błędów jakoś bardziej elegancko? Można - po to jest Sentry.
Aktualizacja
Ten wpis dotyczy bardzo starej wersji Sentry, instalowanej razem z projektem. Od tamtego czasu projekt poszedł ostro do przodu, stał się SaaS-em, którego jednak można za darmo postawić u siebie. O konfiguracji i działaniu współczesnych wersji Sentry możesz przeczytać w Bibliotece Riklaunima.
Jeżeli jednak chcesz zobaczyć, jak to drzewiej bywało, czytaj dalej.
Wprowadzenie
Sentry (ang. strażnik, wartownik), a właściwie django-sentry
, bo pod taką nazwą jest zarejestrowana paczka na PyPI, to aplikacja Django rozwijana przez Davida Cramera i ekipę z Disqus. Stanowi kontynuację django-db-log
i umożliwia rejestrowanie wyjątków oraz logowanie komunikatów błędów do bazy danych. Na dzień dzisiejszy ponad 400 osób obserwuje projekt na Githubie, a kilkadziesiąt utworzyło własne forki.
Instalacja
Wszystko przebiega zupełnie typowo, pip install django-sentry
(easy_install
też zadziała, ale pip
jest bardziej sexy ;) ). Następnie dodajemy zgodnie z dokumentacją Sentry i jego zależności do INSTALLED_APPS
, a potem aktualizujemy strukturę bazy danych (twórca Sentry zaleca South, ja zresztą też).
# dla używających South python manage.py migrate # lub bez South - tradycyjnie python manage.py syncdb
Pozostaje jeszcze podpiąć Sentry do pliku URLconf, najprościej tak:
urlpatterns = patterns('', # ..., (r'^sentry/', include('sentry.urls')), )
Po uruchomieniu serwera deweloperskiego Django i wejściu pod adres skonfigurowany w pliku urls.py
, zobaczymy "kokpit" Sentry, prawdopodobnie pusty. Podobnie jak aplikacja panelu administracyjnego, kokpit Sentry stanowi kompletną witrynę internetową z własnymi szablonami i plikami statycznymi.
Wyjątki
Sentry przechwytuje błędy aplikacji zgłaszane jako wyjątki i loguje wystąpienie błędu do bazy danych. W kokpicie wyjątki są grupowane na podstawie źródła błędu - nazwy funkcji widoku, w której wystąpił problem, lub nazwy pliku szablonu, jeśli błąd powstał w trakcie renderowania. W czytelny sposób jest prezentowana liczba wystąpień danego błędu, jego źródło, oraz data ostatniego wystąpienia. Spośród pozostałych informacji najbardziej istotny jest typ wyjątku oraz właściwy komunikat błędu.
Kokpit prezentuje informacje niemalże w czasie rzeczywistym - za pomocą AJAX-a regularnie odpytuje Sentry, czy nie zarejestrowano nowych błędów i aktualizuje stronę bez potrzeby odświeżania. Dodatkowo, najeżdżając kursorem na informacje o błędzie i klikając pole z prawej strony, możemy go "odfajkować" - oznaczyć, że problem jest znany i prawdopodobnie sobie z nim poradziliśmy. Spowoduje to ukrycie danego błędu z listy. Oczywiście, gdy jednak (odpukać) problem się powtórzy, zgłoszenie pojawi się ponownie w kokpicie.
Możemy sortować informacje o błędach według priorytetu, bądź też czasu pierwszego lub ostatniego wystąpienia. Kokpit umożliwia ponadto filtrowanie zgłoszeń na podstawie kilku kryteriów, między innymi stanu zgłoszenia, loggera - źródła, kategorii błędu, lub serwera na którym wystąpił błąd.
Kliknięcie zgłoszenia otwiera widok jego szczegółów. Zobaczymy tu częstość występowania danego błędu w formie eleganckiego wykresu. Reszta widoku szczegółów zgłoszenia przypomina stronę informacji o błędzie, wyświetlaną przez Django gdy DEBUG = True
.
Logowanie własnych zdarzeń
Druga istotna funkcjonalność Sentry poza przechwytywaniem wyjątków, to możliwość rejestrowania dowolnych zdarzeń w aplikacji, jeśli używamy do tego modułu logging
ze standardowej biblioteki Pythona. Musimy jedynie skonfigurować logging
tak, by wykorzystywał klasę obsługi (handler - kto potrafi to sensowniej przetłumaczyć?) dostarczaną przez Sentry. Posłużę się przykładową konfiguracją z dokumentacji Sentry.
import logging from sentry.client.handlers import SentryHandler logger = logging.getLogger() # ensure we havent already registered the handler if SentryHandler not in map(lambda x: x.__class__, logger.handlers): logger.addHandler(SentryHandler()) # Add StreamHandler to sentry's default so you can catch missed exceptions logger = logging.getLogger('sentry.errors') logger.propagate = False logger.addHandler(logging.StreamHandler())
Jako przykład wykorzystania logowania zdarzeń wykorzystam minimalnie przerobiony fragment kodu z jednego z moich projektów. Chciałem logować rejestrować nieudane próby logowania użytkowników na stronie - w dość naiwny, ale działający sposób.
# globalny logger dla widoków aplikacji logger = logging.getLogger('mojprojekt.accounts.views') # nakładka na widok django.contrib.auth.views.login def login(request, template_name='accounts/login.html'): response = auth_views.login(request, template_name=template_name) if request.method == 'POST' and not request.user.is_authenticated(): logger.warning(u"Failed login attempt (username: %s)" % request.POST.get('username')) return response
Po podpięciu Sentry, mogę śledzić w kokpicie również tego typu zdarzenia.
Tak na marginesie: Django 1.3 dodaje kilka ułatwień w obsłudze logowania, między innymi standaryzuje konfigurację loggerów oraz udostępnia kilka własnych, wbudowanych we framework (między innymi logowanie żądań HTTP kończących się błędami, czy też debugowanie zapytań SQL).
Podsumowując, Sentry to godna uwagi aplikacja i zdecydowanie warto się przyjrzeć jej bliżej. Jako ciekawostkę dodam, że autor rozważa w wersji 2.0 uniezależnienie jej od Django i przepisanie klienta do postaci middleware WSGI.
Zobacz też: