How to inform a registered user in Sentry?

I am using Sentry (Raven 3.4.1) on a Python / Pyramid user oriented web server. It seems that Sentry has the ability to track which and how many users experience a specific exception. (See, for example, Sentry 6.2.0 changelog , which says: β€œStreams in which user data is recorded now shows the number of unique users the event happened.”) How can I provide this information to Raven so that it appears in Sentry?

Can I do this only if I pass the exception to Raven manually? Right now I am using the SentryHandler logging handler attached to the root log and the egg:raven#raven filter in the PasteDeploy pipeline. (After the official Raven configuration docs for Pyramid ).

Is there a good trick to pass this information to the raven? Can I set a local variable with a specific name somewhere at the bottom of my stack as soon as I load a user session and Raven automatically picks it up? What is the best practice here?

I suspect this is due to what I'm trying to do, but I cannot find anything about it in the Raven docs.

+4
source share
1 answer

The only way I found this is to overwrite some of the internal methods of Raven.

The main idea is that we want to change the handle_exception() method in the Sentry Raven class. There I can add the interface sentry.interfaces.User , which was already mentioned in the question. To do this, I need my own factory filter, which I can use instead of the default Paste filter that comes with Raven and that uses my own Sentry subclass.

In my project, I have a sentry.py file:

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

In my setup.py I declare a factory filter as an entry point:

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

Now I can use the entry point to declare a filter in the .ini configuration file and integrate it into the Paste pipeline, as described in Insert documents :

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

So, whenever a Sentry filter receives an exception, it will not only store data about the HTTP request, but also about the user if he finds information about this in the environ . All I need to do now is to enter user information from the session, which I do with user animation:

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

It all seems unreasonably complicated, but I'm glad I found a way to make it work, finally.

+3
source

Source: https://habr.com/ru/post/1500340/


All Articles