We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Why is tornado.application logger ignored?
It appears Sentry do not report any logs from tornado.application logger

https://github.com/getsentry/sentry-python/blob/master/sentry_sdk/integrations/tornado.py#L53
    ignore_logger("tornado.application")

However, it seems the default logger used by Tornado to report unhandled exceptions:

https://github.com/tornadoweb/tornado/blob/682ff8dec2d095b339b62d875252be932ae4a5f2/tornado/web.py#L1762

    def log_exception(
        self,
        typ: "Optional[Type[BaseException]]",
        value: Optional[BaseException],
        tb: Optional[TracebackType],
    ) -> None:
        """Override to customize logging of uncaught exceptions.
        By default logs instances of `HTTPError` as warnings without
        stack traces (on the ``tornado.general`` logger), and all
        other exceptions as errors with stack traces (on the
        ``tornado.application`` logger).
        .. versionadded:: 3.1
        """
        if isinstance(value, HTTPError):
            if value.log_message:
                format = "%d %s: " + value.log_message
                args = [value.status_code, self._request_summary()] + list(value.args)
                gen_log.warning(format, *args)
        else:
            app_log.error(  # type: ignore
                "Uncaught exception %s\n%r",
                self._request_summary(),
                self.request,
                exc_info=(typ, value, tb),
            )

How are we supposed to propagate uncaught exceptions in a Tornado based application to Sentry with Tornado integration?

Thanks

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

{"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@@ -50,7 +50,6 @@\n                 \"The tornado integration for Sentry requires Python 3.6+ or the aiocontextvars package\"\n             )\n \n-        ignore_logger(\"tornado.application\")\n         ignore_logger(\"tornado.access\")\n \n         old_execute = RequestHandler._execute\n", "issue": "Why is tornado.application logger ignored?\nIt appears Sentry do not report any logs from tornado.application logger\r\n\r\nhttps://github.com/getsentry/sentry-python/blob/master/sentry_sdk/integrations/tornado.py#L53\r\n    ignore_logger(\"tornado.application\")\r\n\r\nHowever, it seems the default logger used by Tornado to report unhandled exceptions:\r\n\r\nhttps://github.com/tornadoweb/tornado/blob/682ff8dec2d095b339b62d875252be932ae4a5f2/tornado/web.py#L1762\r\n\r\n    def log_exception(\r\n        self,\r\n        typ: \"Optional[Type[BaseException]]\",\r\n        value: Optional[BaseException],\r\n        tb: Optional[TracebackType],\r\n    ) -> None:\r\n        \"\"\"Override to customize logging of uncaught exceptions.\r\n        By default logs instances of `HTTPError` as warnings without\r\n        stack traces (on the ``tornado.general`` logger), and all\r\n        other exceptions as errors with stack traces (on the\r\n        ``tornado.application`` logger).\r\n        .. versionadded:: 3.1\r\n        \"\"\"\r\n        if isinstance(value, HTTPError):\r\n            if value.log_message:\r\n                format = \"%d %s: \" + value.log_message\r\n                args = [value.status_code, self._request_summary()] + list(value.args)\r\n                gen_log.warning(format, *args)\r\n        else:\r\n            app_log.error(  # type: ignore\r\n                \"Uncaught exception %s\\n%r\",\r\n                self._request_summary(),\r\n                self.request,\r\n                exc_info=(typ, value, tb),\r\n            )\r\n\r\nHow are we supposed to propagate uncaught exceptions in a Tornado based application to Sentry with Tornado integration?\r\n\r\nThanks\n", "before_files": [{"content": "import weakref\nfrom inspect import iscoroutinefunction\n\nfrom sentry_sdk.hub import Hub, _should_send_default_pii\nfrom sentry_sdk.utils import (\n    HAS_REAL_CONTEXTVARS,\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\nfrom sentry_sdk._compat import iteritems\n\nfrom tornado.web import RequestHandler, HTTPError\nfrom tornado.gen import coroutine\n\nfrom sentry_sdk._types import MYPY\n\nif MYPY:\n    from typing import Any\n    from typing import Optional\n    from typing import Dict\n    from typing import Callable\n\n    from sentry_sdk._types import EventProcessor\n\n\nclass TornadoIntegration(Integration):\n    identifier = \"tornado\"\n\n    @staticmethod\n    def setup_once():\n        # type: () -> None\n        import tornado\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 not HAS_REAL_CONTEXTVARS:\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.6+ or the aiocontextvars package\"\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, *Any, **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.clear_breadcrumbs()\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                # type: (RequestHandler, *Any, **Any) -> Any\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    # If an integration is there, a client has to be there.\n    client = hub.client  # type: Any\n\n    event, hint = event_from_exception(\n        (ty, value, tb),\n        client_options=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]) -> EventProcessor\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[str, str]\n        return {k: v.value for k, v in iteritems(self.request.cookies)}\n\n    def raw_data(self):\n        # type: () -> bytes\n        return self.request.body\n\n    def form(self):\n        # type: () -> Dict[str, Any]\n        return {\n            k: [v.decode(\"latin1\", \"replace\") for v in vs]\n            for k, vs in iteritems(self.request.body_arguments)\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[str, Any]\n        return {k: v[0] for k, v in iteritems(self.request.files) if v}\n\n    def size_of_file(self, file):\n        # type: (Any) -> int\n        return len(file.body or ())\n", "path": "sentry_sdk/integrations/tornado.py"}], "after_files": [{"content": "import weakref\nfrom inspect import iscoroutinefunction\n\nfrom sentry_sdk.hub import Hub, _should_send_default_pii\nfrom sentry_sdk.utils import (\n    HAS_REAL_CONTEXTVARS,\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\nfrom sentry_sdk._compat import iteritems\n\nfrom tornado.web import RequestHandler, HTTPError\nfrom tornado.gen import coroutine\n\nfrom sentry_sdk._types import MYPY\n\nif MYPY:\n    from typing import Any\n    from typing import Optional\n    from typing import Dict\n    from typing import Callable\n\n    from sentry_sdk._types import EventProcessor\n\n\nclass TornadoIntegration(Integration):\n    identifier = \"tornado\"\n\n    @staticmethod\n    def setup_once():\n        # type: () -> None\n        import tornado\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 not HAS_REAL_CONTEXTVARS:\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.6+ or the aiocontextvars package\"\n            )\n\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, *Any, **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.clear_breadcrumbs()\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                # type: (RequestHandler, *Any, **Any) -> Any\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    # If an integration is there, a client has to be there.\n    client = hub.client  # type: Any\n\n    event, hint = event_from_exception(\n        (ty, value, tb),\n        client_options=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]) -> EventProcessor\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[str, str]\n        return {k: v.value for k, v in iteritems(self.request.cookies)}\n\n    def raw_data(self):\n        # type: () -> bytes\n        return self.request.body\n\n    def form(self):\n        # type: () -> Dict[str, Any]\n        return {\n            k: [v.decode(\"latin1\", \"replace\") for v in vs]\n            for k, vs in iteritems(self.request.body_arguments)\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[str, Any]\n        return {k: v[0] for k, v in iteritems(self.request.files) if v}\n\n    def size_of_file(self, file):\n        # type: (Any) -> int\n        return len(file.body or ())\n", "path": "sentry_sdk/integrations/tornado.py"}]}