Оригинальная статья "Centralized Logging with Sentry" рассказывает о приложении Sentry которая заменяет стандартный механизм сообщений об ошибках которые приходят на почту в случае каких-то проблем с Django-проектом.

Я люблю получать сообщения по e-mail, особенно, если они начинаются со слов “[Django] Error…”. Готов поспорить, что 95% всех Django-проектов на промышленных площадках использует для слежения за ошибками именно электронную почту. У нас, в Bread & Pepper, мы решили, что с этим надо что-то делать, потому что мы теряли сообщения об ошибках в наших почтовых ящиках и часто не знали, что исправлено, а что нет.

К счастью, есть отличный инструментальный пакет, который называется Sentry, и который создали люди из Disqus - этот пакет позволяет организовать централизованное журналирование ошибок.

Позвольте, я попытаюсь "продать" вам этот пакет, просто перечислив некоторые его характеристики из вводной статьи о нем:

  1. Интеллектуальная группировка сообщений об ошибках.
  2. Идентификация ошибок серверов, функций и URL.
  3. Направление потока ошибок в список по мере их возникновения, без необходимости в ручном обновлении списка.

В данной статье я покажу, как создать и настроить сервер журналирования, и как испытать его на вашем локальном Django-проекте. На моем сервере работает FreeBSD, но вы можете использовать мои инструкции для любой *Nix-системы.

Журналирование через UDP

Sentry использует соединение по протоколу TCP (HTTP). Это не очень здорово для журналирования, потому что этот протокол работает медленно из-за своей "гарантированной доставки". Для не слишком критичных приложений, таких, как журналирование, лучше подходит соединение по UDP. В данный момент последняя стабильная версия Sentry не поддерживает UDP. Однако для тех, кому важна производительность, версия с поддержкой UDP уже в работе и первые успехи уже есть. Учтите все же, что для потокового управления журналами лучше подходят другие инструменты, такие, как logstash.

Установка Sentry

Вначале добудьте себе сервер. Я взял свой на TransIP но вы можете с таким же успехом получить его с Linode, AWS или Brightbox. Сделайте основные настройки, заведите пользователей и сконфигурируйте доступ по SSH. Если вы решили использовать FreeBSD — а это хороший выбор — просто следуйте моему руководству “Solid FreeBSD Server: the Foundation”.

Нашей базой данных будет PostgreSQL. Я не буду описывать процесс ее установки, поскольку это уже описано другими. Вот руководства для Ubuntu, Debian и FreeBSD:

Debian

Use PostgreSQL Relational Databases on Debian 6

Ubuntu

Use PostgreSQL Relational Databases on Ubuntu 10.10

FreeBSD

Solid FreeBSD Server: PostgreSQL 9.0 (это мое руководство)

Сервер PostgreSQL установлен? Хорошо! Давайте создадим базу данных для Sentry:

# Переключиться на  пользователя pgsql 
# Для Debian/Ubuntu это postgres
sudo su - pgsql

# Создать пользователя, ответить 'n' на все вопросы о роли
createuser -P pg_sentry

# Создать базу данных
createdb db_sentry -O pg_sentry --encoding=UNICODE

Мы установим Sentry в виртуальную среду при помощи virtualenv. Чтобы установить эту среду, мы используем менеджер пакетов Python: pip.

На FreeBSD перейдите в каталог /usr/ports/devel/py-pip, и выполните команду make install clean от имени root. Для других систем прочтите инструкции по установке pip. Pip позволяет легко установить, и среду “virtualenv”, и ее вспомогательную утилиту “virtualenvwrapper”. Выполните следующие команды от имени root:

pip install virtualenv
pip install virtualenvwrapper

Virtualenvwrapper требует правильной настройки среды окружения. Вот мои настройки из .zshrc, помещающие все виртуальные среды в каталог ~/.virtualenvs. Если у вас Bash, добавьте эти настройки в ваш .bashrc.

export WORKON_HOME=$HOME/.virtualenvs

# Проверить, установлена ли virtualenvwrapper, если да, запустить!
# Как видите, моя virtualenvwrapper находится в
# `/usr/local/bin/` но у вас это может быть `/usr/bin/`
if [ -e "/usr/local/bin/virtualenvwrapper.sh" ]; then
   source /usr/local/bin/virtualenvwrapper.sh
fi

Выйдите из системы и зайдите снова, чтобы изменения вступили в силу. Если все прошло хорошо, вы получите сообщения об установке скриптов в каталоге .virtualenvs. Теперь все готово для создания виртуальной среды sentry:

mkdir ~/sentry
mkvirtualenv sentry

Ваша виртуальная среда будет активирована, когда вы вызовете скрипт mkvirtualenv, но не забудьте активировать ее снова при помощи workon sentry в следующий раз, когда будете работать с проектом sentry. Все теперь готово, пора установить Sentry. Я люблю работать с файлом требований (requirements) и с pip, поэтому давайте создадим файл requirements.txt в нашем каталоге sentry и заполним его требованиями для Sentry.

touch ~/sentry/requirements.txt
echo "Django==1.3.1" >> ~/sentry/requirements.txt
echo "sentry==2.0.0-RC6" >> ~/sentry/requirements.txt
echo "psycopg2==2.4.2" >> ~/sentry/requirements.txt

Вам не требуется добавлять в файл требований Django, поскольку Sentry позаботится обо всех зависимостях. Но нам нужна последняя стабильная версия Django, поэтому мы поместили сюда это требование.

Теперь, выполним установку при помощи команды pip install -r ~/sentry/requirements.txt. Будет установлено множество библиотек, но в результате вы должны увидеть:

Successfully installed Django sentry django-paging django-indexer django-templatetag-sugar raven python-daemon eventlet South kombu django-kombu simplejson lockfile greenlet anyjson amqplib psycopg2 Cleaning up…"

Нам нужно инициализировать конфигурацию базы для Sentry. Следующая команда создаст файл конфигурации в каталоге sentry :

sentry init ~/sentry/sentry.conf.py

Отредактируем конфигурацию. У меня получилось, в итоге, следующее:

import os.path
from sentry.conf.server import *

ROOT = os.path.dirname(__file__)

DATABASES = {
    'default': {
        # Используется база данных PostgreSQL, которую мы создали ранее 
        'ENGINE': "django.db.backends.postgresql_psycopg2",
        'NAME': "db_sentry",
        'USER': 'pg_sentry',
        'PASSWORD': 'your_password',
        'HOST': 'localhost',
    }
}

SENTRY_KEY = "SOME_KEY"

# Установите позднее в false, чтобы требовалась аутентификация 
SENTRY_PUBLIC = True

SENTRY_WEB_HOST = '0.0.0.0'
SENTRY_WEB_PORT = 9000

Обратите внимание, мы сохранили для SENTRY_PUBLIC значение True. Это сделано для того, чтобы упростить тестирование в дальнейшем. При переходе к реальной работе нужно будет вернуть значение False. Остальные настройки говорят сами за себя.

Довольно неудобно будет указывать местонахождение конфигурации Sentry при выполнении каждой команды. Поскольку Sentry ищет свою конфигурацию в каталоге ~/.sentry/sentry.conf.py, давайте добавим туда символическую ссылку.

mkdir ~/.sentry
ln -s ~/sentry/sentry.conf.py ~/.sentry/sentry.conf.py

Прежде чем запускать Sentry, нужно еще инициализировать базу данных:

cd ~/sentry
sentry upgrade

Теперь мы можем запустить сервер следующей командой:

cd ~/sentry
sentry start

Если порт у вас открыт, то вы можете теперь зайти на веб-сервер по порту 9000, например, http://example.com:9000

Nginx

Не очень удобно каждый раз заходить на сервер по порту “9000”, а в то же время имеется мощный сервер, хорошо подходящий для работы со статическим контентом. Давайте установим Nginx и используем его в качестве прокси для Sentry. На FreeBSD установить Nginx можно, перейдя в каталог /usr/ports/www/nginx и выполнив команду install clean от имени root. Добавьте строку nginx_enable="YES" в файл /etc/rc.conf, чтобы Nginx стартовал при загрузке системы. Запустите сервер при помощи следующей команды от имени root:

 /usr/local/etc/rc.d/nginx start

Nginx для Ubuntu или Debian устанавливается также просто, достаточно заглянуть в одно из руководств в Linode’s Library. Далее приведена конфигурация, которую я использовал для настройки Nginx, если вы замените "example" своими настройками, все должно заработать.

Помните, однако, что Ubuntu и Debian работают с каталогом sites_enabled ,который они включают в основную конфигурацию. Вам в этом случае необходимо вставить раздел server { … } внутрь того файла. Например, /etc/nginx/sites-enabled/sentry.conf.

# На Ubuntu/Debian это, обычно, www-data
# На FreeBSD - www
user  www www;

# Рабочие процессы, по 1 на процессор
worker_processes  2;

error_log  /var/log/nginx-error.log;

# Оптимизация
worker_rlimit_nofile 8192;
events {
    worker_connections  8000;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx-access.log  main;

    sendfile       on;
    tcp_nopush     on;
    tcp_nodelay    off;
    keepalive_timeout  20;

    # Оптимизация доступа к файлу
    open_file_cache max=1000 inactive=20s;
    open_file_cache_valid 30s;
    open_file_cache_min_uses 2;

    # Gzipping
    gzip              on;
    gzip_http_version 1.0;
    gzip_comp_level   5;
    gzip_proxied      any;
    gzip_min_length   512;
    gzip_buffers      4 8k;
    gzip_vary         on;
    gzip_types
      text/css
      text/javascript
      text/xml
      text/plain
      text/x-component
      application/javascript
      application/x-javascript
      application/json
      application/xml
      application/rss+xml
      font/truetype
      font/opentype
      application/vnd.ms-fontobject
      image/svg+xml;

    # Некоторые версии IE  не понимают сжатие на некоторых типах mime
    # поэтому, для них, отключим
    gzip_disable        "MSIE [1-6]\.";

    server {
        listen 80;

        # Заменить именем своего хоста
        server_name sentry.example.com;

        access_log /home/example/sentry/logs/nginx-access.log;

        # Задать кодировку
        charset utf-8;

        # Разрешить Nginx работать со статическими данными. Убедитесь, 
        # что указали их верное местоположение
        location /_static {
            alias /home/example/.virtualenvs/sentry/lib/python2.7/site-packages/sentry/static/;
            expires 14d;
            access_log off;
        }

        # Прокси для  Sentry
        location / {
            proxy_pass         http://localhost:9000;
            proxy_redirect     off;

            proxy_set_header   Host             $host;
            proxy_set_header   X-Real-IP        $remote_addr;
            proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
        }
    }
}

Перезапустите Nginx и вернитесь в каталог Sentry. Запустите Sentry следующим образом:

cd ~/sentry
sentry start --config=sentry.conf.py

Когда вы теперь зайдете на сервер своим браузером, то увидите страницу Sentry без необходимости добавлять номер порта - ":9000". Но вам вряд ли захочется запускать Sentry каждый раз вручную, поэтому давайте установим “Supervisor” для контроля над процессом.

Супервизор

Для установки супервизора в FreeBSD достаточно перейти в каталог /usr/ports/sysutils/py-supervisor и выполнить команду install clean от имени root. Для того, чтобы супервизор запускался при загрузке, добавьте в /etc/rc.conf следующую строку:

supervisord_enable="YES"

Запустите теперь супервизор командой от имени root:

/usr/local/etc/rc.d/supervisord start

Если у вас используется система, отличная от FreeBSD, следуйте указаниям из документации Установка супервизора.

Для слежения за процессом Sentry при помощи Supervisor, добавьте следующие строки в файл supervisord.conf. На FreeBSD он расположен в каталоге /usr/local/etc/supervisord.conf. (Конечно, снова замените "example" на имя вашего пользователя, выполняющего Sentry):

[program:sentry]
directory=/home/example/sentry
command=/home/example/.virtualenvs/sentry/bin/sentry start --config=/home/example/sentry/sentry.conf.py
user=example
umask=022
autostart=True
autorestart=True
redirect_stderr=True

Для того чтобы супервизор смог найти этот новый раздел, нам необходимо перезагрузить его конфигурацию командой supervisorctl reload от имени root. Проверьте, все ли работает правильно - для этого перезапустите свой VPS-сервер. Будем исходить из того, что все прошло гладко (а если нет, то из того, что вы хороший отладчик). Последний шаг состоит в том, чтобы защитить Sentry при помощи авторизации. Добавьте суперпользователя следующими командами:

workon sentry
cd ~/sentry
sentry manage createsuperuser --config=sentry.conf.py

Отредактируйте ваш файл sentry.conf.py и задайте:

SENTRY_PUBLIC = False

Перезапустите Sentry, чтобы новая конфигурация вступила в силу (команда supervisorctl restart sentry от имени root). Теперь откройте свой веб-сайт Sentry - все работает!

Интеграция с вашим Django-проектом

Подключение вашего Django-проекта к Sentry требует наличия Sentry-клиента. Для Python таким клиентом является Raven. Найдите или создайте тот Django-проект, для которого вы хотите использовать Raven. Вначале установите raven командой pip install raven --upgrade, затем откройте файл settings.py вашего Django-проекта.

Затем следуйте инструкциям из документации Raven по конфигурированию Django. Переменную SENTRY_KEY на этом сервере можно найти в файле sentry.conf.py, а SENTRY_SERVERS нужно присвоить имя вашего сервера.

Если вы настроили LOGGING в соответствии с описанной конфигурацией, вы можете проверить систему, добавив в нее одно из ваших представлений "view", и открыв его в браузере. Вы должны увидеть сообщение об ошибке без ручного обновления сервера Sentry.

import logging

# Получить экземпляр logger
logger = logging.getLogger(__name__)
logger.error('There was some crazy error',
             exc_info=True,
             extra={'request': request,})

Собственно журналирование

Ваша система централизованного журналирования работает. Самое время объяснить своим сотрудникам, как она устроена! Полезно будет также прочесть документацию по журналированию Django, прежде чем выбирать в своем проекте подходящие точки журналирования. Если вам чего-то не хватило в этом руководстве, дайте мне знать твитом или через почту.

16 Апрель 2012, 11:45 0 alafin
blog comments powered by Disqus