Gunicorn
See every request your app handles when it runs under Gunicorn, across all of Gunicorn’s worker processes, as spans (each span is one unit of work with a name, a start, and a duration) in Logfire.
Gunicorn is a Python web server that runs your app in several worker processes at once, forking a fresh process for each. Because those workers are created after Gunicorn starts, Logfire has to be set up inside each worker rather than once at startup. This page shows where.
- Each request as a span, no matter which worker process handled it
- The duration and status of every request across all workers
- Any errors raised while handling a request
You’ll need a Logfire project. Open Add data in your project (top navigation) and follow the
setup for your language: it signs your machine in with logfire auth (a browser sign-in, no token
to copy) and, for production or other languages, creates a write token (the credential your app
uses to send data). New to Logfire? Start with Getting Started.
Install logfire:
pip install logfire
uv add logfire
conda install -c conda-forge logfire
If you also want to instrument the web framework you run under Gunicorn (Flask, for example), install its extra too. See that framework’s integration page.
Call logfire.configure() in Gunicorn’s
post_fork hook (the function Gunicorn
runs in each worker process right after it forks) so every worker sends data:
import logfire
def post_fork(server, worker):
logfire.configure()
Then start Gunicorn with that configuration file, where myapp:app is your WSGI application:
gunicorn myapp:app --config gunicorn_config.py
Start Gunicorn and open one of your pages in the browser. Then open the Live view. Within a few seconds you’ll see a span for the request, regardless of which worker handled it.
Not seeing your requests in Logfire? Check that logfire.configure() is called inside the post_fork
hook (not at module top level, where it runs before workers fork), that your write token is set, and
that any framework instrumentation runs once per worker inside the same hook.
Here you also instrument a Flask app running under Gunicorn, so each request becomes a span.
The Flask application (myapp.py):
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'Hello from Flask + Gunicorn!'
Import and instrument the app inside post_fork, so it happens once per worker
(gunicorn_config.py):
from myapp import app
import logfire
def post_fork(server, worker):
logfire.configure()
logfire.instrument_flask(app)
Then start Gunicorn:
gunicorn myapp:app --config gunicorn_config.py
Logfire now records a span for every request the Flask app handles, in every worker.
- Gunicorn
post_forksetting: where the configuration runs. logfire.instrument_flask(): to instrument a Flask app, as shown above.