Using OpenTelemetry to Instrument Flask API and Expose HTTP Metrics

Instrumenting a Flask API with OpenTelemetry to expose HTTP metrics involves setting up the Open Telemetry SDK and configuring exporters and instrumentations.

Prerequisites

  • AWS Account with EC2 Instance.

  • Python 3, pip, and a Python virtual environment must be installed on the system.

  • A basic understanding of Flask and Python is required.

First Update the package list.

sudo apt update

Install Python 3, a Python virtual environment, and pip.

sudo apt install -y python3 python3-venv python3-pip

Create a new directory for our project setup.

mkdir flask-http-metrics

Navigate to that directory.

cd flask-http-metrics

Since pip doesn't work globally, create and use a virtual environment.

Set up a Python Virtual Environment to isolate your Python environment from the global system, simplifying dependency management and preventing conflicts.

python3 -m venv venv

Activate the virtual environment to start using it.

source venv/bin/activate

Install Required Packages

Install Flask and OpenTelemetry libraries within the virtual environment.

pip install flask opentelemetry-api opentelemetry-sdk opentelemetry-instrumentation-flask

Install the necessary package for the OTLP exporter.

pip install opentelemetry-exporter-otlp

Install the Prometheus Flask exporter.

pip install prometheus-flask-exporter

Create a Flask API with Prometheus metrics and OpenTelemetry.

vi app.py

Add the following code to the file.

from flask import Flask
from prometheus_flask_exporter import PrometheusMetrics
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter

# Initialize Flask app
app = Flask(__name__)

# Initialize Prometheus metrics
metrics = PrometheusMetrics(app)

# Initialize OpenTelemetry
trace_exporter = OTLPSpanExporter(endpoint="http://localhost:4317")  # Adjust if using remote OpenTelemetry Collector
provider = TracerProvider()
processor = BatchSpanProcessor(trace_exporter)
provider.add_span_processor(processor)

# Instrument Flask app with OpenTelemetry
FlaskInstrumentor().instrument_app(app)

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

@app.route('/health')
def health():
    return {"status": "healthy"}

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)

Explanation of the code

  1. Importing Necessary Libraries:

    • The code imports libraries for building a Flask web API, exposing HTTP metrics to Prometheus, automatically instrumenting the Flask app with OpenTelemetry for trace collection, defining a trace provider, processing spans in batches, and exporting spans to an OpenTelemetry Collector using the OTLP protocol.A new Flask application instance is created to handle incoming HTTP requests.
  2. Prometheus Metrics Initialization:

    • This sets up Prometheus metrics for the Flask app, allowing the PrometheusMetrics object to automatically provide metrics like request counts and latencies at the /metrics endpoint.
  3. OpenTelemetry Setup:

    • OTLPSpanExporter sends trace data to an OpenTelemetry Collector via gRPC, with the endpoint set to http://localhost:4317 for local setups; TracerProvider manages trace resources and spans; BatchSpanProcessor sends spans in batches to the exporter for better performance, and is added to the TracerProvider to process and export spans.
  4. Instrumenting the Flask App with OpenTelemetry:

    • FlaskInstrumentor().instrument_app(app) automatically adds Open Telemetry tracing to the Flask app, generating trace spans for every incoming HTTP request.

      • Defining Routes

        • The /hello route responds with "Hello, World!" when accessed with an HTTP GET request. It's a simple route to demonstrate how the API works.

        • The /health route is a health check endpoint used in production to confirm the service is running correctly. It returns a JSON response with the application's status.

      • Running the Flask App:

        • This starts the Flask application when the script is run directly. The app listens on all network interfaces (0.0.0.0) and is accessible on port 8080.

        • host='0.0.0.0': This allows the app to be accessed from any IP address, useful for remote access (e.g., on a server or EC2 instance).

        • port=8080: The port where the Flask app runs.

Start the Flask Application

Run the Flask API using this command.

python app.py

Your Flask app will be available on port 8080. Go to http://<EC2-Public-IP>:8080/hello to see the "Hello, World!" message.

Prometheus metrics can be found at /metrics. Visit http://<EC2-Public-IP>:8080/metrics to view them.