def asgi_track_request_data(scope, tracked_request): """ Track request data from an ASGI HTTP or Websocket scope. """ path = scope.get("root_path", "") + scope["path"] query_params = parse_qsl(scope.get("query_string", b"").decode("utf-8")) tracked_request.tag("path", create_filtered_path(path, query_params)) if ignore_path(path): tracked_request.tag("ignore_transaction", True) # We only care about the last values of headers so don't care that we use # a plain dict rather than a multi-value dict headers = {k.lower(): v for k, v in scope.get("headers", ())} if scout_config.value("collect_remote_ip"): user_ip = ( headers.get(b"x-forwarded-for", b"").decode("latin1").split(",")[0] or headers.get(b"client-ip", b"").decode("latin1").split(",")[0] or scope.get("client", ("", ))[0]) tracked_request.tag("user_ip", user_ip) queue_time = headers.get(b"x-queue-start", b"") or headers.get( b"x-request-start", b"") tracked_queue_time = track_request_queue_time(queue_time.decode("latin1"), tracked_request) if not tracked_queue_time: amazon_queue_time = headers.get(b"x-amzn-trace-id", b"") track_amazon_request_queue_time(amazon_queue_time.decode("latin1"), tracked_request)
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()