OpenTelemetry guide for Flask and SQLAlchemy
In this article, you will learn how to use OpenTelemetry with Uptrace to monitor Flask and SQLAlchemy performance.
What is tracing?
OpenTelemetry tracing allows to observe requests as they propagate through distributed systems, especially those built using a microservices architecture.
Tracing provides insights into your app performance along with any errors and logs. You immediately see what conditions cause errors and how particular error affects app performance.
Using tracing, you can break down requests into spans. Span is an operation (unit of work) your app performs handling a request, for example, a database query or a network call.
Trace is a tree of spans that shows the path that a request makes through an app. Root span is the first span in a trace.
To learn more about tracing, see Distributed Tracing using OpenTelemetry.
What is OpenTelemetry?
Otel allows developers to collect and export telemetry data in a vendor agnostic way. With OpenTelemetry, you can instrument your application once and then add or change vendors without changing the instrumentation, for example, here is a list popular DataDog alternatives that support OpenTelemetry.
OpenTelemetry is available for most programming languages and provides interoperability across different languages and environments.
To measure performance of database queries or HTTP requests, you can create a span using OpenTelemetry Python API:
from opentelemetry import trace tracer = trace.get_tracer("app_or_package_name", "1.0.0") def some_func(**kwargs): with tracer.start_as_current_span("some-func") as span: // the code you are measuring
To record contextual information, you can annotate spans with attributes. For example, an HTTP endpoint may have such attributes as
http.method = GET and
http.route = /projects/:id.
# To avoid expensive computations, check that span is recording # before setting any attributes. if span.is_recording(): span.set_attribute("http.method", "GET") span.set_attribute("http.route", "/projects/:id")
You can also record exceptions and set the span status code to indicate an error:
except ValueError as exc: # Record the exception and update the span status. span.record_exception(exc) span.set_status(trace.Status(trace.StatusCode.ERROR, str(exc)))
See OpenTelemetry Python tracing for details.
What is Uptrace?
Uptrace is an open source APM for OpenTelemetry with an intuitive query builder, rich dashboards, automatic alerts, and integrations for most languages and frameworks.
You can get started with Uptrace by downloading a DEB/RPM package or a pre-compiled Go binary.
In this tutorial, you will be instrumenting a toy app that uses Flask and SQLAlchemy database client. You can retrieve the source code with the following command:
git clone firstname.lastname@example.org:uptrace/uptrace.git cd example/flask
The app comes with some dependencies that you can install with:
pip install -r requirements.txt
Uptrace provides OpenTelemetry Python distro that configures OpenTelemetry SDK for you. To install the distro:
pip install uptrace
Then you need to initialize the distro whenever you app is started, for example, in
# manage.py import uptrace def main(): uptrace.configure_opentelemetry( # Copy DSN here or use UPTRACE_DSN env var. # dsn="", service_name="myservice", service_version="v1.0.0", ) # other code
See documentation for details.
Instrumenting Flask app
To instrument Flask app, you need to install a corresponding OpenTelemetry Flask instrumentation:
pip install opentelemetry-instrumentation-flask
Then you can instrument the Flask app:
from opentelemetry.instrumentation.flask import FlaskInstrumentor app = Flask(__name__) FlaskInstrumentor().instrument_app(app)
To instrument SQLAlchemy database client, you need to install a corresponding instrumentation:
pip install opentelemetry-instrumentation-sqlalchemy
Then instrument the db engine:
from flask_sqlalchemy import SQLAlchemy from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///:memory:" db = SQLAlchemy(app) SQLAlchemyInstrumentor().instrument(engine=db.engine)
Running the example
You can start Uptrace backend with a single command using Docker example:
docker-compose up -d
And then start the app passing Uptrace DSN as an env variable:
export UPTRACE_DSN=http://project2_secret_token@localhost:14317/2 python3 main.py
The app should be serving requests on
http://localhost:8000 and should render a link to Uptrace UI. After opening the link, you should see this: