![Integrate AppSignal with AWS Fargate in Python Flask](/_next/image?url=%2Fimages%2Fblog%2F2025-02%2Ffargate-python-flask.jpg&w=3840&q=90)
In this tutorial, we’ll show you how to integrate AppSignal with a Flask application running on AWS Fargate.
Fargate is a serverless container service that allows you to run Docker containers in the cloud. By integrating AppSignal with AWS Fargate, you can monitor the performance of your Flask application and get insights.
Set Up
The Flask application we'll use in this tutorial is a simple weather API that returns random weather data. We’ll build the cloud infrastructure using the AWS Cloud Development Kit (CDK) and deploy the Flask application to AWS Fargate. The app will run from a Docker image hosted on Amazon Elastic Container Registry (ECR).
Once the CDK stack is deployed, we’ll monitor the Flask application using AppSignal. The Open Telemetry instrumentation will have a custom span we can use to track the performance of the randomly generated weather data.
You can follow along with the code presented here or by cloning the GitHub repository.
PIP packages
The weather API will have the following dependencies:
appsignal
: The AppSignal Python agent.opentelemetry-instrumentation-flask
: The OpenTelemetry instrumentation for Flask.Flask
: The Flask web framework.
These requirements can be installed via the requirements.txt
file inside the docker image. To keep it simple, we will use the python:3.12-slim
image as the base image for the Flask application. The docker container can run on any computer that has Docker installed, and it can be deployed to AWS Fargate.
But first, spin up the CDK project using the Python template. The infrastructure code will be the one to build the docker image inside an app
folder.
AWS CDK
Be sure to have the AWS CDK installed on your computer. We will assume you have Python 3.6 or later installed.
Create a new project folder and initialize the CDK project using the Python template:
mkdir flask-fargate-api cd flask-fargate-api cdk init app --language python ./venv/Scripts/activate pip install -r requirements.txt cdk bootstrap cdk synth
The activate
script will activate the virtual environment for your project. The cdk synth
command will verify the CDK project is working correctly.
Open the app.py
file in the flask-fargate-api
folder and make sure your account details are correct.
FlaskFargateApiStack( app, "flask-fargate-api-stack", env=cdk.Environment(account='1234567890', region='us-east-1') )
The stack ID flask-fargate-api-stack
will be the name of the stack used by CloudFormation. You can change the name to something else if you like. But do not change the stack ID once the stack has been deployed because it will bomb.
Open the flask-fargate-api-stack.py
file and add the following code to create the VPC, ECS cluster, and Fargate service:
from aws_cdk import ( Stack, aws_ec2 as ec2, aws_ecs as ecs, aws_ecs_patterns as ecs_patterns, aws_logs as logs ) from constructs import Construct class FlaskFargateApiStack(Stack): def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) vpc = ec2.Vpc( self, "vpc" ) cluster = ecs.Cluster( self, "cluster", vpc=vpc ) service = ecs_patterns.ApplicationLoadBalancedFargateService( self, "api", cluster=cluster, cpu=256, memory_limit_mib=512, desired_count=1, public_load_balancer=True, task_image_options={ "environment": { "ADDRESS": "0.0.0.0", "PORT": "80" }, "image": ecs.ContainerImage.from_asset( directory="app" ), "container_port": 80, "log_driver": ecs.AwsLogDriver( stream_prefix="api", log_retention=logs.RetentionDays.ONE_DAY ) } ) service.target_group.configure_health_check( path="/health" )
The task image has environment variables for the address and port. This will allow the loopback address to be used inside the container. The public_load_balancer
will give us a public URL to access the Flask application.
The VPC allows the CDK to grant network access to the Fargate service. This allows access to the ECR repository and the ECS cluster. The app itself doesn’t exist yet, but the CDK will build the Docker image and push it to ECR. The health check is used to monitor the health of the Fargate service during deployment.
We are not able to deploy the stack yet, because it needs the Docker image to be built and pushed to ECR. Let's do that next.
Weather API
Create the missing app
folder in the root of the project. Inside the app
folder, create a new file called app.py
and add the following code:
import appsignal from appsignal import set_category from opentelemetry import trace # open telemetry instrumentation appsignal.start() tracer = trace.get_tracer(__name__) from flask import Flask, jsonify import random import os app = Flask(__name__) weather_data = [ {"city": "New York", "temperature": 77, "condition": "Cloudy"}, {"city": "Los Angeles", "temperature": 70, "condition": "Sunny"}, {"city": "Chicago", "temperature": 73, "condition": "Sunny"}, {"city": "Houston", "temperature": 81, "condition": "Cloudy"}, {"city": "Phoenix", "temperature": 92, "condition": "Sunny"}, ] @app.route('/weather', methods=['GET']) def get_weather(): # start a custom span with tracer.start_as_current_span("random_weather"): set_category("get_weather") return jsonify(random.choice(weather_data)) @app.route('/health', methods=['GET']) def health(): return jsonify({"status": "ok"}) if __name__ == '__main__': port = os.getenv('PORT', 5000) host = os.getenv('ADDRESS', 'localhost') app.run(debug=True, host=host, port=port)
The tracer
object creates a custom span called random_weather
. This span will track the performance of the random weather data. Keep in mind this could be an API call, a database query, or any other operation that needs to be monitored. The set_category
function sets the category of the span to get_weather
.
The appsignal.start()
function must be called before the Flask application is imported. This will start the AppSignal agent and configure the OpenTelemetry instrumentation for Flask.
To activate this instrumentation, create an __appsignal.py__
file in the app
folder and add the following code:
from appsignal import Appsignal appsignal = Appsignal( active=True, name="flask-fargate-api", # Please do not commit this key to your source control management system. # Move this to your app's security credentials or environment variables. # https://docs.appsignal.com/python/configuration/options.html#option-push_api_key push_api_key="your-push-api-key" )
Next, create the requirements.txt
file in the app
folder and add the following dependencies:
appsignal opentelemetry-instrumentation-flask Flask
Create the Dockerfile
in the app
folder and add the following code:
FROM python:3.12-slim WORKDIR /app COPY . /app RUN pip install --no-cache-dir -r requirements.txt CMD ["python", "app.py"]
This Dockerfile
will create the Docker image for the Flask application to run on AWS Fargate. The command python app.py
will run the Flask application when the container is started. You can test the Flask application locally or via the Docker container.
That’s it for the Flask application. The next step is to build the Docker image and push it to ECR via the CDK.
Deploy the CDK Stack
Drum roll, please! Fire up the CDK stack using the following command:
cdk deploy
If there is an issue with the Docker image, be sure to have Docker installed and running on your computer. Docker must also have access to ECR to push the image.
If it’s having trouble signing in to ECR, run the following command:
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 1234567890.dkr.ecr.us-east-1.amazonaws.com
Be sure to replace 1234567890
with your AWS account number. This will allow Docker to push the image to ECR.
The deployment should take no more than five minutes. If it is taking longer, kill it in CloudFormation and delete the stack. Troubleshoot the issue and try again. AWS charges for the Fargate service and ECR, so do not leave the stack running if it is not working.
At the end, the CDK will output the public URL for the Flask application. Look for the api
URL in the output, which looks like this:
Outputs: flask-fargate-api-stack.api = http://api-1234567890.us-east-1.elb.amazonaws.com
Now grab the URL and test the Flask application via CURL or a web browser. The /weather
endpoint should return random weather data. The /health
endpoint should return a status of ok
.
Hit the /weather
endpoint a few times to generate some data. Next, we will monitor the Flask application using AppSignal.
AppSignal Monitoring of the Python Flask Application
Once you hit the endpoint enough times, go to the AppSignal dashboard under your account. The application should be listed under flask-fargate-api
. The name matches the name configuration in the __appsignal__.py
file. Click on the application to view the dashboard.
Under Performance, you should see Actions, Slow Events, and Graphs. Click on Actions and then the GET /health
endpoint. Then, you can click on 'Slow Events' to see your custom span random_weather
.
The random_weather
span should show average duration, throughput, and overall performance impact. This is the custom span we created to monitor the performance of the random weather data.
![AppSignal Dashboard](/_next/image?url=%2Fimages%2Fblog%2F2025-02%2Fflask-fargate-api-1.png&w=3840&q=90)
Note the span breakdown, which includes impact, meaning the endpoint spent all its time generating random weather data.
You may also track the performance of each call for the custom span.
![AppSignal Custom Span](/_next/image?url=%2Fimages%2Fblog%2F2025-02%2Fflask-fargate-api-2.png&w=3840&q=90)
The breakdown of the span itself is also available. This shows a timeline of the HTTP request and the time spent generating the random weather data.
![AppSignal Span Breakdown](/_next/image?url=%2Fimages%2Fblog%2F2025-02%2Fflask-fargate-api-3.png&w=3840&q=90)
And that's that!
Wrapping Up
In this tutorial, we showed you how to integrate AppSignal with a Flask application running on AWS Fargate. We built the cloud infrastructure using the AWS CDK and deployed the application. We then monitored the Flask application using AppSignal and created a custom span to track the performance of the random weather data.
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!