We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
FastApiIntegration hides request handler function name
### How do you use Sentry?

Sentry Saas (sentry.io)

### Version

1.31.0

### Steps to Reproduce

Use the python sentry sdk in conjunction with FastAPI and the NewRelic python agent. 
View transactions in the NewRelic UI. 

### Expected Result

The NewRelic transaction name should show the function name handling the FastAPI route. 

### Actual Result

New Relic services representing our new fastapi services are seeing significant time spent in a transaction named `sentry_sdk.integrations.fastapi:patch_get_request_handler.<locals>._sentry_get_request_handler.<locals>._sentry_call`.

![image](https://github.com/getsentry/sentry-python/assets/66433626/22bb7222-fb35-45fa-8b19-cba6432b8752)

The source code for `fastspi:patch_get_request_handler` wraps non-async request handlers in a local function called `_sentry_call`. This local function shares the same `__qualname__` responsible for the significant transaction time. The result is every route handler has the same name and it appears in New Relic that the service has one transaction type.  

Sentry sdk integrations wrap functions all the time to create sentry scope and yet we never have this problem. It appears the issue comes from a simple oversight when writing the fastapi integration. Other integrations use `sentry_sdk._functools:wraps` to wrap a function with sentry specific behavior, yet ensure the name, qualname, etc. are retrained from the wrapped function. 

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `sentry_sdk/integrations/fastapi.py`
Content:
```
1 import asyncio
2 from copy import deepcopy
3 
4 from sentry_sdk._types import TYPE_CHECKING
5 from sentry_sdk.hub import Hub, _should_send_default_pii
6 from sentry_sdk.integrations import DidNotEnable
7 from sentry_sdk.tracing import SOURCE_FOR_STYLE, TRANSACTION_SOURCE_ROUTE
8 from sentry_sdk.utils import transaction_from_function, logger
9 
10 if TYPE_CHECKING:
11     from typing import Any, Callable, Dict
12     from sentry_sdk.scope import Scope
13 
14 try:
15     from sentry_sdk.integrations.starlette import (
16         StarletteIntegration,
17         StarletteRequestExtractor,
18     )
19 except DidNotEnable:
20     raise DidNotEnable("Starlette is not installed")
21 
22 try:
23     import fastapi  # type: ignore
24 except ImportError:
25     raise DidNotEnable("FastAPI is not installed")
26 
27 
28 _DEFAULT_TRANSACTION_NAME = "generic FastAPI request"
29 
30 
31 class FastApiIntegration(StarletteIntegration):
32     identifier = "fastapi"
33 
34     @staticmethod
35     def setup_once():
36         # type: () -> None
37         patch_get_request_handler()
38 
39 
40 def _set_transaction_name_and_source(scope, transaction_style, request):
41     # type: (Scope, str, Any) -> None
42     name = ""
43 
44     if transaction_style == "endpoint":
45         endpoint = request.scope.get("endpoint")
46         if endpoint:
47             name = transaction_from_function(endpoint) or ""
48 
49     elif transaction_style == "url":
50         route = request.scope.get("route")
51         if route:
52             path = getattr(route, "path", None)
53             if path is not None:
54                 name = path
55 
56     if not name:
57         name = _DEFAULT_TRANSACTION_NAME
58         source = TRANSACTION_SOURCE_ROUTE
59     else:
60         source = SOURCE_FOR_STYLE[transaction_style]
61 
62     scope.set_transaction_name(name, source=source)
63     logger.debug(
64         "[FastAPI] Set transaction name and source on scope: %s / %s", name, source
65     )
66 
67 
68 def patch_get_request_handler():
69     # type: () -> None
70     old_get_request_handler = fastapi.routing.get_request_handler
71 
72     def _sentry_get_request_handler(*args, **kwargs):
73         # type: (*Any, **Any) -> Any
74         dependant = kwargs.get("dependant")
75         if (
76             dependant
77             and dependant.call is not None
78             and not asyncio.iscoroutinefunction(dependant.call)
79         ):
80             old_call = dependant.call
81 
82             def _sentry_call(*args, **kwargs):
83                 # type: (*Any, **Any) -> Any
84                 hub = Hub.current
85                 with hub.configure_scope() as sentry_scope:
86                     if sentry_scope.profile is not None:
87                         sentry_scope.profile.update_active_thread_id()
88                     return old_call(*args, **kwargs)
89 
90             dependant.call = _sentry_call
91 
92         old_app = old_get_request_handler(*args, **kwargs)
93 
94         async def _sentry_app(*args, **kwargs):
95             # type: (*Any, **Any) -> Any
96             hub = Hub.current
97             integration = hub.get_integration(FastApiIntegration)
98             if integration is None:
99                 return await old_app(*args, **kwargs)
100 
101             with hub.configure_scope() as sentry_scope:
102                 request = args[0]
103 
104                 _set_transaction_name_and_source(
105                     sentry_scope, integration.transaction_style, request
106                 )
107 
108                 extractor = StarletteRequestExtractor(request)
109                 info = await extractor.extract_request_info()
110 
111                 def _make_request_event_processor(req, integration):
112                     # type: (Any, Any) -> Callable[[Dict[str, Any], Dict[str, Any]], Dict[str, Any]]
113                     def event_processor(event, hint):
114                         # type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any]
115 
116                         # Extract information from request
117                         request_info = event.get("request", {})
118                         if info:
119                             if "cookies" in info and _should_send_default_pii():
120                                 request_info["cookies"] = info["cookies"]
121                             if "data" in info:
122                                 request_info["data"] = info["data"]
123                         event["request"] = deepcopy(request_info)
124 
125                         return event
126 
127                     return event_processor
128 
129                 sentry_scope._name = FastApiIntegration.identifier
130                 sentry_scope.add_event_processor(
131                     _make_request_event_processor(request, integration)
132                 )
133 
134             return await old_app(*args, **kwargs)
135 
136         return _sentry_app
137 
138     fastapi.routing.get_request_handler = _sentry_get_request_handler
139
```
--- 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()

```

diff --git a/sentry_sdk/integrations/fastapi.py b/sentry_sdk/integrations/fastapi.py
--- a/sentry_sdk/integrations/fastapi.py
+++ b/sentry_sdk/integrations/fastapi.py
@@ -1,6 +1,7 @@
 import asyncio
 from copy import deepcopy
 
+from sentry_sdk._functools import wraps
 from sentry_sdk._types import TYPE_CHECKING
 from sentry_sdk.hub import Hub, _should_send_default_pii
 from sentry_sdk.integrations import DidNotEnable
@@ -79,6 +80,7 @@
         ):
             old_call = dependant.call
 
+            @wraps(old_call)
             def _sentry_call(*args, **kwargs):
                 # type: (*Any, **Any) -> Any
                 hub = Hub.current

{"golden_diff": "diff --git a/sentry_sdk/integrations/fastapi.py b/sentry_sdk/integrations/fastapi.py\n--- a/sentry_sdk/integrations/fastapi.py\n+++ b/sentry_sdk/integrations/fastapi.py\n@@ -1,6 +1,7 @@\n import asyncio\n from copy import deepcopy\n \n+from sentry_sdk._functools import wraps\n from sentry_sdk._types import TYPE_CHECKING\n from sentry_sdk.hub import Hub, _should_send_default_pii\n from sentry_sdk.integrations import DidNotEnable\n@@ -79,6 +80,7 @@\n         ):\n             old_call = dependant.call\n \n+            @wraps(old_call)\n             def _sentry_call(*args, **kwargs):\n                 # type: (*Any, **Any) -> Any\n                 hub = Hub.current\n", "issue": "FastApiIntegration hides request handler function name\n### How do you use Sentry?\n\nSentry Saas (sentry.io)\n\n### Version\n\n1.31.0\n\n### Steps to Reproduce\n\nUse the python sentry sdk in conjunction with FastAPI and the NewRelic python agent. \r\nView transactions in the NewRelic UI. \n\n### Expected Result\n\nThe NewRelic transaction name should show the function name handling the FastAPI route. \n\n### Actual Result\n\nNew Relic services representing our new fastapi services are seeing significant time spent in a transaction named `sentry_sdk.integrations.fastapi:patch_get_request_handler.<locals>._sentry_get_request_handler.<locals>._sentry_call`.\r\n\r\n![image](https://github.com/getsentry/sentry-python/assets/66433626/22bb7222-fb35-45fa-8b19-cba6432b8752)\r\n\r\nThe source code for `fastspi:patch_get_request_handler` wraps non-async request handlers in a local function called `_sentry_call`. This local function shares the same `__qualname__` responsible for the significant transaction time. The result is every route handler has the same name and it appears in New Relic that the service has one transaction type.  \r\n\r\nSentry sdk integrations wrap functions all the time to create sentry scope and yet we never have this problem. It appears the issue comes from a simple oversight when writing the fastapi integration. Other integrations use `sentry_sdk._functools:wraps` to wrap a function with sentry specific behavior, yet ensure the name, qualname, etc. are retrained from the wrapped function. \n", "before_files": [{"content": "import asyncio\nfrom copy import deepcopy\n\nfrom sentry_sdk._types import TYPE_CHECKING\nfrom sentry_sdk.hub import Hub, _should_send_default_pii\nfrom sentry_sdk.integrations import DidNotEnable\nfrom sentry_sdk.tracing import SOURCE_FOR_STYLE, TRANSACTION_SOURCE_ROUTE\nfrom sentry_sdk.utils import transaction_from_function, logger\n\nif TYPE_CHECKING:\n    from typing import Any, Callable, Dict\n    from sentry_sdk.scope import Scope\n\ntry:\n    from sentry_sdk.integrations.starlette import (\n        StarletteIntegration,\n        StarletteRequestExtractor,\n    )\nexcept DidNotEnable:\n    raise DidNotEnable(\"Starlette is not installed\")\n\ntry:\n    import fastapi  # type: ignore\nexcept ImportError:\n    raise DidNotEnable(\"FastAPI is not installed\")\n\n\n_DEFAULT_TRANSACTION_NAME = \"generic FastAPI request\"\n\n\nclass FastApiIntegration(StarletteIntegration):\n    identifier = \"fastapi\"\n\n    @staticmethod\n    def setup_once():\n        # type: () -> None\n        patch_get_request_handler()\n\n\ndef _set_transaction_name_and_source(scope, transaction_style, request):\n    # type: (Scope, str, Any) -> None\n    name = \"\"\n\n    if transaction_style == \"endpoint\":\n        endpoint = request.scope.get(\"endpoint\")\n        if endpoint:\n            name = transaction_from_function(endpoint) or \"\"\n\n    elif transaction_style == \"url\":\n        route = request.scope.get(\"route\")\n        if route:\n            path = getattr(route, \"path\", None)\n            if path is not None:\n                name = path\n\n    if not name:\n        name = _DEFAULT_TRANSACTION_NAME\n        source = TRANSACTION_SOURCE_ROUTE\n    else:\n        source = SOURCE_FOR_STYLE[transaction_style]\n\n    scope.set_transaction_name(name, source=source)\n    logger.debug(\n        \"[FastAPI] Set transaction name and source on scope: %s / %s\", name, source\n    )\n\n\ndef patch_get_request_handler():\n    # type: () -> None\n    old_get_request_handler = fastapi.routing.get_request_handler\n\n    def _sentry_get_request_handler(*args, **kwargs):\n        # type: (*Any, **Any) -> Any\n        dependant = kwargs.get(\"dependant\")\n        if (\n            dependant\n            and dependant.call is not None\n            and not asyncio.iscoroutinefunction(dependant.call)\n        ):\n            old_call = dependant.call\n\n            def _sentry_call(*args, **kwargs):\n                # type: (*Any, **Any) -> Any\n                hub = Hub.current\n                with hub.configure_scope() as sentry_scope:\n                    if sentry_scope.profile is not None:\n                        sentry_scope.profile.update_active_thread_id()\n                    return old_call(*args, **kwargs)\n\n            dependant.call = _sentry_call\n\n        old_app = old_get_request_handler(*args, **kwargs)\n\n        async def _sentry_app(*args, **kwargs):\n            # type: (*Any, **Any) -> Any\n            hub = Hub.current\n            integration = hub.get_integration(FastApiIntegration)\n            if integration is None:\n                return await old_app(*args, **kwargs)\n\n            with hub.configure_scope() as sentry_scope:\n                request = args[0]\n\n                _set_transaction_name_and_source(\n                    sentry_scope, integration.transaction_style, request\n                )\n\n                extractor = StarletteRequestExtractor(request)\n                info = await extractor.extract_request_info()\n\n                def _make_request_event_processor(req, integration):\n                    # type: (Any, Any) -> Callable[[Dict[str, Any], Dict[str, Any]], Dict[str, Any]]\n                    def event_processor(event, hint):\n                        # type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any]\n\n                        # Extract information from request\n                        request_info = event.get(\"request\", {})\n                        if info:\n                            if \"cookies\" in info and _should_send_default_pii():\n                                request_info[\"cookies\"] = info[\"cookies\"]\n                            if \"data\" in info:\n                                request_info[\"data\"] = info[\"data\"]\n                        event[\"request\"] = deepcopy(request_info)\n\n                        return event\n\n                    return event_processor\n\n                sentry_scope._name = FastApiIntegration.identifier\n                sentry_scope.add_event_processor(\n                    _make_request_event_processor(request, integration)\n                )\n\n            return await old_app(*args, **kwargs)\n\n        return _sentry_app\n\n    fastapi.routing.get_request_handler = _sentry_get_request_handler\n", "path": "sentry_sdk/integrations/fastapi.py"}], "after_files": [{"content": "import asyncio\nfrom copy import deepcopy\n\nfrom sentry_sdk._functools import wraps\nfrom sentry_sdk._types import TYPE_CHECKING\nfrom sentry_sdk.hub import Hub, _should_send_default_pii\nfrom sentry_sdk.integrations import DidNotEnable\nfrom sentry_sdk.tracing import SOURCE_FOR_STYLE, TRANSACTION_SOURCE_ROUTE\nfrom sentry_sdk.utils import transaction_from_function, logger\n\nif TYPE_CHECKING:\n    from typing import Any, Callable, Dict\n    from sentry_sdk.scope import Scope\n\ntry:\n    from sentry_sdk.integrations.starlette import (\n        StarletteIntegration,\n        StarletteRequestExtractor,\n    )\nexcept DidNotEnable:\n    raise DidNotEnable(\"Starlette is not installed\")\n\ntry:\n    import fastapi  # type: ignore\nexcept ImportError:\n    raise DidNotEnable(\"FastAPI is not installed\")\n\n\n_DEFAULT_TRANSACTION_NAME = \"generic FastAPI request\"\n\n\nclass FastApiIntegration(StarletteIntegration):\n    identifier = \"fastapi\"\n\n    @staticmethod\n    def setup_once():\n        # type: () -> None\n        patch_get_request_handler()\n\n\ndef _set_transaction_name_and_source(scope, transaction_style, request):\n    # type: (Scope, str, Any) -> None\n    name = \"\"\n\n    if transaction_style == \"endpoint\":\n        endpoint = request.scope.get(\"endpoint\")\n        if endpoint:\n            name = transaction_from_function(endpoint) or \"\"\n\n    elif transaction_style == \"url\":\n        route = request.scope.get(\"route\")\n        if route:\n            path = getattr(route, \"path\", None)\n            if path is not None:\n                name = path\n\n    if not name:\n        name = _DEFAULT_TRANSACTION_NAME\n        source = TRANSACTION_SOURCE_ROUTE\n    else:\n        source = SOURCE_FOR_STYLE[transaction_style]\n\n    scope.set_transaction_name(name, source=source)\n    logger.debug(\n        \"[FastAPI] Set transaction name and source on scope: %s / %s\", name, source\n    )\n\n\ndef patch_get_request_handler():\n    # type: () -> None\n    old_get_request_handler = fastapi.routing.get_request_handler\n\n    def _sentry_get_request_handler(*args, **kwargs):\n        # type: (*Any, **Any) -> Any\n        dependant = kwargs.get(\"dependant\")\n        if (\n            dependant\n            and dependant.call is not None\n            and not asyncio.iscoroutinefunction(dependant.call)\n        ):\n            old_call = dependant.call\n\n            @wraps(old_call)\n            def _sentry_call(*args, **kwargs):\n                # type: (*Any, **Any) -> Any\n                hub = Hub.current\n                with hub.configure_scope() as sentry_scope:\n                    if sentry_scope.profile is not None:\n                        sentry_scope.profile.update_active_thread_id()\n                    return old_call(*args, **kwargs)\n\n            dependant.call = _sentry_call\n\n        old_app = old_get_request_handler(*args, **kwargs)\n\n        async def _sentry_app(*args, **kwargs):\n            # type: (*Any, **Any) -> Any\n            hub = Hub.current\n            integration = hub.get_integration(FastApiIntegration)\n            if integration is None:\n                return await old_app(*args, **kwargs)\n\n            with hub.configure_scope() as sentry_scope:\n                request = args[0]\n\n                _set_transaction_name_and_source(\n                    sentry_scope, integration.transaction_style, request\n                )\n\n                extractor = StarletteRequestExtractor(request)\n                info = await extractor.extract_request_info()\n\n                def _make_request_event_processor(req, integration):\n                    # type: (Any, Any) -> Callable[[Dict[str, Any], Dict[str, Any]], Dict[str, Any]]\n                    def event_processor(event, hint):\n                        # type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any]\n\n                        # Extract information from request\n                        request_info = event.get(\"request\", {})\n                        if info:\n                            if \"cookies\" in info and _should_send_default_pii():\n                                request_info[\"cookies\"] = info[\"cookies\"]\n                            if \"data\" in info:\n                                request_info[\"data\"] = info[\"data\"]\n                        event[\"request\"] = deepcopy(request_info)\n\n                        return event\n\n                    return event_processor\n\n                sentry_scope._name = FastApiIntegration.identifier\n                sentry_scope.add_event_processor(\n                    _make_request_event_processor(request, integration)\n                )\n\n            return await old_app(*args, **kwargs)\n\n        return _sentry_app\n\n    fastapi.routing.get_request_handler = _sentry_get_request_handler\n", "path": "sentry_sdk/integrations/fastapi.py"}]}