如何向Sentry报告当前登录的用户



我在面向用户的Python/Pyramid网络应用程序上使用Sentry(Raven 3.4.1.)。Sentry似乎有能力跟踪哪些用户以及有多少用户经历了某种异常。(例如,请参阅Sentry 6.2.0变更日志,其中提到:"记录了用户数据的流现在将显示事件发生的唯一用户数量。")我如何将这些信息提供给Raven,使其显示在哨兵中?

只有手动将异常传递给Raven,我才能执行此操作吗?现在,我正在使用一个连接到根记录器的SentryHandler日志处理程序,以及PasteDeploy管道中的egg:raven#raven过滤器。(密切关注Pyramid的Raven官方配置文档。)

有没有一个好的技巧可以将这些信息传递给Raven?我可以在堆栈底部的某个地方设置一个具有特定名称的局部变量吗?一旦我加载了用户的会话,Raven就会自动拾取它?这里的最佳做法是什么?

我怀疑这与我试图做的事情有关,但我在Raven文档中找不到任何关于它的信息。

我找到的唯一方法是覆盖Raven的一些内部方法。

其基本思想是,我们希望在Raven的Sentry类上修改handle_exception()方法。在那里,我可以注入我在问题中已经提到的sentry.interfaces.User接口。要做到这一点,我需要我自己的过滤器工厂,然后我可以使用它来代替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
""",

现在,我可以使用入口点在我的configuration.ini文件中声明一个过滤器,并将其集成到Paste管道中,就像Paste文档中所描述的那样:

[pipeline:main]
pipeline =
    sentry
    myapp
[filter:sentry]
use = egg:myapp#raven
dsn = https://abc:def@app.getsentry.com/123

因此,现在,每当Sentry过滤器捕捉到异常时,它不仅会存储有关HTTP请求的数据,还会存储有关用户的数据——假设它可以在environ中找到有关该请求的信息。我现在所要做的就是从那里注入会话中的用户信息,我正在使用一个自定义的tween:

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')

这一切看起来不合理地复杂,但我很高兴我终于找到了一种让它发挥作用的方法。

最新更新