Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

How to log Quart requests to file? #340

Answered by catwell
joshft91 asked this question in Q&A
Discussion options

I have a very simple Quart app that I use for some local home automation. I'd like to log the default Quart requests to a file instead of the console/stdout.

When the app starts and a request is made (curl http://localhost/info), the following is printed to console/stdout:

 * Serving Quart app 'app2'
 * Debug mode: False
 * Please use an ASGI server (e.g. Hypercorn) directly in production
 * Running on http://0.0.0.0:5000 (CTRL + C to quit)
[2024年05月14日 09:11:52 -0500] [17720] [INFO] Running on http://0.0.0.0:5000 (CTRL + C to quit)
[2024年05月14日 09:12:02 -0500] [17720] [INFO] 127.0.0.1:64062 GET /info 1.1 200 16 11965
[2024年05月14日 09:12:02 -0500] [17720] [INFO] 127.0.0.1:64062 GET /info 1.1 - - 12964

I would like to be able to console log the last two lines (info about the request) to a log file. Despite many attempts to do so, I can never it to work. The closest I have gotten is with this code:

hypercorn_logger = logging.getLogger('hypercorn')
hypercorn_logger.addHandler(logging.FileHandler('test.log', 'w'))

However, it only logs this line to the file: Running on http://0.0.0.0:5000 (CTRL + C to quit). What am I missing?

Demo App Code
import logging
from quart import Quart
app = Quart(__name__)
@app.route('/info')
async def info():
 return "here's some info"
if __name__ == '__main__':
 app.run(host='0.0.0.0')

Versions:

  • Quart 0.19.5
  • Hypercorn 0.16.0
You must be logged in to vote

The reason is that when you use the development server with app.run() Quart overrides the Hypercorn config.

You can either use Hypercorn directly (like described here), or do this:

from collections.abc import Awaitable, Callable, Coroutine
from hypercorn.asyncio import serve
from hypercorn.config import Config as HyperConfig
from quart import Quart
class App(Quart):
 def run_task(
 self,
 host: str = "127.0.0.1",
 port: int = 5000,
 debug: bool | None = None,
 ca_certs: str | None = None,
 certfile: str | None = None,
 keyfile: str | None = None,
 shutdown_trigger: Callable[..., Awaitable[None]] | None = None,
 ) -> Coroutine[

Replies: 1 comment 3 replies

Comment options

The easiest way if you use Hypercorn is to set the accesslog variable in the config file.

You must be logged in to vote
3 replies
Comment options

if you use Hypercorn

I think Hypercorn gets used behind the scenes, right? I'm still running it as a Quart app with app.run().

When attempting to configure the Hypercorn accesslog option I still get the same behavior. My log file generates Running on http://127.0.0.1:5000 (CTRL + C to quit) to the specified FileHandler, but no other request information makes it there.

Am I setting the variable incorrectly?

import logging
from quart import Quart
from hypercorn.config import Config
app = Quart(__name__)
config = Config()
config.accesslog = '-'
hypercorn_logger = logging.getLogger('hypercorn')
hypercorn_logger.addHandler(logging.FileHandler('test.log', 'w'))
@app.route('/info')
async def info():
 return "here's some info"
if __name__ == '__main__':
 app.run()
Comment options

The reason is that when you use the development server with app.run() Quart overrides the Hypercorn config.

You can either use Hypercorn directly (like described here), or do this:

from collections.abc import Awaitable, Callable, Coroutine
from hypercorn.asyncio import serve
from hypercorn.config import Config as HyperConfig
from quart import Quart
class App(Quart):
 def run_task(
 self,
 host: str = "127.0.0.1",
 port: int = 5000,
 debug: bool | None = None,
 ca_certs: str | None = None,
 certfile: str | None = None,
 keyfile: str | None = None,
 shutdown_trigger: Callable[..., Awaitable[None]] | None = None,
 ) -> Coroutine[None, None, None]:
 config = HyperConfig()
 config.access_log_format = "%(h)s %(r)s %(s)s %(b)s %(D)s"
 config.accesslog = "test.log" # I modified this
 config.bind = [f"{host}:{port}"]
 config.ca_certs = ca_certs
 config.certfile = certfile
 if debug is not None:
 self.debug = debug
 config.errorlog = "-" # I modified this
 config.keyfile = keyfile
 return serve(self, config, shutdown_trigger=shutdown_trigger)
app = App(__name__)
@app.route("/info")
async def info():
 return "here's some info"
if __name__ == "__main__":
 app.run()
Answer selected by joshft91
Comment options

Thank you for taking the time to explain what's going on. I had a hunch that Quart was doing something goofy with Hypercorn but I couldn't find those references that you pointed out so I appreciate it.

It looks like the best thing to do is to run it using Hypercorn which I think I'll do; easy enough to spin up the app that way instead of overriding those properties. Thanks again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Q&A
Labels
None yet
2 participants

AltStyle によって変換されたページ (->オリジナル) /