docs: def generate_crash_handler_decorator(error_decorator=None):
      """Return the crash_handler to pass to pymacaron_core, with optional error decoration"""
  
      def crash_handler(f):
          """Return a decorator that reports failed api calls via the error_reporter,
          for use on every server endpoint"""
  
          @wraps(f)
          def wrapper(*args, **kwargs):
              """Generate a report of this api call, and if the call failed or was too slow,
              forward this report via the error_reporter"""
  
              data = {}
              t0 = timenow()
              exception_string = ''
  
              # Call endpoint and log execution time
              try:
                  res = f(*args, **kwargs)
              except Exception as e:
                  # An unhandled exception occured!
                  exception_string = str(e)
                  exc_type, exc_value, exc_traceback = sys.exc_info()
                  trace = traceback.format_exception(exc_type, exc_value, exc_traceback, 30)
                  data['trace'] = trace
  
                  # If it is a PyMacaronException, just call its http_reply()
                  if hasattr(e, 'http_reply'):
                      res = e.http_reply()
                  else:
                      # Otherwise, forge a Response
                      e = UnhandledServerError(exception_string)
                      log.error("UNHANDLED EXCEPTION: %s" % '\n'.join(trace))
                      res = e.http_reply()
  
              t1 = timenow()
  
              # Is the response an Error instance?
              response_type = type(res).__name__
              status_code = 200
              is_an_error = 0
              error = ''
              error_description = ''
              error_user_message = ''
  
              error_id = ''
  
              if isinstance(res, Response):
                  # Got a flask.Response object
                  res_data = None
  
                  status_code = str(res.status_code)
  
                  if str(status_code) == '200':
  
                      # It could be any valid json response, but it could also be an Error model
                      # that pymacaron_core handled as a status 200 because it does not know of
                      # pymacaron Errors
                      if res.content_type == 'application/json':
                          s = str(res.data)
                          if '"error":' in s and '"error_description":' in s and '"status":' in s:
                              # This looks like an error, let's decode it
                              res_data = res.get_data()
                  else:
                      # Assuming it is a PyMacaronException.http_reply()
                      res_data = res.get_data()
  
                  if res_data:
                      if type(res_data) is bytes:
                          res_data = res_data.decode("utf-8")
  
                      is_json = True
                      try:
                          j = json.loads(res_data)
                      except ValueError as e:
                          # This was a plain html response. Fake an error
                          is_json = False
                          j = {'error': res_data, 'status': status_code}
  
                      # Make sure that the response gets the same status as the PyMacaron Error it contained
                      status_code = j['status']
                      res.status_code = int(status_code)
  
                      # Patch Response to contain a unique id
                      if is_json:
                          if 'error_id' not in j:
                              # If the error is forwarded by multiple micro-services, we
                              # want the error_id to be set only on the original error
                              error_id = str(uuid.uuid4())
                              j['error_id'] = error_id
                              res.set_data(json.dumps(j))
  
                          if error_decorator:
                              # Apply error_decorator, if any defined
                              res.set_data(json.dumps(error_decorator(j)))
  
                      # And extract data from this error
                      error = j.get('error', 'NO_ERROR_IN_JSON')
                      error_description = j.get('error_description', res_data)
                      if error_description == '':
                          error_description = res_data
  
                      if not exception_string:
                          exception_string = error_description
  
                      error_user_message = j.get('user_message', '')
                      is_an_error = 1
  
  
              request_args = []
              if len(args):
                  request_args.append(args)
              if kwargs:
                  request_args.append(kwargs)
  
              data.update({
                  # Set only on the original error, not on forwarded ones, not on
                  # success responses
                  'error_id': error_id,
  
                  # Call results
                  'time': {
                      'start': t0.isoformat(),
                      'end': t1.isoformat(),
                      'microsecs': (t1.timestamp() - t0.timestamp()) * 1000000,
                  },
  
                  # Response details
                  'response': {
                      'type': response_type,
                      'status': str(status_code),
                      'is_error': is_an_error,
                      'error_code': error,
                      'error_description': error_description,
                      'user_message': error_user_message,
                  },
  
                  # Request details
                  'request': {
                      'params': pformat(request_args),
                  },
              })
  
              populate_error_report(data)
  
              # inspect may raise a UnicodeDecodeError...
              fname = function_name(f)
  
              #
              # Should we report this call?
              #
  
              # If it is an internal errors, report it
              if data['response']['status'] and int(data['response']['status']) >= 500:
                  report_error(
                      title="%s(): %s" % (fname, exception_string),
                      data=data,
                      is_fatal=True
                  )
  
              log.info("")
              log.info(" <= Done!")
              log.info("")
  
              return res
  
          return wrapper
  
      return crash_handler