Skip to content

Commit 15e17cf

Browse files
authored
feat(asgi): no longer add NullHandler to the falcon logger (#2595)
1 parent ecb7218 commit 15e17cf

File tree

6 files changed

+83
-6
lines changed

6 files changed

+83
-6
lines changed

MANIFEST.in

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
recursive-include docs *.rst *.md *.html *.ico *.png *.py *.svg
22
recursive-include e2e-tests *.py *.css *.html *.js
3-
recursive-include examples *.py
3+
recursive-include examples *.py *.yaml
44
recursive-include falcon *.pyx
55
recursive-include tests *.py *.pyx
66
include .coveragerc
@@ -14,6 +14,8 @@ include docs/conf.py docs/Makefile
1414
include falcon/py.typed
1515
graft docs/_static
1616
graft docs/_templates
17+
graft examples/asgilook/requirements
18+
graft examples/look/requirements
1719
graft requirements
1820
graft tools
1921
prune docs/_build

docs/_newsfragments/2594.misc.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Falcon no longer adds an instance of :class:`logging.NullHandler` to the
2+
``falcon`` logger, so ASGI application tracebacks may still reach
3+
``sys.stderr`` via the :any:`logging.lastResort` handler in the absence of
4+
configuration (see also: :ref:`debugging_asgi_applications`).

docs/user/faq.rst

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1414,7 +1414,7 @@ is non-zero, we can overwrite that value in the header.
14141414
Why do I see no error tracebacks in my ASGI application?
14151415
--------------------------------------------------------
14161416

1417-
When using Falcon with an ASGI server like Uvicorn,
1417+
When using Falcon with an ASGI server,
14181418
you might notice that server errors do not include any traceback by default.
14191419
This behavior differs from WSGI, where the PEP-3333 specification defines the
14201420
`wsgi.errors <https://peps.python.org/pep-3333/#environ-variables>`__ stream
@@ -1424,8 +1424,17 @@ This behavior differs from WSGI, where the PEP-3333 specification defines the
14241424
Since there is no standardized way to log errors back to the ASGI server,
14251425
the framework simply opts to log them using the ``falcon``
14261426
:class:`logger <logging.Logger>`.
1427+
As a well-behaved library, Falcon does not preconfigure any loggers since that
1428+
might interfere with the user's logging setup.
14271429

1428-
The easiest way to get started is configuring the root logger via
1430+
Starting with Falcon :doc:`4.3 </changes/4.3.0>`, however, the framework no
1431+
longer adds an instance of :class:`logging.NullHandler` to the ``falcon``
1432+
logger, so error tracebacks may still reach ``sys.stderr`` via the
1433+
:any:`logging.lastResort` handler (but it depends on the existing logging
1434+
configuration of the ASGI server in question).
1435+
1436+
If you are seeing an HTTP 500 error response without any corresponding
1437+
traceback, the easiest way to get started is configuring the root logger via
14291438
:func:`logging.basicConfig`:
14301439

14311440
.. code:: python
@@ -1451,4 +1460,4 @@ By adding the above logging configuration, you should now see tracebacks logged
14511460
to :any:`stderr <sys.stderr>` when accessing ``/things``.
14521461

14531462
For additional details on this topic,
1454-
please refer to :ref:`debugging_asgi_applications`.
1463+
please refer to the ASGI tutorial: :ref:`debugging_asgi_applications`.

docs/user/tutorial-asgi.rst

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,13 @@ Unlike WSGI, the ASGI specification has no standard mechanism for logging
129129
errors back to the application server, so Falcon falls back to the stdlib's
130130
:mod:`logging` (using the ``falcon`` :class:`logger <logging.Logger>`).
131131

132-
As a well-behaved library, Falcon does not configure any loggers since that
132+
As a well-behaved library, Falcon does not preconfigure any loggers since that
133133
might interfere with the user's logging setup.
134+
(Starting with Falcon :doc:`4.3 </changes/4.3.0>`, however, the framework no
135+
longer adds an instance of :class:`logging.NullHandler` to the ``falcon``
136+
logger, so error tracebacks may still reach ``sys.stderr`` via the
137+
:any:`logging.lastResort` handler.)
138+
134139
Here's how you can set up basic logging in your ASGI Falcon application via
135140
:func:`logging.basicConfig`:
136141

@@ -165,6 +170,23 @@ might look like:
165170
raise Exception("Something went wrong!")
166171
Exception: Something went wrong!
167172
173+
Your ASGI application server may also provide means to configure logging.
174+
For instance, Uvicorn (that we are using in this tutorial) can be pointed to a
175+
logging configuration via the ``--log-config`` command line parameter (or via
176+
its config file)::
177+
178+
uvicorn --log-config logging.yaml asgilook.app:app
179+
180+
A suitable logging configuration (including the ``falcon`` logger) for Uvicorn
181+
could look like:
182+
183+
.. literalinclude:: ../../examples/asgilook/logging.yaml
184+
:caption: logging.yaml
185+
:language: python
186+
187+
Falcon's tracebacks should now blend into Uvicorn's own logs seamlessly.
188+
You can also configure logging to files, syslog, or other destinations, in this way.
189+
168190
.. note::
169191
While logging is helpful for development and debugging, be mindful of
170192
logging sensitive information. Ensure that log files are stored securely

examples/asgilook/logging.yaml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
version: 1
2+
disable_existing_loggers: false
3+
formatters:
4+
default:
5+
(): 'uvicorn.logging.DefaultFormatter'
6+
fmt: '%(levelprefix)s [%(asctime)s] %(message)s'
7+
access:
8+
(): 'uvicorn.logging.AccessFormatter'
9+
fmt: '%(levelprefix)s [%(asctime)s] %(client_addr)s - "%(request_line)s" %(status_code)s'
10+
handlers:
11+
default:
12+
class: logging.StreamHandler
13+
formatter: default
14+
stream: ext://sys.stderr
15+
access:
16+
class: logging.StreamHandler
17+
formatter: access
18+
stream: ext://sys.stdout
19+
loggers:
20+
falcon:
21+
level: WARNING
22+
handlers:
23+
- default
24+
uvicorn:
25+
level: INFO
26+
handlers:
27+
- default
28+
uvicorn.access:
29+
level: INFO
30+
propagate: false
31+
handlers:
32+
- access

falcon/__init__.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -649,4 +649,12 @@
649649
# NOTE(kgriffs): Only to be used internally on the rare occasion that we
650650
# need to log something that we can't communicate any other way.
651651
_logger = _logging.getLogger('falcon')
652-
_logger.addHandler(_logging.NullHandler())
652+
653+
# NOTE(vytas): We used to add a NullHandler() to the above _logger;
654+
# which *could* be done according to the stdlib's docs,
655+
# "*if* you want to prevent your library's logged events being output to
656+
# sys.stderr in the absence of logging configuration".
657+
#
658+
# However, this has mostly resulted in confusion for people trying the ASGI
659+
# flavor of the framework as HTTP 500 tracebacks may disappear completely,
660+
# so the revised choice is NOT to prevent last resort logging to sys.stderr.

0 commit comments

Comments
 (0)