def version(env): try: version = get_version() except Exception: if env.instance_type == 'production': raise version = None return {'version': version}
def make_sentry_teller(env): if env.sentry_dsn: try: release = get_version() if '-' in release: release = None except: release = None sentry = raven.Client( env.sentry_dsn, environment=env.instance_type, release=release, ) else: sentry = None print("Won't log to Sentry (SENTRY_DSN is empty).") def tell_sentry(exception, state, allow_reraise=True): if isinstance(exception, pando.Response) and exception.code < 500: # Only log server errors return if isinstance(exception, NeedDatabase): # Don't flood Sentry when DB is down return if isinstance(exception, psycopg2.Error): from liberapay.website import website if getattr(website, 'db', None): try: website.db.one('SELECT 1 AS x') except psycopg2.Error: # If it can't answer this simple query, it's down. website.db = NoDB() # Show the proper 503 error page state['exception'] = NeedDatabase() # Tell gunicorn to gracefully restart this worker os.kill(os.getpid(), signal.SIGTERM) if 'read-only' in str(exception): # DB is in read only mode state['db_is_readonly'] = True # Show the proper 503 error page state['exception'] = NeedDatabase() # Don't reraise this in tests allow_reraise = False if isinstance(exception, ValueError): if 'cannot contain NUL (0x00) characters' in str(exception): # https://github.com/liberapay/liberapay.com/issues/675 response = state.get('response') or pando.Response() response.code = 400 response.body = str(exception) return {'exception': None} if not sentry: # No Sentry, log to stderr instead traceback.print_exc() # Reraise if allowed if env.sentry_reraise and allow_reraise: raise return {'sentry_ident': None} # Prepare context data sentry_data = {} if state: try: sentry_data['tags'] = { 'lang': getattr(state.get('locale'), 'language', None), } request = state.get('request') user_data = sentry_data['user'] = {} if request is not None: user_data['ip_address'] = str(request.source) sentry_data['request'] = { 'method': request.method, 'url': request.line.uri, 'headers': { k: b', '.join(v) for k, v in request.headers.items() if k != b'Cookie' }, } user = state.get('user') if isinstance(user, Participant): user_data['id'] = getattr(user, 'id', None) user_data['username'] = getattr(user, 'username', None) except Exception as e: tell_sentry(e, {}) # Tell Sentry result = sentry.captureException(data=sentry_data) # Put the Sentry id in the state for logging, etc return {'sentry_ident': sentry.get_ident(result)} CustomUndefined._tell_sentry = staticmethod(tell_sentry) return {'tell_sentry': tell_sentry}
def make_sentry_teller(env): if env.sentry_dsn: try: release = get_version() if '-' in release: release = None except Exception: release = None sentry = raven.Client( env.sentry_dsn, environment=env.instance_type, release=release, ) else: sentry = None print("Won't log to Sentry (SENTRY_DSN is empty).") def tell_sentry(exception, state, allow_reraise=True): if isinstance(exception, pando.Response) and exception.code < 500: # Only log server errors return if isinstance(exception, NeedDatabase): # Don't flood Sentry when DB is down return if isinstance(exception, psycopg2.Error): from liberapay.website import website if getattr(website, 'db', None): try: website.db.one('SELECT 1 AS x') except psycopg2.Error: # If it can't answer this simple query, it's down. website.db = NoDB() # Show the proper 503 error page state['exception'] = NeedDatabase() # Tell gunicorn to gracefully restart this worker os.kill(os.getpid(), signal.SIGTERM) if 'read-only' in str(exception): # DB is in read only mode state['db_is_readonly'] = True # Show the proper 503 error page state['exception'] = NeedDatabase() # Don't reraise this in tests allow_reraise = False if isinstance(exception, ValueError): if 'cannot contain NUL (0x00) characters' in str(exception): # https://github.com/liberapay/liberapay.com/issues/675 response = state.get('response') or pando.Response() response.code = 400 response.body = str(exception) return {'exception': None} if not sentry: # No Sentry, log to stderr instead traceback.print_exc() # Reraise if allowed if env.sentry_reraise and allow_reraise: raise return {'sentry_ident': None} # Prepare context data sentry_data = {} if state: try: sentry_data['tags'] = { 'lang': getattr(state.get('locale'), 'language', None), } request = state.get('request') user_data = sentry_data['user'] = {} if request is not None: user_data['ip_address'] = str(request.source) sentry_data['request'] = { 'method': request.method, 'url': request.line.uri.decoded, 'headers': { k.decode('ascii', 'repr'): b', '.join(v).decode('ascii', 'repr') for k, v in request.headers.items() if k != b'Cookie' }, } user = state.get('user') if isinstance(user, Participant): user_data['id'] = getattr(user, 'id', None) user_data['username'] = getattr(user, 'username', None) except Exception as e: tell_sentry(e, {}) # Tell Sentry result = sentry.captureException(data=sentry_data) # Put the Sentry id in the state for logging, etc return {'sentry_ident': sentry.get_ident(result)} CustomUndefined._tell_sentry = staticmethod(tell_sentry) return {'tell_sentry': tell_sentry}