Skip to main content

Measure the execution time of a function or endpoint in Flask

· 4 min read
Serhii Hrekov
software engineer, creator, artist, programmer, projects founder

The best way to precisely measure the execution time of a function or endpoint in Flask is by using a decorator or middleware. This approach allows you to wrap your functions with timing logic without directly altering the original function's code, which keeps your application clean and maintainable.

Using a Decorator for a Specific Function

A decorator is ideal for measuring the execution time of a few specific endpoints or functions. It's a simple, reusable way to add timing functionality.

The Decorator

import time
import functools

def measure_execution_time(func):
"""A decorator to measure and print the execution time of a function."""
@functools.wraps(func)
def wrapper(*args, **kwargs):
start_time = time.perf_counter()
result = func(*args, **kwargs)
end_time = time.perf_counter()
execution_time_ms = (end_time - start_time) * 1000
print(f"'{func.__name__}' executed in {execution_time_ms:.4f} ms")
return result
return wrapper

We use time.perf_counter() because it's the most precise timer available for performance measurement and is not affected by system clock adjustments. The @functools.wraps decorator is used to preserve the original function's metadata, such as its name and docstrings.

Applying the Decorator to an Endpoint

You can now apply this decorator to any of your Flask endpoints.

from flask import Flask

app = Flask(__name__)

@app.route("/items/<int:item_id>")
@measure_execution_time
def get_item(item_id):
# Simulate a long-running operation
time.sleep(0.1)
return {"item_id": item_id}

if __name__ == '__main__':
app.run(debug=True)

Using a before_request and after_request for All Endpoints

For measuring the execution time of all requests to your application, a better approach is to use Flask's before_request and after_request decorators. This is essentially a form of middleware that centralizes your timing logic.

from flask import Flask, g, request

app = Flask(__name__)

@app.before_request
def start_timer():
"""Starts a timer before a request is processed."""
g.start_time = time.perf_counter()

@app.after_request
def log_request_time(response):
"""Calculates and logs the request processing time."""
end_time = time.perf_counter()
execution_time_ms = (end_time - g.start_time) * 1000

# You can log the time
print(f"Request to '{request.path}' took {execution_time_ms:.4f} ms")

# Or add it to a response header
response.headers["X-Process-Time-Ms"] = str(execution_time_ms)

return response

@app.route("/hello")
def hello():
return "Hello, World!"

The g object is a special context-local object in Flask used to store data for a single request. We store the start time on g in the before_request function and then retrieve it in the after_request function to calculate the duration. This ensures the timer is isolated to each individual request.


Summary of Approaches

MethodProsConsBest For
DecoratorFine-grained control, targets specific functions.Requires manual application to each function.Measuring specific, critical endpoints.
before/after_requestCentralized, measures all requests automatically.Less granular, includes overhead from other functions.Measuring overall API performance.

For precise, global timing, using before_request and after_request is the most robust solution. For micro-optimizing a few specific functions, a decorator is the best choice.