Единственный способ, которым я нашел это, - перезаписать некоторые внутренние методы Ворона.
Основная идея заключается в том, что мы хотим изменить метод 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')
Это все кажется неоправданно сложным, но я рад, что я нашел способ заставьте его работать, наконец.
возвращение ошибки: LookupError: неоднозначные имена разделов ['app: main', 'конвейер: main'] для раздела 'main' (с префиксом 'app' или 'application' или 'composite' или 'composit' или ' конвейер 'или' filter-app '), найденный в config ..../development.ini –
@PaulYin Это ошибка, с которой вы сталкиваетесь? Похоже, что это не связано с вышеизложенным. По-видимому, у вас есть несколько «основных» разделов в вашем PYTHONPATH, но не указано, какой из них вы имеете в виду где-то в вашем development.ini. Если это вам не поможет, пожалуйста, откройте новый вопрос! –