Skip to content

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. See that framework’s integration page.

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), that your write token is set, and that any framework instrumentation runs once per worker inside the same hook.

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!'

Import and instrument the app inside post_fork, so it happens once per worker (gunicorn_config.py):

gunicorn_config.py
from myapp import app

import logfire


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

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