def process_request(self, req, resp):
        tracked_request = TrackedRequest.instance()
        tracked_request.is_real_request = True
        req.context.scout_tracked_request = tracked_request

        path = req.path
        # Falcon URL parameter values are *either* single items or lists
        url_params = [
            (k, v)
            for k, vs in req.params.items()
            for v in (vs if isinstance(vs, list) else [vs])
        ]
        tracked_request.tag("path", create_filtered_path(path, url_params))
        if ignore_path(path):
            tracked_request.tag("ignore_transaction", True)

        # Determine a remote IP to associate with the request. The value is
        # spoofable by the requester so this is not suitable to use in any
        # security sensitive context.
        user_ip = (
            req.get_header("x-forwarded-for", default="").split(",")[0]
            or req.get_header("client-ip", default="").split(",")[0]
            or req.remote_addr
        )
        tracked_request.tag("user_ip", user_ip)

        queue_time = req.get_header("x-queue-start", default="") or req.get_header(
            "x-request-start", default=""
        )
        tracked_queue_time = track_request_queue_time(queue_time, tracked_request)
        if not tracked_queue_time:
            amazon_queue_time = req.get_header("x-amzn-trace-id", default="")
            track_amazon_request_queue_time(amazon_queue_time, tracked_request)
def track_request_view_data(request, tracked_request):
    path = request.path
    tracked_request.tag(
        "path",
        create_filtered_path(path, [(k, v) for k, vs in request.GET.lists()
                                    for v in vs]),
    )
    if ignore_path(path):
        tracked_request.tag("ignore_transaction", True)

    if scout_config.value("collect_remote_ip"):
        try:
            # Determine a remote IP to associate with the request. The value is
            # spoofable by the requester so this is not suitable to use in any
            # security sensitive context.
            user_ip = (request.META.get("HTTP_X_FORWARDED_FOR",
                                        "").split(",")[0]
                       or request.META.get("HTTP_CLIENT_IP", "").split(",")[0]
                       or request.META.get("REMOTE_ADDR", None))
            tracked_request.tag("user_ip", user_ip)
        except Exception:
            pass

    # Django's request.user caches in this attribute on first access. We only
    # want to track the user if the application code has touched request.user
    # because touching it causes session access, which adds "Cookie" to the
    # "Vary" header.
    user = getattr(request, "_cached_user", None)
    if user is not None:
        try:
            tracked_request.tag("username", user.get_username())
        except Exception:
            pass

    tracked_request.tag("urlconf", get_urlconf(settings.ROOT_URLCONF))
def track_request_view_data(request, tracked_request):
    path = request.path
    tracked_request.tag(
        "path",
        create_filtered_path(path, [(k, v) for k, vs in request.GET.lists()
                                    for v in vs]),
    )
    if ignore_path(path):
        tracked_request.tag("ignore_transaction", True)

    if scout_config.value("collect_remote_ip"):
        try:
            # Determine a remote IP to associate with the request. The value is
            # spoofable by the requester so this is not suitable to use in any
            # security sensitive context.
            user_ip = (request.META.get("HTTP_X_FORWARDED_FOR",
                                        "").split(",")[0]
                       or request.META.get("HTTP_CLIENT_IP", "").split(",")[0]
                       or request.META.get("REMOTE_ADDR", None))
            tracked_request.tag("user_ip", user_ip)
        except Exception:
            pass

    user = getattr(request, "user", None)
    if user is not None:
        try:
            tracked_request.tag("username", user.get_username())
        except Exception:
            pass

    tracked_request.tag("urlconf", get_urlconf(settings.ROOT_URLCONF))
Beispiel #4
0
    def process_request(self, req, resp):
        if self._do_nothing:
            return
        if self.api is None and self.hug_http_interface is not None:
            self.api = self.hug_http_interface.falcon
        tracked_request = TrackedRequest.instance()
        tracked_request.is_real_request = True
        req.context.scout_tracked_request = tracked_request
        tracked_request.start_span(operation="Middleware",
                                   should_capture_backtrace=False)

        path = req.path
        # Falcon URL parameter values are *either* single items or lists
        url_params = [(k, v) for k, vs in req.params.items()
                      for v in (vs if isinstance(vs, list) else [vs])]
        tracked_request.tag("path", create_filtered_path(path, url_params))
        if ignore_path(path):
            tracked_request.tag("ignore_transaction", True)

        if scout_config.value("collect_remote_ip"):
            # Determine a remote IP to associate with the request. The value is
            # spoofable by the requester so this is not suitable to use in any
            # security sensitive context.
            user_ip = (req.get_header("x-forwarded-for",
                                      default="").split(",")[0]
                       or req.get_header("client-ip", default="").split(",")[0]
                       or req.remote_addr)
            tracked_request.tag("user_ip", user_ip)

        queue_time = req.get_header(
            "x-queue-start", default="") or req.get_header("x-request-start",
                                                           default="")
        track_request_queue_time(queue_time, tracked_request)
Beispiel #5
0
def test_create_filtered_path_path(path, params):
    # If config filtered_params is set to "path", expect we always get the path
    # back
    scout_config.set(uri_reporting="path")
    try:
        assert create_filtered_path(path, params) == path
    finally:
        scout_config.reset_all()
Beispiel #6
0
    def after_request(self):
        if self._do_nothing:
            return
        request = cherrypy.request
        tracked_request = getattr(request, "_scout_tracked_request", None)
        if tracked_request is None:
            return

        # Rename controller span now routing has been done
        operation_name = get_operation_name(request)
        if operation_name is not None:
            request._scout_controller_span.operation = operation_name

        # Grab general request data now it has been parsed
        path = request.path_info
        # Parse params ourselves because we want only GET params but CherryPy
        # parses POST params (nearly always sensitive) into the same dict.
        params = parse_qsl(request.query_string)
        tracked_request.tag("path", create_filtered_path(path, params))
        if ignore_path(path):
            tracked_request.tag("ignore_transaction", True)

        if scout_config.value("collect_remote_ip"):
            # Determine a remote IP to associate with the request. The value is
            # spoofable by the requester so this is not suitable to use in any
            # security sensitive context.
            user_ip = (
                request.headers.get("x-forwarded-for", "").split(",")[0]
                or request.headers.get("client-ip", "").split(",")[0]
                or (request.remote.ip or None)
            )
            tracked_request.tag("user_ip", user_ip)

        queue_time = request.headers.get("x-queue-start", "") or request.headers.get(
            "x-request-start", ""
        )
        tracked_queue_time = track_request_queue_time(queue_time, tracked_request)
        if not tracked_queue_time:
            amazon_queue_time = request.headers.get("x-amzn-trace-id", "")
            track_amazon_request_queue_time(amazon_queue_time, tracked_request)

        response = cherrypy.response
        status = response.status
        if isinstance(status, int):
            status_int = status
        else:
            status_first = status.split(" ", 1)[0]
            try:
                status_int = int(status_first)
            except ValueError:
                # Assume OK
                status_int = 200
        if 500 <= status_int <= 599:
            tracked_request.tag("error", "true")
        elif status_int == 404:
            tracked_request.is_real_request = False

        tracked_request.stop_span()
Beispiel #7
0
    def scout_tween(request):
        tracked_request = TrackedRequest.instance()
        span = tracked_request.start_span(operation="Controller/Pyramid",
                                          should_capture_backtrace=False)

        try:
            path = request.path
            # mixed() returns values as *either* single items or lists
            url_params = [(k, v)
                          for k, vs in request.GET.dict_of_lists().items()
                          for v in vs]
            tracked_request.tag("path", create_filtered_path(path, url_params))
            if ignore_path(path):
                tracked_request.tag("ignore_transaction", True)

            if scout_config.value("collect_remote_ip"):
                # Determine a remote IP to associate with the request. The value is
                # spoofable by the requester so this is not suitable to use in any
                # security sensitive context.
                user_ip = (request.headers.get("x-forwarded-for",
                                               default="").split(",")[0]
                           or request.headers.get("client-ip",
                                                  default="").split(",")[0]
                           or request.remote_addr)
                tracked_request.tag("user_ip", user_ip)

            tracked_queue_time = False
            queue_time = request.headers.get(
                "x-queue-start", default="") or request.headers.get(
                    "x-request-start", default="")
            tracked_queue_time = track_request_queue_time(
                queue_time, tracked_request)
            if not tracked_queue_time:
                amazon_queue_time = request.headers.get("x-amzn-trace-id",
                                                        default="")
                track_amazon_request_queue_time(amazon_queue_time,
                                                tracked_request)

            try:
                try:
                    response = handler(request)
                finally:
                    # Routing lives further down the call chain. So time it
                    # starting above, but only set the name if it gets a name
                    if request.matched_route is not None:
                        tracked_request.is_real_request = True
                        span.operation = "Controller/" + request.matched_route.name
            except Exception:
                tracked_request.tag("error", "true")
                raise

            if 500 <= response.status_code <= 599:
                tracked_request.tag("error", "true")
        finally:
            tracked_request.stop_span()

        return response
Beispiel #8
0
def wrap_callback(wrapped, instance, args, kwargs):
    tracked_request = TrackedRequest.instance()
    tracked_request.is_real_request = True

    path = request.path
    # allitems() is an undocumented bottle internal
    tracked_request.tag("path",
                        create_filtered_path(path, request.query.allitems()))
    if ignore_path(path):
        tracked_request.tag("ignore_transaction", True)

    if request.route.name is not None:
        controller_name = request.route.name
    else:
        controller_name = request.route.rule
    if controller_name == "/":
        controller_name = "/home"
    if not controller_name.startswith("/"):
        controller_name = "/" + controller_name
    tracked_request.start_span(
        operation="Controller{}".format(controller_name),
        should_capture_backtrace=False)

    if scout_config.value("collect_remote_ip"):
        # Determine a remote IP to associate with the request. The
        # value is spoofable by the requester so this is not suitable
        # to use in any security sensitive context.
        user_ip = (request.headers.get("x-forwarded-for", "").split(",")[0]
                   or request.headers.get("client-ip", "").split(",")[0]
                   or request.environ.get("REMOTE_ADDR"))
        tracked_request.tag("user_ip", user_ip)

    tracked_queue_time = False
    queue_time = request.headers.get(
        "x-queue-start", "") or request.headers.get("x-request-start", "")
    tracked_queue_time = track_request_queue_time(queue_time, tracked_request)
    if not tracked_queue_time:
        amazon_queue_time = request.headers.get("x-amzn-trace-id", "")
        track_amazon_request_queue_time(amazon_queue_time, tracked_request)

    try:
        value = wrapped(*args, **kwargs)
    except Exception:
        tracked_request.tag("error", "true")
        raise
    else:
        if 500 <= response.status_code <= 599:
            tracked_request.tag("error", "true")
        return value
    finally:
        tracked_request.stop_span()
Beispiel #9
0
def test_create_filtered_path(path, params, expected):
    assert create_filtered_path(path, params) == expected
Beispiel #10
0
    async def __call__(self, scope, receive, send):
        if self._do_nothing or scope["type"] != "http":
            await self.app(scope, receive, send)
            return

        request = Request(scope)
        tracked_request = TrackedRequest.instance()
        # Can't name controller until post-routing - see final clause
        controller_span = tracked_request.start_span(operation="Controller/Unknown")

        tracked_request.tag(
            "path",
            create_filtered_path(request.url.path, request.query_params.multi_items()),
        )
        if ignore_path(request.url.path):
            tracked_request.tag("ignore_transaction", True)

        user_ip = (
            request.headers.get("x-forwarded-for", default="").split(",")[0]
            or request.headers.get("client-ip", default="").split(",")[0]
            or request.client.host
        )
        tracked_request.tag("user_ip", user_ip)

        queue_time = request.headers.get(
            "x-queue-start", default=""
        ) or request.headers.get("x-request-start", default="")
        tracked_queue_time = track_request_queue_time(queue_time, tracked_request)
        if not tracked_queue_time:
            amazon_queue_time = request.headers.get("x-amzn-trace-id", default="")
            track_amazon_request_queue_time(amazon_queue_time, tracked_request)

        def grab_extra_data():
            if "endpoint" in scope:
                # Rename top span
                endpoint = scope["endpoint"]
                controller_span.operation = "Controller/{}.{}".format(
                    endpoint.__module__, endpoint.__qualname__
                )
                tracked_request.is_real_request = True

            # From AuthenticationMiddleware - bypass request.user because it
            # throws AssertionError if 'user' is not in Scope, and we need a
            # try/except already
            try:
                username = scope["user"].display_name
            except (KeyError, AttributeError):
                pass
            else:
                tracked_request.tag("username", username)

        async def wrapped_send(data):
            # Finish HTTP span when body finishes sending, not later (e.g.
            # after background tasks)
            if data.get("type", None) == "http.response.body" and not data.get(
                "more_body", False
            ):
                grab_extra_data()
                tracked_request.stop_span()
            return await send(data)

        try:
            await self.app(scope, receive, wrapped_send)
        except Exception as exc:
            tracked_request.tag("error", "true")
            raise exc
        finally:
            if tracked_request.end_time is None:
                grab_extra_data()
                tracked_request.stop_span()