예제 #1
0
    def get_error(self, worker_ctx, exc_info):
        """ Transform exception to serialisable dictionary
        """

        exc_type, exc, traceback = exc_info

        expected_exceptions = getattr(worker_ctx.entrypoint,
                                      'expected_exceptions', None)
        expected_exceptions = expected_exceptions or tuple()

        is_expected = isinstance(exc, expected_exceptions)

        try:
            exc_traceback = ''.join(format_exception(*exc_info))
        except Exception:
            exc_traceback = 'traceback serialisation failed'

        return {
            'exc_type': exc_type.__name__,
            'exc_path': get_module_path(exc_type),
            'exc_args': utils.safe_for_serialisation(exc.args),
            'exc_value': utils.safe_for_serialisation(exc),
            'traceback': exc_traceback,
            'is_expected': is_expected,
        }
예제 #2
0
def test_safe_for_serialisation_repr_failure():
    class CannotRepr(object):
        def __repr__(self):
            raise Exception('boom')

    assert (utils.safe_for_serialisation(
        [1, CannotRepr(), 2]) == [1, 'failed to get string representation', 2])
예제 #3
0
    def process(self, message, kwargs):
        """ Extract useful entrypoint processing information

        Extract useful entrypoint information and set it as
        ``constants.TRACE_KEY`` named attribute of the log record.
        Content of this attribute should be easily serialisable and the aim
        is to fill it with something that can go easily over a wire and that
        can be easily stored, filtered and searched.

        """

        hostname = self.extra['hostname']

        stage = kwargs['extra']['stage']
        worker_ctx = kwargs['extra']['worker_ctx']
        timestamp = kwargs['extra']['timestamp']

        entrypoint = worker_ctx.entrypoint

        data = kwargs['extra'].get(constants.TRACE_KEY, {})

        data[constants.TIMESTAMP_KEY] = timestamp
        data[constants.HOSTNAME_KEY] = hostname
        data[constants.SERVICE_NAME_KEY] = worker_ctx.service_name
        data[constants.ENTRYPOINT_TYPE_KEY] = type(entrypoint).__name__
        data[constants.ENTRYPOINT_NAME_KEY] = entrypoint.method_name

        data[constants.CONTEXT_DATA_KEY] = utils.safe_for_serialisation(
            worker_ctx.data)

        data[constants.CALL_ID_KEY] = worker_ctx.call_id
        data[constants.CALL_ID_STACK_KEY] = worker_ctx.call_id_stack
        data[constants.ORIGIN_CALL_ID_KEY] = worker_ctx.origin_call_id

        data[constants.STAGE_KEY] = stage.value

        call_args, call_args_redacted = self.get_call_args(worker_ctx)
        data[constants.REQUEST_KEY] = call_args
        data[constants.REQUEST_REDACTED_KEY] = call_args_redacted

        if stage == constants.Stage.response:

            exc_info = kwargs['extra']['exc_info_']

            if exc_info:
                data[constants.RESPONSE_STATUS_KEY] = (
                    constants.Status.error.value)
                self.set_exception(data, worker_ctx, exc_info)
            else:
                data[constants.RESPONSE_STATUS_KEY] = (
                    constants.Status.success.value)
                result = kwargs['extra']['result']
                data[constants.RESPONSE_KEY] = self.get_result(result)

            data[constants.RESPONSE_TIME_KEY] = (
                kwargs['extra']['response_time'])

        kwargs['extra'][constants.TRACE_KEY] = data

        return message, kwargs
예제 #4
0
    def set_exception(self, data, worker_ctx, exc_info):
        """ Set exception details as serialisable trace attributes
        """

        exc_type, exc, _ = exc_info

        expected_exceptions = getattr(worker_ctx.entrypoint,
                                      'expected_exceptions', None)
        expected_exceptions = expected_exceptions or tuple()
        is_expected = isinstance(exc, expected_exceptions)

        try:
            exc_traceback = ''.join(format_exception(*exc_info))
        except Exception:
            exc_traceback = 'traceback serialisation failed'

        exc_args = utils.safe_for_serialisation(exc.args)

        data[constants.EXCEPTION_TYPE_KEY] = exc_type.__name__
        data[constants.EXCEPTION_PATH_KEY] = get_module_path(exc_type)
        data[constants.EXCEPTION_ARGS_KEY] = exc_args
        data[constants.EXCEPTION_VALUE_KEY] = utils.safe_for_serialisation(exc)
        data[constants.EXCEPTION_TRACEBACK_KEY] = exc_traceback
        data[constants.EXCEPTION_EXPECTED_KEY] = is_expected
예제 #5
0
    def get_call_args(self, worker_ctx):
        """ Transform request object to serialized dictionary
        """

        entrypoint = worker_ctx.entrypoint

        method = getattr(entrypoint.container.service_cls,
                         entrypoint.method_name)
        call_args = inspect.getcallargs(method, None, *worker_ctx.args,
                                        **worker_ctx.kwargs)
        del call_args['self']

        request = call_args.pop('request')
        data = request.data or request.form
        call_args['request'] = {
            'url': request.url,
            'method': request.method,
            'data': utils.safe_for_serialisation(data),
            'headers': dict(self.get_headers(request.environ)),
            'env': dict(self.get_environ(request.environ)),
        }

        return call_args, False
예제 #6
0
 def get_result(self, result):
     """ Return serialisable result data
     """
     return utils.safe_for_serialisation(result)
예제 #7
0
def test_safe_for_serialisation(input_, expected_output):
    assert utils.safe_for_serialisation(input_) == expected_output