python

Monitor the Performance of Your Python Flask Application with AppSignal

Amir Tadrisi

Amir Tadrisi on

Monitor the Performance of Your Python Flask Application with AppSignal

When a system runs slowly, our first thought might be that it’s failing. This common reaction underscores a key point:

Performance is crucial for an application's readiness and maturity.

In the world of web applications, even milliseconds matter. Performance impacts user satisfaction and operational efficiency, making it a critical factor.

In this article, we'll show you how to use AppSignal to monitor and improve the performance of your Flask applications.

Flask Performance Monitoring Essentials: Key Metrics

Achieving optimal performance in Flask applications involves a comprehensive approach. This means building applications that not only run efficiently but also maintain this efficiency as they scale. Key metrics provide the data needed to guide our optimization efforts. Let’s explore some of these essential metrics:

  • Response Time: This is a direct indicator of user experience, measuring the time taken for a user's request to be processed and the response to be sent back. In a Flask application, factors such as database queries, view processing, and middleware operations can influence response times.
  • Throughput: Throughput refers to the number of requests your application can handle within a given timeframe. Higher throughput indicates better performance under load.
  • Error Rates: The frequency of errors (4xx and 5xx HTTP responses) can indicate issues with code, database queries, or server configuration. Monitoring error rates helps to quickly identify and fix problems that could degrade user experience.
  • Database Performance Metrics: These include the number of queries per request, query execution time, and the efficiency of database connections. Optimizing these metrics can significantly improve overall application performance.
  • Handling Concurrent Users: The ability to efficiently serve multiple users accessing your Flask application simultaneously is critical. Monitoring how well your application handles concurrent users helps ensure it can scale effectively without delays.

What We Will Build

In this article, we'll construct a Flask-based blog application ready for high-traffic events, integrating AppSignal to monitor, optimize, and ensure it scales seamlessly under load.

Here's the codebase and the branch appsignal-integration is where we have AppSignal integrated with our Flask app. You can access the live site.

Prerequisites

To follow along, you'll need:

Prepare the Project

Now let's create a directory for our project, clone it from GitHub, and install all the requirements:

Shell
mkdir flask-performance && cd flask-performance python3.12 -m venv venv source venv/bin/activate git clone -b main https://github.com/amirtds/myblog cd myblog python3.12 -m pip install -r requirements.txt npm run build:css python run.py

Now visit 127.0.0.1:8000.

Install AppSignal

Now we are going to install appsignal and opentelemetry-instrumentation-flask in our project.

Before installing these packages, log in to AppSignal using your credentials. After picking the organization, click on Add app on the top right of the navigation bar. Select Python as the language and note the push-api-key.

Make sure your virtual environment is activated and run the following commands in the project:

Shell
python3.12 -m pip install appsignal==1.3.6 python3.12 -m appsignal install --push-api-key [YOU-KEY] python3.12 -m pip install opentelemetry-instrumentation-flask==0.46b0

Provide the app name to the CLI prompt. After finishing the installation, you should see a new file called __appsignal__.py in your project.

Now let's create an .env file in the project root and add APPSIGNAL_PUSH_API_KEY=YOUR-KEY (remember to change the value to your actual key). Next, let's change the content of the __appsignal__.py file to the following:

py
# __appsignal__.py import os from appsignal import Appsignal # Load environment variables from the .env file from dotenv import load_dotenv load_dotenv() # Get APPSIGNAL_PUSH_API_KEY from environment push_api_key = os.getenv('APPSIGNAL_PUSH_API_KEY') appsignal = Appsignal( active=True, name="myblog", push_api_key=os.getenv("APPSIGNAL_PUSH_API_KEY"), )

And update the __init__.py to the following:

py
from flask import Flask from __appsignal__ import appsignal # new line from opentelemetry.instrumentation.flask import FlaskInstrumentor # new line from opentelemetry import trace # new line def create_app(): appsignal.start() # new line app = Flask(__name__) app.static_folder = 'static' # Instrument Flask with OpenTelemetry FlaskInstrumentor().instrument_app(app) # new line from . import routes app.register_blueprint(routes.bp) return app

We have imported appsignal and started it using the configuration we used in __appsignal__.py.

Monitor Concurrent Users

Now let's look at monitoring concurrent users.

Scenario: Optimizing for High Load on Blog Posts

As we anticipate increased traffic on our Flask-based blog application, we want to ensure our site remains fast and responsive. We've had traffic spikes that led to slow load times and occasional downtime. We're determined to avoid these issues by thoroughly testing and optimizing our site beforehand. We'll use Locust to simulate user traffic and AppSignal to monitor our application's performance.

Creating a Locust Test for Simulated Traffic

First, we'll create a locustfile.py that simulates users navigating through critical parts of our blog: the homepage and individual post pages. This simulation helps us understand how our site performs under pressure.

Create locustfile.py in the project root:

py
# locustfile.py from locust import HttpUser, between, task import random class BlogUser(HttpUser): wait_time = between(1, 3) # Users wait 1-3 seconds between tasks post_urls = ["/post/post1", "/post/post2", "/post/post3", "/post/post4", "/post/post5", "/post/post6"] @task def index_page(self): self.client.get("/") @task(3) def view_post(self): post_url = random.choice(self.post_urls) self.client.get(post_url)

In this locustfile.py, users primarily visit the post pages, occasionally returning to the homepage. This pattern mimics realistic user behavior on a blog.

Before running Locust, ensure you have posts available in your Flask app. You can check this by visiting the homepage and individual post pages.

Defining Acceptable Response Times

Before we start, let's define what we consider acceptable response times. For a smooth user experience, we aim for:

  • Homepage: under 1 second
  • Post page: under 1.5 seconds

These targets ensure users experience minimal delay, keeping their engagement high.

Conducting the Test and Monitoring Results

With our Locust test ready, we run it to simulate the 500 users and observe results in real time. Here's how:

  • Start the Locust test by running locust -f locustfile.py in your terminal, then open http://localhost:8089 to set up and start the simulation. Set the Number of Users to 500 and set the host to http://127.0.0.1:8000
  • Monitor performance in both Locust's web interface and AppSignal. Locust shows us request rates and response times, while AppSignal provides deeper insights into our Flask app's behavior under load.

After running Locust, you can find information about the load test in its dashboard:

Locust dashboard

Now go to your application page in AppSignal. Under the Performance section, click on Actions and you should see something similar to the following:

AppSignal action monitoring list
  • Mean: This is the average response time for all the requests made to a particular endpoint. It provides a general idea of how long it takes for the server to respond. In our context, any mean response time greater than 1 second could be considered a red flag, indicating that our application's performance might not meet user expectations for speed.
  • 90th Percentile: This is the response time at the 90th percentile. For example, for GET /, if we have 7 ms, it means 90% of requests are completed in 7 ms or less.
  • Throughput: This is the number of requests handled per second.

Now let's click on the Graphs option under Performance. You should see something like the following:

AppSignal performance graphs

Analyzing and Improving Performance

We need to prepare our site for increased traffic as response times might exceed our targets. Here's a simplified plan:

  • Database queries: Slow queries often cause performance issues. We will delve into this in the next section.
  • Static assets: Ensure they're properly cached. Use a CDN for better delivery speeds.
  • Application resources: Sometimes, the solution is as straightforward as adding more RAM and CPUs.

Track Errors

Let's introduce an error in one of the routes. For example, we can create a route that divides by zero, which will cause a ZeroDivisionError. In the end of the routes.py file, let's add the following:

py
# Introduce a route that causes an error @bp.route('/cause-error') def cause_error(): # This will cause a ZeroDivisionError 1 / 0

Now visit http://127.0.0.1:8000/cause-error. We should see a ZeroDivisionError in the dashboard.

Let's head to the dashboard in AppSignal. On the left sidebar, click on Errors -> Issue List. Here you should see all the errors that occur to users when they visit specific URLs. By clicking on each issue, you should see more detailed information.

AppSignal error dashboard

It is highly recommended that you integrate AppSignal with your GitHub repo. When an error occurs, an issue will be created in the repo automatically so you don't lose track of it.

No additional steps are required beyond the initial setup to begin logging and managing errors.

In the Graphs we can see the Error rate, Count, and Throughput:

AppSignal error graph

Monitor Performance

In the Performance section of your dashboard, click on the Issues list to see a detailed breakdown of all visited URLs along with key metrics:

  • Mean: This metric indicates the average response time for requests to a specific endpoint. It gives us a sense of the overall speed of our server's responses. For our blog, if the mean response time exceeds 1 second, it could be a warning sign that our performance may not meet user expectations.
  • Throughput: This metric shows the number of requests being processed per second. High throughput with acceptable response times indicates good performance.
  • Impact: This reflects the significance of a particular action on the overall application performance, based on its usage relative to other actions.
Performance issues list

Additionally, we can visualize our application's performance through various graphs:

Performance graphs

This data is crucial as it provides insights into how users experience page load times. High response times signal the need for optimization. For instance, if multiple requests exceed 1 second, we should investigate and improve those areas to enhance performance.

By using these insights from AppSignal, we can continually refine and optimize our Flask application to ensure it delivers a fast and smooth user experience.

Anomaly Detection and Alerts

We can also set up triggers to alert us to high resource usage on our platform. This is crucial for taking action before our site goes down due to a spike in traffic. Additionally, this is important because when a critical function fails, we may see a surge in errors. Anomaly detection can notify us before this impacts more users.

Let's create two triggers: one for high memory usage when it exceeds 70% and another for error rates when they surpass 20%.

Anomaly trigger 1
Anomaly trigger 2
Active anomaly triggers

Ensure the Email notification option is checked to receive notifications when an anomaly occurs.

In the Issues list, you can view all the anomalies that have occurred based on the conditions you defined.

Detected anomalies list

Uptime Monitoring

Uptime monitoring is essential to ensure your blog remains accessible and performs well. Here's why you might need uptime monitoring:

  • Post-Deployment Issues: After deploying updates, there might be changes in URLs or resources, such as CSS files, leading to errors and a broken appearance. This not only affects the aesthetics but can also frustrate users.
  • System Downtimes: Various issues, like database outages or failures in third-party services, can cause your site to go down. Downtimes disrupt user experience and can damage your platform's reputation.

Uptime monitoring not only confirms that your site is operational but also alerts you immediately if it goes down.

Features of Uptime Monitoring

  • Regional Response Times: AppSignal's uptime check shows response times from different regions, providing insights into global performance. This is particularly useful for ensuring a consistent user experience across various geographical locations.
  • Public Status Page: Set up a public status page to communicate real-time site status, reducing the number of support tickets as users can verify the site status themselves.
Public status page

In your Uptime Monitoring dashboard, you can add new URLs by clicking on Add Uptime Monitor. For instance, you can create monitors for your blog's critical resources and main URLs.

Uptime monitor
Uptime monitor showing response times by region

By setting up these alerts and monitors, you ensure that your Flask blog application remains robust and performs well, even under high traffic or unexpected issues.

Host Monitoring

In this section, we can observe how our VM resources are being utilized by our Flask application. The metrics section in AppSignal provides visualizations and graphs, making it easier to understand resource usage.

Monitoring Resource Usage

Using AppSignal's Host Monitoring, we can track various aspects of our VM's performance. Here are some of the key metrics we can visualize:

  • CPU Usage: This metric shows how much CPU is being used by our application. High CPU usage can indicate that our application is under heavy load or that processes need optimization.
  • Memory Usage: Monitoring memory usage helps us understand how much memory our application consumes. If memory usage is consistently high, optimizing the application or increasing the available memory might be necessary.
  • Disk I/O: Disk I/O metrics show how much data is being read from or written to the disk. High disk I/O can be a sign of heavy data processing tasks or inefficient data handling.
Host metric 1
Host metric 2
Host metric 3

Importance of Resource Monitoring

Resource monitoring is crucial for maintaining the performance and reliability of our Flask application. By keeping an eye on these metrics, we can:

  • Identify Bottlenecks: High resource usage can indicate performance bottlenecks that need to be addressed.
  • Optimize Performance: Understanding resource consumption helps in optimizing the application for better performance.
  • Prevent Downtime: Monitoring helps in proactively managing resources, preventing potential downtimes due to resource exhaustion.

By using these insights from AppSignal, we can ensure that our Flask blog application remains performant and reliable.

Wrapping Up

Monitoring the performance of your Flask application is crucial for ensuring a smooth and responsive user experience, especially as traffic increases. By integrating AppSignal, we can gain valuable insights into various performance metrics, identify potential bottlenecks, and take proactive measures to optimize our application.

Happy coding!

P.S. If you'd like to read Python posts as soon as they get off the press, subscribe to our Python Wizardry newsletter and never miss a single post!

Amir Tadrisi

Amir Tadrisi

Guest author Amir is a full-stack Python and Django software engineer who loves building educational products, including Open edX.

All articles by Amir Tadrisi

Become our next author!

Find out more

AppSignal monitors your apps

AppSignal provides insights for Ruby, Rails, Elixir, Phoenix, Node.js, Express and many other frameworks and libraries. We are located in beautiful Amsterdam. We love stroopwafels. If you do too, let us know. We might send you some!

Discover AppSignal
AppSignal monitors your apps