prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Report error requests on Pyramid
  Currently if an error occurs in a Pyramid request, we don't report it. Error cases can be just as useful to see so we should try and do this. It looks like it's possible by rearranging the existing code.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `src/scout_apm/pyramid.py`
  Content:
  ```
  1 # coding=utf-8
  2 from __future__ import absolute_import, division, print_function, unicode_literals
  3 
  4 import scout_apm.core
  5 from scout_apm.core.config import ScoutConfig
  6 from scout_apm.core.tracked_request import TrackedRequest
  7 from scout_apm.core.web_requests import (
  8     create_filtered_path,
  9     ignore_path,
  10     track_amazon_request_queue_time,
  11     track_request_queue_time,
  12 )
  13 
  14 
  15 def includeme(config):
  16     configs = {}
  17     pyramid_config = config.get_settings()
  18     for name in pyramid_config:
  19         if name.startswith("SCOUT_"):
  20             value = pyramid_config[name]
  21             clean_name = name.replace("SCOUT_", "").lower()
  22             configs[clean_name] = value
  23     ScoutConfig.set(**configs)
  24 
  25     if scout_apm.core.install():
  26         config.add_tween("scout_apm.pyramid.instruments")
  27 
  28 
  29 def instruments(handler, registry):
  30     def scout_tween(request):
  31         tracked_request = TrackedRequest.instance()
  32         span = tracked_request.start_span(operation="Controller/Pyramid")
  33 
  34         try:
  35             path = request.path
  36             # mixed() returns values as *either* single items or lists
  37             url_params = [
  38                 (k, v) for k, vs in request.GET.dict_of_lists().items() for v in vs
  39             ]
  40             tracked_request.tag("path", create_filtered_path(path, url_params))
  41             if ignore_path(path):
  42                 tracked_request.tag("ignore_transaction", True)
  43 
  44             try:
  45                 # Determine a remote IP to associate with the request. The value is
  46                 # spoofable by the requester so this is not suitable to use in any
  47                 # security sensitive context.
  48                 user_ip = (
  49                     request.headers.get("x-forwarded-for", default="").split(",")[0]
  50                     or request.headers.get("client-ip", default="").split(",")[0]
  51                     or request.remote_addr
  52                 )
  53             except Exception:
  54                 pass
  55             else:
  56                 tracked_request.tag("user_ip", user_ip)
  57 
  58             tracked_queue_time = False
  59             try:
  60                 queue_time = request.headers.get(
  61                     "x-queue-start", default=""
  62                 ) or request.headers.get("x-request-start", default="")
  63             except Exception:
  64                 pass
  65             else:
  66                 tracked_queue_time = track_request_queue_time(
  67                     queue_time, tracked_request
  68                 )
  69             if not tracked_queue_time:
  70                 try:
  71                     amazon_queue_time = request.headers.get(
  72                         "x-amzn-trace-id", default=""
  73                     )
  74                 except Exception:
  75                     pass
  76                 else:
  77                     track_amazon_request_queue_time(amazon_queue_time, tracked_request)
  78 
  79             try:
  80                 response = handler(request)
  81             except Exception:
  82                 tracked_request.tag("error", "true")
  83                 raise
  84 
  85             # This happens further down the call chain. So time it starting
  86             # above, but only name it if it gets to here.
  87             if request.matched_route is not None:
  88                 tracked_request.mark_real_request()
  89                 span.operation = "Controller/" + request.matched_route.name
  90 
  91         finally:
  92             tracked_request.stop_span()
  93 
  94         return response
  95 
  96     return scout_tween
  97
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/src/scout_apm/pyramid.py b/src/scout_apm/pyramid.py
  --- a/src/scout_apm/pyramid.py
  +++ b/src/scout_apm/pyramid.py
  @@ -77,17 +77,18 @@
                       track_amazon_request_queue_time(amazon_queue_time, tracked_request)
   
               try:
  -                response = handler(request)
  +                try:
  +                    response = handler(request)
  +                finally:
  +                    # Routing further down the call chain. So time it starting
  +                    # above, but only name it if it gets a name
  +                    if request.matched_route is not None:
  +                        tracked_request.mark_real_request()
  +                        span.operation = "Controller/" + request.matched_route.name
               except Exception:
                   tracked_request.tag("error", "true")
                   raise
   
  -            # This happens further down the call chain. So time it starting
  -            # above, but only name it if it gets to here.
  -            if request.matched_route is not None:
  -                tracked_request.mark_real_request()
  -                span.operation = "Controller/" + request.matched_route.name
  -
           finally:
               tracked_request.stop_span()
  
verification_info: {"golden_diff": "diff --git a/src/scout_apm/pyramid.py b/src/scout_apm/pyramid.py\n--- a/src/scout_apm/pyramid.py\n+++ b/src/scout_apm/pyramid.py\n@@ -77,17 +77,18 @@\n                     track_amazon_request_queue_time(amazon_queue_time, tracked_request)\n \n             try:\n-                response = handler(request)\n+                try:\n+                    response = handler(request)\n+                finally:\n+                    # Routing further down the call chain. So time it starting\n+                    # above, but only name it if it gets a name\n+                    if request.matched_route is not None:\n+                        tracked_request.mark_real_request()\n+                        span.operation = \"Controller/\" + request.matched_route.name\n             except Exception:\n                 tracked_request.tag(\"error\", \"true\")\n                 raise\n \n-            # This happens further down the call chain. So time it starting\n-            # above, but only name it if it gets to here.\n-            if request.matched_route is not None:\n-                tracked_request.mark_real_request()\n-                span.operation = \"Controller/\" + request.matched_route.name\n-\n         finally:\n             tracked_request.stop_span()\n", "issue": "Report error requests on Pyramid\nCurrently if an error occurs in a Pyramid request, we don't report it. Error cases can be just as useful to see so we should try and do this. It looks like it's possible by rearranging the existing code.\n", "before_files": [{"content": "# coding=utf-8\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nimport scout_apm.core\nfrom scout_apm.core.config import ScoutConfig\nfrom scout_apm.core.tracked_request import TrackedRequest\nfrom scout_apm.core.web_requests import (\n    create_filtered_path,\n    ignore_path,\n    track_amazon_request_queue_time,\n    track_request_queue_time,\n)\n\n\ndef includeme(config):\n    configs = {}\n    pyramid_config = config.get_settings()\n    for name in pyramid_config:\n        if name.startswith(\"SCOUT_\"):\n            value = pyramid_config[name]\n            clean_name = name.replace(\"SCOUT_\", \"\").lower()\n            configs[clean_name] = value\n    ScoutConfig.set(**configs)\n\n    if scout_apm.core.install():\n        config.add_tween(\"scout_apm.pyramid.instruments\")\n\n\ndef instruments(handler, registry):\n    def scout_tween(request):\n        tracked_request = TrackedRequest.instance()\n        span = tracked_request.start_span(operation=\"Controller/Pyramid\")\n\n        try:\n            path = request.path\n            # mixed() returns values as *either* single items or lists\n            url_params = [\n                (k, v) for k, vs in request.GET.dict_of_lists().items() for v in vs\n            ]\n            tracked_request.tag(\"path\", create_filtered_path(path, url_params))\n            if ignore_path(path):\n                tracked_request.tag(\"ignore_transaction\", True)\n\n            try:\n                # Determine a remote IP to associate with the request. The value is\n                # spoofable by the requester so this is not suitable to use in any\n                # security sensitive context.\n                user_ip = (\n                    request.headers.get(\"x-forwarded-for\", default=\"\").split(\",\")[0]\n                    or request.headers.get(\"client-ip\", default=\"\").split(\",\")[0]\n                    or request.remote_addr\n                )\n            except Exception:\n                pass\n            else:\n                tracked_request.tag(\"user_ip\", user_ip)\n\n            tracked_queue_time = False\n            try:\n                queue_time = request.headers.get(\n                    \"x-queue-start\", default=\"\"\n                ) or request.headers.get(\"x-request-start\", default=\"\")\n            except Exception:\n                pass\n            else:\n                tracked_queue_time = track_request_queue_time(\n                    queue_time, tracked_request\n                )\n            if not tracked_queue_time:\n                try:\n                    amazon_queue_time = request.headers.get(\n                        \"x-amzn-trace-id\", default=\"\"\n                    )\n                except Exception:\n                    pass\n                else:\n                    track_amazon_request_queue_time(amazon_queue_time, tracked_request)\n\n            try:\n                response = handler(request)\n            except Exception:\n                tracked_request.tag(\"error\", \"true\")\n                raise\n\n            # This happens further down the call chain. So time it starting\n            # above, but only name it if it gets to here.\n            if request.matched_route is not None:\n                tracked_request.mark_real_request()\n                span.operation = \"Controller/\" + request.matched_route.name\n\n        finally:\n            tracked_request.stop_span()\n\n        return response\n\n    return scout_tween\n", "path": "src/scout_apm/pyramid.py"}], "after_files": [{"content": "# coding=utf-8\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nimport scout_apm.core\nfrom scout_apm.core.config import ScoutConfig\nfrom scout_apm.core.tracked_request import TrackedRequest\nfrom scout_apm.core.web_requests import (\n    create_filtered_path,\n    ignore_path,\n    track_amazon_request_queue_time,\n    track_request_queue_time,\n)\n\n\ndef includeme(config):\n    configs = {}\n    pyramid_config = config.get_settings()\n    for name in pyramid_config:\n        if name.startswith(\"SCOUT_\"):\n            value = pyramid_config[name]\n            clean_name = name.replace(\"SCOUT_\", \"\").lower()\n            configs[clean_name] = value\n    ScoutConfig.set(**configs)\n\n    if scout_apm.core.install():\n        config.add_tween(\"scout_apm.pyramid.instruments\")\n\n\ndef instruments(handler, registry):\n    def scout_tween(request):\n        tracked_request = TrackedRequest.instance()\n        span = tracked_request.start_span(operation=\"Controller/Pyramid\")\n\n        try:\n            path = request.path\n            # mixed() returns values as *either* single items or lists\n            url_params = [\n                (k, v) for k, vs in request.GET.dict_of_lists().items() for v in vs\n            ]\n            tracked_request.tag(\"path\", create_filtered_path(path, url_params))\n            if ignore_path(path):\n                tracked_request.tag(\"ignore_transaction\", True)\n\n            try:\n                # Determine a remote IP to associate with the request. The value is\n                # spoofable by the requester so this is not suitable to use in any\n                # security sensitive context.\n                user_ip = (\n                    request.headers.get(\"x-forwarded-for\", default=\"\").split(\",\")[0]\n                    or request.headers.get(\"client-ip\", default=\"\").split(\",\")[0]\n                    or request.remote_addr\n                )\n            except Exception:\n                pass\n            else:\n                tracked_request.tag(\"user_ip\", user_ip)\n\n            tracked_queue_time = False\n            try:\n                queue_time = request.headers.get(\n                    \"x-queue-start\", default=\"\"\n                ) or request.headers.get(\"x-request-start\", default=\"\")\n            except Exception:\n                pass\n            else:\n                tracked_queue_time = track_request_queue_time(\n                    queue_time, tracked_request\n                )\n            if not tracked_queue_time:\n                try:\n                    amazon_queue_time = request.headers.get(\n                        \"x-amzn-trace-id\", default=\"\"\n                    )\n                except Exception:\n                    pass\n                else:\n                    track_amazon_request_queue_time(amazon_queue_time, tracked_request)\n\n            try:\n                try:\n                    response = handler(request)\n                finally:\n                    # Routing further down the call chain. So time it starting\n                    # above, but only name it if it gets a name\n                    if request.matched_route is not None:\n                        tracked_request.mark_real_request()\n                        span.operation = \"Controller/\" + request.matched_route.name\n            except Exception:\n                tracked_request.tag(\"error\", \"true\")\n                raise\n\n        finally:\n            tracked_request.stop_span()\n\n        return response\n\n    return scout_tween\n", "path": "src/scout_apm/pyramid.py"}]}