def do_version(): """Return version details of the running server api""" v = ApiPool.ping.model.Version( name=ApiPool().current_server_name, version=ApiPool().current_server_api.get_version(), container=get_container_version(), ) log.info("/version: " + pprint.pformat(v)) return v
def to_model(self): """Return a bravado-core Error instance""" e = ApiPool().current_server_api.model.Error( status=self.status, error=self.code.upper(), error_description=str(self), ) if self.error_id: e.error_id = self.error_id if self.user_message: e.user_message = self.user_message if self.error_caught: e.error_caught = pformat(self.error_caught) return e
def report_error(title=None, data={}, caught=None, is_fatal=False): """Format a crash report and send it somewhere relevant. There are two types of crashes: fatal crashes (backend errors) or non-fatal ones (just reporting a glitch, but the api call did not fail)""" # Don't report errors if NO_ERROR_REPORTING set to 1 (set by run_acceptance_tests) if os.environ.get('DO_REPORT_ERROR', None): # Force error reporting pass elif os.environ.get('NO_ERROR_REPORTING', '') == '1': log.info("NO_ERROR_REPORTING is set: not reporting error!") return elif 'is_ec2_instance' in data: if not data['is_ec2_instance']: # Not running on amazon: no reporting log.info("DATA[is_ec2_instance] is False: not reporting error!") return elif not is_ec2_instance(): log.info("Not running on an EC2 instance: not reporting error!") return # Fill error report with tons of usefull data if 'user' not in data: populate_error_report(data) # Add the message data['title'] = title data['is_fatal_error'] = is_fatal # Add the error caught, if any: if caught: data['error_caught'] = "%s" % caught # Add a trace - Formatting traceback may raise a UnicodeDecodeError... data['stack'] = [] try: data['stack'] = [l for l in traceback.format_stack()] except Exception as ee: data['stack'] = 'Skipped trace - contained non-ascii chars' # inspect may raise a UnicodeDecodeError... fname = '' try: fname = inspect.stack()[1][3] except Exception as e: fname = 'unknown-method' # Format the error's title status, code = 'unknown_status', 'unknown_error_code' if 'response' in data: status = data['response'].get('status', status) code = data['response'].get('error_code', code) title_details = "%s %s %s" % (ApiPool().current_server_name, status, code) else: title_details = "%s %s()" % (ApiPool().current_server_name, fname) if is_fatal: title_details = 'FATAL ERROR %s' % title_details else: title_details = 'NON-FATAL ERROR %s' % title_details if title: title = "%s: %s" % (title_details, title) else: title = title_details global error_reporter log.info("Reporting crash...") try: error_reporter(title, json.dumps(data, sort_keys=True, indent=4)) except Exception as e: # Don't block on replying to api caller log.error("Failed to send email report: %s" % str(e))
def populate_error_report(data): """Add generic stats to the error report""" # Did klue-client-server set a call_id and call_path? call_id, call_path = '', '' if hasattr(stack.top, 'call_id'): call_id = stack.top.call_id if hasattr(stack.top, 'call_path'): call_path = stack.top.call_path # Unique ID associated to all responses associated to a given # call to klue-api, across all micro-services data['call_id'] = call_id data['call_path'] = call_path # Are we in aws? data['is_ec2_instance'] = is_ec2_instance() # If user is authenticated, get her id user_data = { 'id': '', 'is_auth': 0, 'ip': '', } if stack.top: # We are in a request context user_data['ip'] = request.remote_addr if 'X-Forwarded-For' in request.headers: user_data['forwarded_ip'] = request.headers.get('X-Forwarded-For', '') if 'User-Agent' in request.headers: user_data['user_agent'] = request.headers.get('User-Agent', '') if hasattr(stack.top, 'current_user'): user_data['is_auth'] = 1 user_data['id'] = stack.top.current_user.get('sub', '') for k in ('name', 'email', 'is_expert', 'is_admin', 'is_support', 'is_tester', 'language'): v = stack.top.current_user.get(k, None) if v: user_data[k] = v data['user'] = user_data # Is the current code running as a server? if ApiPool().current_server_api: # Server info server = request.base_url server = server.replace('http://', '') server = server.replace('https://', '') server = server.split('/')[0] parts = server.split(':') fqdn = parts[0] port = parts[1] if len(parts) == 2 else '' data['server'] = { 'fqdn': fqdn, 'port': port, 'api_name': ApiPool().current_server_name, 'api_version': ApiPool().current_server_api.get_version(), } # Endpoint data data['endpoint'] = { 'id': "%s %s %s" % (ApiPool().current_server_name, request.method, request.path), 'url': request.url, 'base_url': request.base_url, 'path': request.path, 'method': request.method }