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