2013-09-03 2 views
4

Я использую Sentry (Raven 3.4.1) на пользовательском Python/Pyramid webapp. Кажется, что Sentry имеет возможность отслеживать, какие и сколько пользователей испытывают определенное исключение. (См. Например, Sentry 6.2.0 changelog, в котором говорится: «Потоки, в которых записаны данные пользователя, теперь будут отображаться количество уникальных пользователей, с которыми произошло событие».) Как мне предоставить эту информацию ворон, чтобы она появилась в Sentry ?Как сообщить зарегистрированному пользователю в Sentry?

Могу ли я это сделать только в том случае, если я передам исключение из Raven вручную? Прямо сейчас, я использую обработчик регистрации SentryHandler, прикрепленный к корневому регистратору, и фильтр egg:raven#raven в конвейере PasteDeploy. (После официального сообщения Raven configuration docs for Pyramid тесно.)

Есть ли хороший трюк, чтобы передать эту информацию ворон? Могу ли я установить локальную переменную с определенным именем где-то внизу моего стека, как только я загружу сеанс пользователя, и Raven автоматически заберет его? Какая здесь самая лучшая практика?

Я подозреваю, что this имеет отношение к тому, что я пытаюсь сделать, но я не могу найти что-либо об этом в документах Raven.

ответ

3

Единственный способ, которым я нашел это, - перезаписать некоторые внутренние методы Ворона.

Основная идея заключается в том, что мы хотим изменить метод handle_exception() класса Sentry Ворона. Там я могу ввести интерфейс sentry.interfaces.User, который уже упоминался в вопросе. Для этого мне нужна моя собственная фабрика фильтров, которую я могу использовать вместо фильтра по умолчанию Paste, который поставляется с Raven и который использует мой собственный подкласс Sentry.

В моем проекте, у меня есть файл sentry.py:

from raven.middleware import Sentry 
from raven.utils.wsgi import get_current_url, get_headers, get_environ 
from raven.base import Client 

def sentry_filter_factory(app, global_conf, **kwargs): 
    """ Overwritten just to override the 'Sentry' class being used. """ 
    client = Client(**kwargs) 
    return UserEnhancedSentry(app, client) 

class UserEnhancedSentry(Sentry): 
    """ Overriding raven.middleware.Sentry's handle_exception() method to inject 
     the sentry.interfaces.User interface. This relies on the data previously 
     being injected into the environ by our custom tween. """ 
    def handle_exception(self, environ): 
     data={} 
     data['sentry.interfaces.Http'] = { 
      'method': environ.get('REQUEST_METHOD'), 
      'url': get_current_url(environ, strip_querystring=True), 
      'query_string': environ.get('QUERY_STRING'), 
      # TODO 
      # 'data': environ.get('wsgi.input'), 
      'headers': dict(get_headers(environ)), 
      'env': dict(get_environ(environ)), 
     } 
     if environ.has_key('myapp.user'): 
      user_id, username, email = environ.get('myapp.user') 
      ip_address = environ.get('HTTP_X_FORWARDED_FOR', environ.get('REMOTE_ADDR')) 
      data['sentry.interfaces.User'] = { 
       'id': user_id, 
       'username': username, 
       'email': email, 
       'ip_address': ip_address, 
      } 
     event_id = self.client.captureException(data=data) 
     return event_id 

В моем setup.py, я объявляю фильтра завод в качестве точки входа:

entry_points = """\ 
[paste.app_factory] 
main = myapp:main 
[paste.filter_app_factory] 
raven = myapp.sentry:sentry_filter_factory 
""", 

Теперь я могу использовать точку входа объявите фильтр в моем файле конфигурации .ini и проинтегрируем его в трубопровод Paste, как описано в Paste docs:

[pipeline:main] 
pipeline = 
    sentry 
    myapp 

[filter:sentry] 
use = egg:myapp#raven 
dsn = https://abc:[email protected]/123 

Итак, всякий раз, когда фильтр Sentry получает исключение, он не только будет хранить данные о HTTP-запросе, но также и о пользователе, если он найдет информацию об этом в environ. Все, что я должен сделать теперь вводить информацию пользователя из сеанса там, что я делаю с пользовательской анимацией:

def sentry_user_tween_factory(handler, registry): 
    """ Returns a tween that does nothing but enhance the environ by information about the currently 
     logged in user, which will be useful for the Sentry report in case there's an exception """ 
    def sentry_user_tween(request): 
     user = request.session.get('user') 
     if user: 
      request.environ['myapp.user'] = (user.token, user.name, user.email) 
     else: 
      request.environ['myapp.user'] = (0, 'anonymous', None) 
     # proceed with the next tween/handler 
     response = handler(request) 
     return response 
    return sentry_user_tween 

config.add_tween('myapp.sentry_user_tween_factory') 

Это все кажется неоправданно сложным, но я рад, что я нашел способ заставьте его работать, наконец.

+0

возвращение ошибки: LookupError: неоднозначные имена разделов ['app: main', 'конвейер: main'] для раздела 'main' (с префиксом 'app' или 'application' или 'composite' или 'composit' или ' конвейер 'или' filter-app '), найденный в config ..../development.ini –

+0

@PaulYin Это ошибка, с которой вы сталкиваетесь? Похоже, что это не связано с вышеизложенным. По-видимому, у вас есть несколько «основных» разделов в вашем PYTHONPATH, но не указано, какой из них вы имеете в виду где-то в вашем development.ini. Если это вам не поможет, пожалуйста, откройте новый вопрос! –