Skip to content

Commit c623d10

Browse files
committed
docs(ASGI): clean up docs on logging setup
1 parent 21412f5 commit c623d10

File tree

3 files changed

+86
-76
lines changed

3 files changed

+86
-76
lines changed

docs/user/faq.rst

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,47 +1348,44 @@ To include multiple values, simply use ``"; "`` to separate each name-value
13481348
pair. For example, if you were to pass ``{'Cookie': 'xxx=yyy; hello=world'}``,
13491349
you would get ``{'cookies': {'xxx': 'yyy', 'hello': 'world'}}``.
13501350

1351-
Why do I not see error tracebacks in ASGI applications?
1352-
-------------------------------------------------------
1351+
Why do I see no error tracebacks in my ASGI application?
1352+
--------------------------------------------------------
13531353

1354-
When using Falcon with ASGI servers like Uvicorn,
1355-
you might notice that server errors do not display a traceback by default.
1356-
This behavior differs from WSGI applications, where errors are logged to `stderr`,
1357-
providing detailed tracebacks.
1354+
When using Falcon with an ASGI server like Uvicorn,
1355+
you might notice that server errors do not include any traceback by default.
1356+
This behavior differs from WSGI, where the PEP-3333 specification defines the
1357+
`wsgi.errors <https://peps.python.org/pep-3333/#environ-variables>`__ stream
1358+
(which Falcon utilizes to log unhandled
1359+
:class:`internal server errors <falcon.HTTPInternalServerError>`).
13581360

1359-
The reason for this is that ASGI does not define a standardized way to log errors back to the application server,
1360-
unlike WSGI. Therefore, you need to configure logging manually to see these tracebacks.
1361+
Since there is no standardized way to log errors back to the ASGI server,
1362+
the framework simply opts to log them using the ``falcon``
1363+
:class:`logger <logging.Logger>`.
13611364

1362-
Here’s how to set up logging in your ASGI Falcon application to capture error tracebacks:
1365+
The easiest way to get started is configuring the root logger via
1366+
:func:`logging.basicConfig`:
13631367

13641368
.. code:: python
13651369
13661370
import logging
1371+
13671372
import falcon
13681373
import falcon.asgi
13691374
13701375
logging.basicConfig(
1371-
format="%(asctime)s [%(levelname)s] %(message)s",
1372-
level=logging.INFO
1373-
)
1376+
format="%(asctime)s [%(levelname)s] %(message)s", level=logging.INFO)
1377+
13741378
1375-
class ThingsResource:
1379+
class FaultyResource:
13761380
async def on_get(self, req, resp):
13771381
raise ValueError('foo')
13781382
1379-
app = falcon.asgi.App()
1380-
things = ThingsResource()
1381-
app.add_route('/things', things)
1382-
1383-
By adding the above logging configuration, you will see tracebacks like this in your console:
13841383
1385-
.. code-block:: none
1384+
app = falcon.asgi.App()
1385+
app.add_route('/things', FaultyResource())
13861386
1387-
[ERROR] [FALCON] Unhandled exception in ASGI app
1388-
Traceback (most recent call last):
1389-
File "<...>", line 12, in on_get
1390-
raise ValueError('foo')
1391-
ValueError: foo
1387+
By adding the above logging configuration, you should now see tracebacks logged
1388+
to :any:`stderr <sys.stderr>` when accessing ``/things``.
13921389

1393-
For additional details on this topic,
1394-
please refer to :ref:`debugging-asgi-applications`.
1390+
For additional details on this topic,
1391+
please refer to :ref:`debugging_asgi_applications`.

docs/user/tutorial-asgi.rst

Lines changed: 62 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,68 @@ Woohoo, it works!!!
115115

116116
Well, sort of. Onwards to adding some real functionality!
117117

118+
.. _debugging_asgi_applications:
119+
120+
Debugging ASGI Applications
121+
---------------------------
122+
123+
While developing and testing a Falcon ASGI application along the lines of this
124+
tutorial, you may encounter unexpected issues or behaviors, be it a copy-paste
125+
mistake, an idea that didn't work out, or unusual input where validation falls
126+
outside of the scope of this tutorial.
127+
128+
Unlike WSGI, the ASGI specification has no standard mechanism for logging
129+
errors back to the application server, so Falcon falls back to the stdlib's
130+
:mod:`logging` (using the ``falcon`` :class:`logger <logging.Logger>`).
131+
132+
As a well-behaved library, Falcon does not configure any loggers since that
133+
might interfere with the user's logging setup.
134+
Here's how you can set up basic logging in your ASGI Falcon application via
135+
:func:`logging.basicConfig`:
136+
137+
.. code:: python
138+
139+
import logging
140+
141+
import falcon
142+
143+
logging.basicConfig(level=logging.INFO)
144+
145+
146+
class ErrorResource:
147+
def on_get(self, req, resp):
148+
raise Exception('Something went wrong!')
149+
150+
151+
app = falcon.App()
152+
app.add_route('/error', ErrorResource())
153+
154+
When the above route is accessed, Falcon will catch the unhandled exception and
155+
automatically log an error message. Below is an example of what the log output
156+
might look like:
157+
158+
.. code-block:: none
159+
160+
ERROR:falcon.asgi.app:Unhandled exception in ASGI application
161+
Traceback (most recent call last):
162+
File "/path/to/your/app.py", line 123, in __call__
163+
resp = resource.on_get(req, resp)
164+
File "/path/to/your/app.py", line 7, in on_get
165+
raise Exception("Something went wrong!")
166+
Exception: Something went wrong!
167+
168+
.. note::
169+
While logging is helpful for development and debugging, be mindful of
170+
logging sensitive information. Ensure that log files are stored securely
171+
and are not accessible to unauthorized users.
172+
173+
.. note::
174+
Unhandled errors are only logged automatically by Falcon's default error
175+
handler for :class:`Exception`. If you
176+
:meth:`replace this handler <falcon.asgi.App.add_error_handler>` with your
177+
own generic :class:`Exception` handler, you are responsible for logging or
178+
reporting these errors yourself.
179+
118180
.. _asgi_tutorial_config:
119181

120182
Configuration
@@ -963,54 +1025,6 @@ adding ``--cov-fail-under=100`` (or any other percent threshold) to our
9631025
tests in multiple environments would most probably involve running
9641026
``coverage`` directly, and combining results.
9651027

966-
.. _debugging-asgi-applications:
967-
968-
Debugging ASGI Applications
969-
---------------------------
970-
(This section also applies to WSGI applications)
971-
972-
While developing and testing ASGI applications, understanding how to configure
973-
and utilize logging can be helpful, especially when you encounter unexpected
974-
issues or behaviors.
975-
976-
By default, Falcon does not set up logging for you,
977-
but Python's built-in :mod:`logging` module provides a flexible framework for
978-
emitting and capturing log messages. Here's how you can set up basic logging in
979-
your ASGI Falcon application:
980-
981-
.. code:: python
982-
983-
import logging
984-
import falcon
985-
986-
logging.basicConfig(level=logging.INFO)
987-
988-
class ErrorResource:
989-
def on_get(self, req, resp):
990-
raise Exception('Something went wrong!')
991-
992-
app = falcon.App()
993-
app.add_route('/error', ErrorResource())
994-
995-
When the above route is accessed, Falcon will catch the unhandled exception and
996-
automatically log an error message. Below is an example of what the log output
997-
might look like:
998-
999-
.. code-block:: none
1000-
1001-
ERROR:falcon.asgi.app:Unhandled exception in ASGI application
1002-
Traceback (most recent call last):
1003-
File "path/to/falcon/app.py", line 123, in __call__
1004-
resp = resource.on_get(req, resp)
1005-
File "/path/to/your/app.py", line 7, in on_get
1006-
raise Exception("Something went wrong!")
1007-
Exception: Something went wrong!
1008-
1009-
.. note::
1010-
While logging is helpful for development and debugging, be mindful of logging
1011-
sensitive information. Ensure that log files are stored securely and are not
1012-
accessible to unauthorized users.
1013-
10141028
What Now?
10151029
---------
10161030

falcon/typing.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ def read(self, n: Optional[int] = ..., /) -> bytes: ...
3939

4040
# ASGI
4141
class AsyncReadableIO(Protocol):
42-
"""Async file-like protocol that defines only a read method, and is
43-
iterable.
42+
"""Async file-like protocol that defines only a read method, and is iterable.
4443
4544
.. versionadded:: 4.0
4645
"""

0 commit comments

Comments
 (0)