On exiting due to an unhandled exception during the app initialization (lifespan), the process(es) spawned by multiprocessing.BaseContext.Process.start() in _populate() would have their stack traceback directly printed to stderr by BaseProcess:_bootstrap.
Using the user-configurable config.log logger instead makes the log output more consistent.
Notes on the changeset:
The exc_info is added and created manually to the logger.exception() call, as we're not in an except block and using exc_info=True wouldn't help as later sys.exc_info() wouldn't return anything. This tuple contains what's expected as per the documentation.
As we're not exiting the process by raising an unhandled exception anymore, we have to exit(1) in order for the "active" loop in hypercorn/run.py:run() to break and hypercorn to shutdown instead of respawning a process for the app. Exiting the process with an exception was also exiting with code 1 but also printed the stack traceback which is what we want to avoid.
Upon a failure at this point, nothing was initialized yet so it's safe to exit() without having to do any cleanup.
Motivation
We're using fastapi/hypercorn in production with structlog and a json formatter so the logs can be ingested by some logs storage and visualization tooling.
We've configured everything so the application outputs JSON logs but in the case the app fails to start, hypercorn was outputting a raw stack traceback to stderr, which isn't consistent with how the logging system was configured.
On exiting due to an unhandled exception during the app initialization (lifespan), the process(es) spawned by
multiprocessing.BaseContext.Process.start()
in_populate()
would have their stack traceback directly printed to stderr byBaseProcess:_bootstrap
.Using the user-configurable
config.log
logger instead makes the log output more consistent.Notes on the changeset:
exc_info
is added and created manually to thelogger.exception()
call, as we're not in anexcept
block and usingexc_info=True
wouldn't help as latersys.exc_info()
wouldn't return anything. This tuple contains what's expected as per the documentation.exit(1)
in order for the "active" loop inhypercorn/run.py:run()
to break and hypercorn to shutdown instead of respawning a process for the app. Exiting the process with an exception was also exiting with code 1 but also printed the stack traceback which is what we want to avoid.Motivation
We're using fastapi/hypercorn in production with structlog and a json formatter so the logs can be ingested by some logs storage and visualization tooling. We've configured everything so the application outputs JSON logs but in the case the app fails to start, hypercorn was outputting a raw stack traceback to stderr, which isn't consistent with how the logging system was configured.