We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Tornado integration does not capture formdata
There is no obvious way to get just formdata from Tornado's request object (not mixed with other request params), but I haven't done a lot of research on that.

--- 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/tornado.py`
Content:
```
1 import sys
2 import weakref
3 from inspect import iscoroutinefunction
4 
5 from sentry_sdk.hub import Hub, _should_send_default_pii
6 from sentry_sdk.utils import (
7     event_from_exception,
8     capture_internal_exceptions,
9     transaction_from_function,
10 )
11 from sentry_sdk.integrations import Integration
12 from sentry_sdk.integrations._wsgi_common import (
13     RequestExtractor,
14     _filter_headers,
15     _is_json_content_type,
16 )
17 from sentry_sdk.integrations.logging import ignore_logger
18 
19 from tornado.web import RequestHandler, HTTPError  # type: ignore
20 from tornado.gen import coroutine  # type: ignore
21 
22 if False:
23     from typing import Any
24     from typing import List
25     from typing import Optional
26     from typing import Dict
27     from typing import Callable
28 
29 
30 class TornadoIntegration(Integration):
31     identifier = "tornado"
32 
33     @staticmethod
34     def setup_once():
35         # type: () -> None
36         import tornado  # type: ignore
37 
38         tornado_version = getattr(tornado, "version_info", None)
39         if tornado_version is None or tornado_version < (5, 0):
40             raise RuntimeError("Tornado 5+ required")
41 
42         if sys.version_info < (3, 7):
43             # Tornado is async. We better have contextvars or we're going to leak
44             # state between requests.
45             raise RuntimeError(
46                 "The tornado integration for Sentry requires Python 3.7+"
47             )
48 
49         ignore_logger("tornado.application")
50         ignore_logger("tornado.access")
51 
52         old_execute = RequestHandler._execute
53 
54         awaitable = iscoroutinefunction(old_execute)
55 
56         if awaitable:
57             # Starting Tornado 6 RequestHandler._execute method is a standard Python coroutine (async/await)
58             # In that case our method should be a coroutine function too
59             async def sentry_execute_request_handler(self, *args, **kwargs):
60                 # type: (Any, *List, **Any) -> Any
61                 hub = Hub.current
62                 integration = hub.get_integration(TornadoIntegration)
63                 if integration is None:
64                     return await old_execute(self, *args, **kwargs)
65 
66                 weak_handler = weakref.ref(self)
67 
68                 with Hub(hub) as hub:
69                     with hub.configure_scope() as scope:
70                         scope.add_event_processor(_make_event_processor(weak_handler))
71                     return await old_execute(self, *args, **kwargs)
72 
73         else:
74 
75             @coroutine  # type: ignore
76             def sentry_execute_request_handler(self, *args, **kwargs):
77                 hub = Hub.current
78                 integration = hub.get_integration(TornadoIntegration)
79                 if integration is None:
80                     return old_execute(self, *args, **kwargs)
81 
82                 weak_handler = weakref.ref(self)
83 
84                 with Hub(hub) as hub:
85                     with hub.configure_scope() as scope:
86                         scope.add_event_processor(_make_event_processor(weak_handler))
87                     result = yield from old_execute(self, *args, **kwargs)
88                     return result
89 
90         RequestHandler._execute = sentry_execute_request_handler
91 
92         old_log_exception = RequestHandler.log_exception
93 
94         def sentry_log_exception(self, ty, value, tb, *args, **kwargs):
95             # type: (Any, type, BaseException, Any, *Any, **Any) -> Optional[Any]
96             _capture_exception(ty, value, tb)
97             return old_log_exception(self, ty, value, tb, *args, **kwargs)
98 
99         RequestHandler.log_exception = sentry_log_exception
100 
101 
102 def _capture_exception(ty, value, tb):
103     # type: (type, BaseException, Any) -> None
104     hub = Hub.current
105     if hub.get_integration(TornadoIntegration) is None:
106         return
107     if isinstance(value, HTTPError):
108         return
109 
110     event, hint = event_from_exception(
111         (ty, value, tb),
112         client_options=hub.client.options,
113         mechanism={"type": "tornado", "handled": False},
114     )
115 
116     hub.capture_event(event, hint=hint)
117 
118 
119 def _make_event_processor(weak_handler):
120     # type: (Callable[[], RequestHandler]) -> Callable
121     def tornado_processor(event, hint):
122         # type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any]
123         handler = weak_handler()
124         if handler is None:
125             return event
126 
127         request = handler.request
128 
129         with capture_internal_exceptions():
130             method = getattr(handler, handler.request.method.lower())
131             event["transaction"] = transaction_from_function(method)
132 
133         with capture_internal_exceptions():
134             extractor = TornadoRequestExtractor(request)
135             extractor.extract_into_event(event)
136 
137             request_info = event["request"]
138 
139             request_info["url"] = "%s://%s%s" % (
140                 request.protocol,
141                 request.host,
142                 request.path,
143             )
144 
145             request_info["query_string"] = request.query
146             request_info["method"] = request.method
147             request_info["env"] = {"REMOTE_ADDR": request.remote_ip}
148             request_info["headers"] = _filter_headers(dict(request.headers))
149 
150         with capture_internal_exceptions():
151             if handler.current_user and _should_send_default_pii():
152                 event.setdefault("user", {})["is_authenticated"] = True
153 
154         return event
155 
156     return tornado_processor
157 
158 
159 class TornadoRequestExtractor(RequestExtractor):
160     def content_length(self):
161         # type: () -> int
162         if self.request.body is None:
163             return 0
164         return len(self.request.body)
165 
166     def cookies(self):
167         # type: () -> Dict
168         return {k: v.value for k, v in self.request.cookies.items()}
169 
170     def raw_data(self):
171         # type: () -> bytes
172         return self.request.body
173 
174     def form(self):
175         # type: () -> Optional[Any]
176         # TODO: Where to get formdata and nothing else?
177         return None
178 
179     def is_json(self):
180         # type: () -> bool
181         return _is_json_content_type(self.request.headers.get("content-type"))
182 
183     def files(self):
184         # type: () -> Dict
185         return {k: v[0] for k, v in self.request.files.items() if v}
186 
187     def size_of_file(self, file):
188         return len(file.body or ())
189
```
--- 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/tornado.py b/sentry_sdk/integrations/tornado.py
--- a/sentry_sdk/integrations/tornado.py
+++ b/sentry_sdk/integrations/tornado.py
@@ -173,8 +173,10 @@
 
     def form(self):
         # type: () -> Optional[Any]
-        # TODO: Where to get formdata and nothing else?
-        return None
+        return {
+            k: [v.decode("latin1", "replace") for v in vs]
+            for k, vs in self.request.body_arguments.items()
+        }
 
     def is_json(self):
         # type: () -> bool

{"golden_diff": "diff --git a/sentry_sdk/integrations/tornado.py b/sentry_sdk/integrations/tornado.py\n--- a/sentry_sdk/integrations/tornado.py\n+++ b/sentry_sdk/integrations/tornado.py\n@@ -173,8 +173,10 @@\n \n     def form(self):\n         # type: () -> Optional[Any]\n-        # TODO: Where to get formdata and nothing else?\n-        return None\n+        return {\n+            k: [v.decode(\"latin1\", \"replace\") for v in vs]\n+            for k, vs in self.request.body_arguments.items()\n+        }\n \n     def is_json(self):\n         # type: () -> bool\n", "issue": "Tornado integration does not capture formdata\nThere is no obvious way to get just formdata from Tornado's request object (not mixed with other request params), but I haven't done a lot of research on that.\n", "before_files": [{"content": "import sys\nimport weakref\nfrom inspect import iscoroutinefunction\n\nfrom sentry_sdk.hub import Hub, _should_send_default_pii\nfrom sentry_sdk.utils import (\n    event_from_exception,\n    capture_internal_exceptions,\n    transaction_from_function,\n)\nfrom sentry_sdk.integrations import Integration\nfrom sentry_sdk.integrations._wsgi_common import (\n    RequestExtractor,\n    _filter_headers,\n    _is_json_content_type,\n)\nfrom sentry_sdk.integrations.logging import ignore_logger\n\nfrom tornado.web import RequestHandler, HTTPError  # type: ignore\nfrom tornado.gen import coroutine  # type: ignore\n\nif False:\n    from typing import Any\n    from typing import List\n    from typing import Optional\n    from typing import Dict\n    from typing import Callable\n\n\nclass TornadoIntegration(Integration):\n    identifier = \"tornado\"\n\n    @staticmethod\n    def setup_once():\n        # type: () -> None\n        import tornado  # type: ignore\n\n        tornado_version = getattr(tornado, \"version_info\", None)\n        if tornado_version is None or tornado_version < (5, 0):\n            raise RuntimeError(\"Tornado 5+ required\")\n\n        if sys.version_info < (3, 7):\n            # Tornado is async. We better have contextvars or we're going to leak\n            # state between requests.\n            raise RuntimeError(\n                \"The tornado integration for Sentry requires Python 3.7+\"\n            )\n\n        ignore_logger(\"tornado.application\")\n        ignore_logger(\"tornado.access\")\n\n        old_execute = RequestHandler._execute\n\n        awaitable = iscoroutinefunction(old_execute)\n\n        if awaitable:\n            # Starting Tornado 6 RequestHandler._execute method is a standard Python coroutine (async/await)\n            # In that case our method should be a coroutine function too\n            async def sentry_execute_request_handler(self, *args, **kwargs):\n                # type: (Any, *List, **Any) -> Any\n                hub = Hub.current\n                integration = hub.get_integration(TornadoIntegration)\n                if integration is None:\n                    return await old_execute(self, *args, **kwargs)\n\n                weak_handler = weakref.ref(self)\n\n                with Hub(hub) as hub:\n                    with hub.configure_scope() as scope:\n                        scope.add_event_processor(_make_event_processor(weak_handler))\n                    return await old_execute(self, *args, **kwargs)\n\n        else:\n\n            @coroutine  # type: ignore\n            def sentry_execute_request_handler(self, *args, **kwargs):\n                hub = Hub.current\n                integration = hub.get_integration(TornadoIntegration)\n                if integration is None:\n                    return old_execute(self, *args, **kwargs)\n\n                weak_handler = weakref.ref(self)\n\n                with Hub(hub) as hub:\n                    with hub.configure_scope() as scope:\n                        scope.add_event_processor(_make_event_processor(weak_handler))\n                    result = yield from old_execute(self, *args, **kwargs)\n                    return result\n\n        RequestHandler._execute = sentry_execute_request_handler\n\n        old_log_exception = RequestHandler.log_exception\n\n        def sentry_log_exception(self, ty, value, tb, *args, **kwargs):\n            # type: (Any, type, BaseException, Any, *Any, **Any) -> Optional[Any]\n            _capture_exception(ty, value, tb)\n            return old_log_exception(self, ty, value, tb, *args, **kwargs)\n\n        RequestHandler.log_exception = sentry_log_exception\n\n\ndef _capture_exception(ty, value, tb):\n    # type: (type, BaseException, Any) -> None\n    hub = Hub.current\n    if hub.get_integration(TornadoIntegration) is None:\n        return\n    if isinstance(value, HTTPError):\n        return\n\n    event, hint = event_from_exception(\n        (ty, value, tb),\n        client_options=hub.client.options,\n        mechanism={\"type\": \"tornado\", \"handled\": False},\n    )\n\n    hub.capture_event(event, hint=hint)\n\n\ndef _make_event_processor(weak_handler):\n    # type: (Callable[[], RequestHandler]) -> Callable\n    def tornado_processor(event, hint):\n        # type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any]\n        handler = weak_handler()\n        if handler is None:\n            return event\n\n        request = handler.request\n\n        with capture_internal_exceptions():\n            method = getattr(handler, handler.request.method.lower())\n            event[\"transaction\"] = transaction_from_function(method)\n\n        with capture_internal_exceptions():\n            extractor = TornadoRequestExtractor(request)\n            extractor.extract_into_event(event)\n\n            request_info = event[\"request\"]\n\n            request_info[\"url\"] = \"%s://%s%s\" % (\n                request.protocol,\n                request.host,\n                request.path,\n            )\n\n            request_info[\"query_string\"] = request.query\n            request_info[\"method\"] = request.method\n            request_info[\"env\"] = {\"REMOTE_ADDR\": request.remote_ip}\n            request_info[\"headers\"] = _filter_headers(dict(request.headers))\n\n        with capture_internal_exceptions():\n            if handler.current_user and _should_send_default_pii():\n                event.setdefault(\"user\", {})[\"is_authenticated\"] = True\n\n        return event\n\n    return tornado_processor\n\n\nclass TornadoRequestExtractor(RequestExtractor):\n    def content_length(self):\n        # type: () -> int\n        if self.request.body is None:\n            return 0\n        return len(self.request.body)\n\n    def cookies(self):\n        # type: () -> Dict\n        return {k: v.value for k, v in self.request.cookies.items()}\n\n    def raw_data(self):\n        # type: () -> bytes\n        return self.request.body\n\n    def form(self):\n        # type: () -> Optional[Any]\n        # TODO: Where to get formdata and nothing else?\n        return None\n\n    def is_json(self):\n        # type: () -> bool\n        return _is_json_content_type(self.request.headers.get(\"content-type\"))\n\n    def files(self):\n        # type: () -> Dict\n        return {k: v[0] for k, v in self.request.files.items() if v}\n\n    def size_of_file(self, file):\n        return len(file.body or ())\n", "path": "sentry_sdk/integrations/tornado.py"}], "after_files": [{"content": "import sys\nimport weakref\nfrom inspect import iscoroutinefunction\n\nfrom sentry_sdk.hub import Hub, _should_send_default_pii\nfrom sentry_sdk.utils import (\n    event_from_exception,\n    capture_internal_exceptions,\n    transaction_from_function,\n)\nfrom sentry_sdk.integrations import Integration\nfrom sentry_sdk.integrations._wsgi_common import (\n    RequestExtractor,\n    _filter_headers,\n    _is_json_content_type,\n)\nfrom sentry_sdk.integrations.logging import ignore_logger\n\nfrom tornado.web import RequestHandler, HTTPError  # type: ignore\nfrom tornado.gen import coroutine  # type: ignore\n\nif False:\n    from typing import Any\n    from typing import List\n    from typing import Optional\n    from typing import Dict\n    from typing import Callable\n\n\nclass TornadoIntegration(Integration):\n    identifier = \"tornado\"\n\n    @staticmethod\n    def setup_once():\n        # type: () -> None\n        import tornado  # type: ignore\n\n        tornado_version = getattr(tornado, \"version_info\", None)\n        if tornado_version is None or tornado_version < (5, 0):\n            raise RuntimeError(\"Tornado 5+ required\")\n\n        if sys.version_info < (3, 7):\n            # Tornado is async. We better have contextvars or we're going to leak\n            # state between requests.\n            raise RuntimeError(\n                \"The tornado integration for Sentry requires Python 3.7+\"\n            )\n\n        ignore_logger(\"tornado.application\")\n        ignore_logger(\"tornado.access\")\n\n        old_execute = RequestHandler._execute\n\n        awaitable = iscoroutinefunction(old_execute)\n\n        if awaitable:\n            # Starting Tornado 6 RequestHandler._execute method is a standard Python coroutine (async/await)\n            # In that case our method should be a coroutine function too\n            async def sentry_execute_request_handler(self, *args, **kwargs):\n                # type: (Any, *List, **Any) -> Any\n                hub = Hub.current\n                integration = hub.get_integration(TornadoIntegration)\n                if integration is None:\n                    return await old_execute(self, *args, **kwargs)\n\n                weak_handler = weakref.ref(self)\n\n                with Hub(hub) as hub:\n                    with hub.configure_scope() as scope:\n                        scope.add_event_processor(_make_event_processor(weak_handler))\n                    return await old_execute(self, *args, **kwargs)\n\n        else:\n\n            @coroutine  # type: ignore\n            def sentry_execute_request_handler(self, *args, **kwargs):\n                hub = Hub.current\n                integration = hub.get_integration(TornadoIntegration)\n                if integration is None:\n                    return old_execute(self, *args, **kwargs)\n\n                weak_handler = weakref.ref(self)\n\n                with Hub(hub) as hub:\n                    with hub.configure_scope() as scope:\n                        scope.add_event_processor(_make_event_processor(weak_handler))\n                    result = yield from old_execute(self, *args, **kwargs)\n                    return result\n\n        RequestHandler._execute = sentry_execute_request_handler\n\n        old_log_exception = RequestHandler.log_exception\n\n        def sentry_log_exception(self, ty, value, tb, *args, **kwargs):\n            # type: (Any, type, BaseException, Any, *Any, **Any) -> Optional[Any]\n            _capture_exception(ty, value, tb)\n            return old_log_exception(self, ty, value, tb, *args, **kwargs)\n\n        RequestHandler.log_exception = sentry_log_exception\n\n\ndef _capture_exception(ty, value, tb):\n    # type: (type, BaseException, Any) -> None\n    hub = Hub.current\n    if hub.get_integration(TornadoIntegration) is None:\n        return\n    if isinstance(value, HTTPError):\n        return\n\n    event, hint = event_from_exception(\n        (ty, value, tb),\n        client_options=hub.client.options,\n        mechanism={\"type\": \"tornado\", \"handled\": False},\n    )\n\n    hub.capture_event(event, hint=hint)\n\n\ndef _make_event_processor(weak_handler):\n    # type: (Callable[[], RequestHandler]) -> Callable\n    def tornado_processor(event, hint):\n        # type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any]\n        handler = weak_handler()\n        if handler is None:\n            return event\n\n        request = handler.request\n\n        with capture_internal_exceptions():\n            method = getattr(handler, handler.request.method.lower())\n            event[\"transaction\"] = transaction_from_function(method)\n\n        with capture_internal_exceptions():\n            extractor = TornadoRequestExtractor(request)\n            extractor.extract_into_event(event)\n\n            request_info = event[\"request\"]\n\n            request_info[\"url\"] = \"%s://%s%s\" % (\n                request.protocol,\n                request.host,\n                request.path,\n            )\n\n            request_info[\"query_string\"] = request.query\n            request_info[\"method\"] = request.method\n            request_info[\"env\"] = {\"REMOTE_ADDR\": request.remote_ip}\n            request_info[\"headers\"] = _filter_headers(dict(request.headers))\n\n        with capture_internal_exceptions():\n            if handler.current_user and _should_send_default_pii():\n                event.setdefault(\"user\", {})[\"is_authenticated\"] = True\n\n        return event\n\n    return tornado_processor\n\n\nclass TornadoRequestExtractor(RequestExtractor):\n    def content_length(self):\n        # type: () -> int\n        if self.request.body is None:\n            return 0\n        return len(self.request.body)\n\n    def cookies(self):\n        # type: () -> Dict\n        return {k: v.value for k, v in self.request.cookies.items()}\n\n    def raw_data(self):\n        # type: () -> bytes\n        return self.request.body\n\n    def form(self):\n        # type: () -> Optional[Any]\n        return {\n            k: [v.decode(\"latin1\", \"replace\") for v in vs]\n            for k, vs in self.request.body_arguments.items()\n        }\n\n    def is_json(self):\n        # type: () -> bool\n        return _is_json_content_type(self.request.headers.get(\"content-type\"))\n\n    def files(self):\n        # type: () -> Dict\n        return {k: v[0] for k, v in self.request.files.items() if v}\n\n    def size_of_file(self, file):\n        return len(file.body or ())\n", "path": "sentry_sdk/integrations/tornado.py"}]}