예제 #1
0
def _request_wrapper(func, instance, args, kwargs):
    """
    This is the wrapper of the requests. it parses the http's message to conclude the url, headers, and body.
    Finally, it add an event to the span, and run the wrapped function (http.client.HTTPConnection.send).
    """
    data = safe_get_list(args, 0)
    with lumigo_safe_execute("parse requested streams"):
        if isinstance(data, BytesIO):
            current_pos = data.tell()
            data = data.read(MAX_READ_SIZE)
            args[0].seek(current_pos)

    host, method, headers, body, uri = (
        getattr(instance, "host", None),
        getattr(instance, "_method", None),
        None,
        None,
        None,
    )
    with lumigo_safe_execute("parse request"):
        if isinstance(data, bytes) and _BODY_HEADER_SPLITTER in data:
            headers, body = data.split(_BODY_HEADER_SPLITTER, 1)
            if _FLAGS_HEADER_SPLITTER in headers:
                request_info, headers = headers.split(_FLAGS_HEADER_SPLITTER, 1)
                headers = http.client.parse_headers(BytesIO(headers))
                path_and_query_params = (
                    # Parse path from request info, remove method (GET | POST) and http version (HTTP/1.1)
                    request_info.decode("ascii")
                    .replace(method, "")
                    .replace(instance._http_vsn_str, "")
                    .strip()
                )
                uri = f"{host}{path_and_query_params}"
                host = host or headers.get("Host")

    with lumigo_safe_execute("add request event"):
        if headers:
            SpansContainer.get_span().add_request_event(
                HttpRequest(host=host, method=method, uri=uri, headers=headers, body=body)
            )
        else:
            SpansContainer.get_span().add_unparsed_request(
                HttpRequest(host=host, method=method, uri=uri, body=data)
            )

    ret_val = func(*args, **kwargs)
    with lumigo_safe_execute("add response event"):
        SpansContainer.get_span().update_event_end_time()
    return ret_val
예제 #2
0
def _read_stream_wrapper_generator(stream_generator, instance):
    for partial_response in stream_generator:
        with lumigo_safe_execute("parse response.read_chunked"):
            SpansContainer.get_span().update_event_response(
                None, instance.status, instance.headers, partial_response
            )
        yield partial_response
예제 #3
0
def _add_wrap_flag_to_context(*args):
    """
    This function is here in order to validate that we didn't already wrap this invocation
        (using the sls plugin / auto instrumentation / etc.).
    We are adding lumigo's flag to the context, and check it's value in _is_context_already_wrapped.
    """
    if len(args) >= 2:
        with lumigo_safe_execute("wrap context"):
            setattr(args[1], CONTEXT_WRAPPED_BY_LUMIGO_KEY, True)
예제 #4
0
def _read_wrapper(func, instance, args, kwargs):
    """
    This is the wrapper of the function that can be called only after `getresponse` was called.
    """
    ret_val = func(*args, **kwargs)
    if ret_val:
        with lumigo_safe_execute("parse response.read"):
            SpansContainer.get_span().update_event_response(
                None, instance.code, instance.headers, ret_val
            )
    return ret_val
예제 #5
0
def _response_wrapper(func, instance, args, kwargs):
    """
    This is the wrapper of the function that can be called only after that the http request was sent.
    Note that we don't examine the response data because it may change the original behaviour (ret_val.peek()).
    """
    ret_val = func(*args, **kwargs)
    with lumigo_safe_execute("parse response"):
        headers = ret_val.headers
        status_code = ret_val.code
        SpansContainer.get_span().update_event_response(instance.host, status_code, headers, b"")
    return ret_val
예제 #6
0
def wrap_http_calls():
    global already_wrapped
    if not already_wrapped:
        with lumigo_safe_execute("wrap http calls"):
            get_logger().debug("wrapping the http request")
            wrap_function_wrapper("http.client", "HTTPConnection.send", _request_wrapper)
            wrap_function_wrapper("botocore.awsrequest", "AWSRequest.__init__", _putheader_wrapper)
            wrap_function_wrapper("http.client", "HTTPConnection.getresponse", _response_wrapper)
            wrap_function_wrapper("http.client", "HTTPResponse.read", _read_wrapper)
            if importlib.util.find_spec("urllib3"):
                wrap_function_wrapper(
                    "urllib3.response", "HTTPResponse.read_chunked", _read_stream_wrapper
                )
            already_wrapped = True
예제 #7
0
    def lambda_wrapper(*args, **kwargs):
        if str(os.environ.get(_KILL_SWITCH, "")).lower() == "true":
            return func(*args, **kwargs)

        if _is_context_already_wrapped(*args):
            return func(*args, **kwargs)
        _add_wrap_flag_to_context(*args)
        executed = False
        ret_val = None
        local_print = print
        local_logging_format = logging.Formatter.format
        try:
            if Configuration.enhanced_print:
                _enhance_output(args, local_print, local_logging_format)
            SpansContainer.create_span(*args, force=True)
            SpansContainer.get_span().start(*args)
            wrap_http_calls()
            try:
                executed = True
                ret_val = func(*args, **kwargs)
            except Exception as e:
                with lumigo_safe_execute("Customer's exception"):
                    SpansContainer.get_span().add_exception_event(e, inspect.trace())
                raise
            finally:
                SpansContainer.get_span().end(ret_val)
                if Configuration.enhanced_print:
                    builtins.print = local_print
                    logging.Formatter.format = local_logging_format
            return ret_val
        except Exception:
            # The case where our wrapping raised an exception
            if not executed:
                TimeoutMechanism.stop()
                get_logger().exception("exception in the wrapper", exc_info=True)
                return func(*args, **kwargs)
            else:
                raise
예제 #8
0
def parse_triggered_by(event: dict):
    """
    This function parses the event and build the dictionary that describes the given event.

    The current possible values are:
    * {triggeredBy: unknown}
    * {triggeredBy: apigw, api: <host>, resource: <>, httpMethod: <>, stage: <>, identity: <>, referer: <>}
    """
    with lumigo_safe_execute("triggered by"):
        if not isinstance(event, dict):
            return None
        if _is_supported_http_method(event):
            return parse_http_method(event)
        elif _is_supported_sns(event):
            return _parse_sns(event)
        elif _is_supported_streams(event):
            return _parse_streams(event)
        elif _is_supported_cw(event):
            return _parse_cw(event)
        elif _is_step_function(event):
            return _parse_step_function(event)

    return _parse_unknown(event)