JustAnalytics for Flask

Step-by-step guide to add analytics, error tracking, and APM to your Flask app

JustAnalytics for Flask

Add distributed tracing, error tracking, structured logging, and infrastructure metrics to your Flask application.

Time to data: 3 minutes

Prerequisites#


Install the SDK

pip install justanalytics-python[flask]

Initialize and add middleware

# app.py
import os
import justanalytics
from flask import Flask
from justanalytics.integrations.flask import JustAnalyticsMiddleware

# Initialize the SDK BEFORE creating the Flask app
justanalytics.init(
    site_id=os.environ.get("JA_SITE_ID"),
    api_key=os.environ.get("JA_API_KEY"),
    service_name="flask-api",
    environment=os.environ.get("FLASK_ENV", "development"),
)

app = Flask(__name__)

# Add the middleware — traces all incoming requests automatically
JustAnalyticsMiddleware(app)

Add your routes

Routes are automatically traced. Each request creates a span named after the endpoint:

@app.route("/api/users/<int:user_id>")
def get_user(user_id):
    # Automatically traced as "GET /api/users/<int:user_id>"
    user = User.query.get_or_404(user_id)
    return jsonify(user.to_dict())

@app.route("/api/orders", methods=["POST"])
def create_order():
    data = request.get_json()
    order = Order.create(**data)
    return jsonify(order.to_dict()), 201

Add error handling

Unhandled exceptions are automatically captured. For explicit error reporting:

@app.errorhandler(500)
def handle_500(error):
    justanalytics.capture_exception(error, tags={"handler": "500"})
    return jsonify({"error": "Internal server error"}), 500

@app.route("/api/payments", methods=["POST"])
def process_payment():
    try:
        result = charge_card(request.json)
        return jsonify(result)
    except PaymentError as e:
        justanalytics.capture_exception(e, tags={"module": "payments"})
        return jsonify({"error": str(e)}), 400

Verify data is flowing

Start your Flask app and make a test request:

flask run
curl http://localhost:5000/api/users/1

Verify Your Setup

After sending a test request, check the Traces tab. You should see Flask request spans with route patterns.

Open Dashboard

Advanced Features#

Custom spans#

@app.route("/api/reports/<report_id>")
def get_report(report_id):
    with justanalytics.start_span("generate-report") as span:
        span.set_attribute("report.id", report_id)

        with justanalytics.start_span("query-database"):
            data = Report.query.get(report_id)

        with justanalytics.start_span("render-template"):
            html = render_template("report.html", data=data)

    return html

Decorator-based tracing#

@justanalytics.span(op="service.call")
def send_notification(user_id, message):
    # Automatically creates a span named "send_notification"
    return notification_service.send(user_id, message)

User identification#

@app.before_request
def identify_user():
    if hasattr(g, "current_user") and g.current_user:
        justanalytics.set_user(
            id=str(g.current_user.id),
            email=g.current_user.email,
        )

Structured logging#

justanalytics.log("info", "User registered", {"user_id": "u123", "source": "google"})
justanalytics.log("warn", "Rate limit close", {"ip": request.remote_addr, "remaining": 5})

Outgoing HTTP tracing#

from justanalytics.integrations.requests import RequestsIntegration

RequestsIntegration(service_name="flask-api").enable()

# Now all requests.get/post calls propagate trace context
import requests
response = requests.get("https://api.stripe.com/v1/charges")

Custom metrics#

justanalytics.record_metric("custom.active_users", active_count)
justanalytics.record_metric("custom.response_time_ms", elapsed, {"endpoint": "/api/users"})

Graceful shutdown#

import atexit

atexit.register(justanalytics.flush)
atexit.register(justanalytics.close)

Environment variables#

| Variable | Description | Required | |----------|-------------|----------| | JA_SITE_ID | Your site ID from the dashboard | Yes | | JA_API_KEY | API key (starts with ja_sk_) | Yes | | FLASK_ENV | Used as the default environment tag | No |