Tutorial

Adding real-time logging to a Flask app in 10 minutes

March 11, 2025 BunnyLogs Team

Flask has solid built-in logging built on Python's logging module, but by default that output goes to stderr and disappears once the process is gone. This tutorial shows how to wire BunnyLogs into Flask's logger in a few lines, giving you a persistent live stream URL you can watch from anywhere.

Prerequisites

  • An existing Flask app (any version)
  • A free BunnyLogs account and a new stream UUID

Install

pip install bunnylogs

Basic setup

The simplest integration adds the handler to Flask's app logger:

from flask import Flask
from bunnylogs import BunnyLogsHandler

app = Flask(__name__)
app.logger.addHandler(BunnyLogsHandler("your-uuid-here"))
app.logger.setLevel("INFO")

@app.route("/")
def index():
    app.logger.info("Home page hit")
    return "Hello, world!"

Start Flask and open bunnylogs.com/live/your-uuid. Make a request to / and the log line appears immediately.

Capturing Werkzeug access logs

Flask's development server uses Werkzeug, which logs every HTTP request to the werkzeug logger. Add the handler there too to see access logs in your stream:

import logging
from bunnylogs import BunnyLogsHandler

handler = BunnyLogsHandler("your-uuid")

logging.getLogger("werkzeug").addHandler(handler)
app.logger.addHandler(handler)

Now every GET / and POST /api/data appears in the live stream alongside your application logs.

Production setup with environment variables

For production, configure logging in the app factory and read the UUID from an environment variable so it doesn't get committed to source control:

import os
import logging
from flask import Flask
from bunnylogs import BunnyLogsHandler

def create_app():
    app = Flask(__name__)

    uuid = os.environ.get("BUNNYLOGS_UUID")
    if uuid:
        handler = BunnyLogsHandler(uuid, level=logging.WARNING)
        app.logger.addHandler(handler)
        logging.getLogger("werkzeug").addHandler(handler)

    return app

In development, leave BUNNYLOGS_UUID unset (or use a development stream). In production, set it to your production stream UUID.

Logging request context

Flask's request context is available inside view functions. Log relevant details so the stream tells the full story of each request:

from flask import Flask, request, g
import time

app = Flask(__name__)

@app.before_request
def start_timer():
    g.start = time.time()

@app.after_request
def log_request(response):
    duration_ms = int((time.time() - g.start) * 1000)
    app.logger.info(
        f"{request.method} {request.path} → {response.status_code} ({duration_ms}ms)"
    )
    return response

Your stream now shows every request with method, path, status code, and duration. Slow requests and errors are immediately visible.

Error logging with tracebacks

Register an error handler that logs the full traceback to the stream:

@app.errorhandler(Exception)
def handle_exception(e):
    app.logger.error(f"Unhandled exception: {e}", exc_info=True)
    return {"error": "Internal server error"}, 500

Unhandled exceptions now appear in your live stream with the full traceback — visible to you and anyone you've shared the stream URL with.

Gunicorn in production

When running under Gunicorn, Flask's app logger doesn't inherit Gunicorn's logging configuration by default. Configure the handler in your app factory (as shown above) and it'll work correctly with Gunicorn workers.

Try BunnyLogs with Flask →


Related posts