Skip to content

Configure Logfire with 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.

What you’ll capture

  • 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

Before you start

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.

Installation

Install logfire:

Terminal
pip install logfire

If you also want to instrument the web framework you run under Gunicorn (Flask, for example), install its extra too. Choose the relevant framework from the web framework integrations.

Usage

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:

gunicorn_config.py
import logfire


def post_fork(server, worker):
    logfire.configure()

Then start Gunicorn with that configuration file, where myapp:app is your WSGI application:

Terminal
gunicorn myapp:app --config gunicorn_config.py

Verify it worked

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.

Troubleshooting

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), and that your write token is set. For Flask, check that instrument_flask(worker.wsgi) runs inside post_worker_init, as shown below. Other frameworks can require different setup; choose the relevant framework from the web framework integrations.

Advanced

Instrumenting a Flask application

Here you also instrument a Flask app running under Gunicorn, so each request becomes a span.

The Flask application (myapp.py):

myapp.py
from flask import Flask

app = Flask(__name__)


@app.route('/')
def index():
    return 'Hello from Flask + Gunicorn!'

Configure Logfire after each worker is forked, then instrument the application after Gunicorn loads it (gunicorn_config.py):

gunicorn_config.py
import logfire


def post_fork(server, worker):
    logfire.configure()


def post_worker_init(worker):
    logfire.instrument_flask(worker.wsgi)

Then start Gunicorn:

Terminal
gunicorn myapp:app --config gunicorn_config.py

Logfire now records a span for every request the Flask app handles, in every worker.

Reference